Merge "Define clear ownership for roundness SourceType" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
446cb95aa1
@@ -83,8 +83,7 @@ object Flags {
|
||||
val SEMI_STABLE_SORT = unreleasedFlag(115, "semi_stable_sort", teamfood = true)
|
||||
|
||||
@JvmField
|
||||
val NOTIFICATION_GROUP_CORNER =
|
||||
unreleasedFlag(116, "notification_group_corner", teamfood = true)
|
||||
val USE_ROUNDNESS_SOURCETYPES = unreleasedFlag(116, "use_roundness_sourcetype", teamfood = true)
|
||||
|
||||
// TODO(b/259217907)
|
||||
@JvmField
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.animation.Interpolators;
|
||||
import com.android.systemui.animation.ShadeInterpolation;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
|
||||
import com.android.systemui.statusbar.notification.LegacySourceType;
|
||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||
import com.android.systemui.statusbar.notification.SourceType;
|
||||
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
|
||||
@@ -66,6 +67,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
// the next icon has translated out of the way, to avoid overlapping.
|
||||
private static final Interpolator ICON_ALPHA_INTERPOLATOR =
|
||||
new PathInterpolator(0.6f, 0f, 0.6f, 0f);
|
||||
private static final SourceType BASE_VALUE = SourceType.from("BaseValue");
|
||||
private static final SourceType SHELF_SCROLL = SourceType.from("ShelfScroll");
|
||||
|
||||
private NotificationIconContainer mShelfIcons;
|
||||
private int[] mTmp = new int[2];
|
||||
@@ -112,19 +115,24 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
setClipChildren(false);
|
||||
setClipToPadding(false);
|
||||
mShelfIcons.setIsStaticLayout(false);
|
||||
requestBottomRoundness(1.0f, /* animate = */ false, SourceType.DefaultValue);
|
||||
requestTopRoundness(1f, false, SourceType.DefaultValue);
|
||||
requestRoundness(/* top = */ 1f, /* bottom = */ 1f, BASE_VALUE, /* animate = */ false);
|
||||
|
||||
// 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
|
||||
setFirstInSection(true);
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
// 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
|
||||
setFirstInSection(true);
|
||||
}
|
||||
updateResources();
|
||||
}
|
||||
|
||||
public void bind(AmbientState ambientState,
|
||||
NotificationStackScrollLayoutController hostLayoutController) {
|
||||
NotificationStackScrollLayoutController hostLayoutController) {
|
||||
mAmbientState = ambientState;
|
||||
mHostLayoutController = hostLayoutController;
|
||||
hostLayoutController.setOnNotificationRemovedListener((child, isTransferInProgress) -> {
|
||||
child.requestRoundnessReset(SHELF_SCROLL);
|
||||
});
|
||||
}
|
||||
|
||||
private void updateResources() {
|
||||
@@ -185,9 +193,11 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
+ " indexOfFirstViewInShelf=" + mIndexOfFirstViewInShelf + ')';
|
||||
}
|
||||
|
||||
/** Update the state of the shelf. */
|
||||
/**
|
||||
* Update the state of the shelf.
|
||||
*/
|
||||
public void updateState(StackScrollAlgorithm.StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState) {
|
||||
AmbientState ambientState) {
|
||||
ExpandableView lastView = ambientState.getLastVisibleBackgroundChild();
|
||||
ShelfState viewState = (ShelfState) getViewState();
|
||||
if (mShowNotificationShelf && lastView != null) {
|
||||
@@ -246,7 +256,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
|
||||
/**
|
||||
* @param fractionToShade Fraction of lockscreen to shade transition
|
||||
* @param shortestWidth Shortest width to use for lockscreen shelf
|
||||
* @param shortestWidth Shortest width to use for lockscreen shelf
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public void updateActualWidth(float fractionToShade, float shortestWidth) {
|
||||
@@ -281,9 +291,9 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
|
||||
/**
|
||||
* @param localX Click x from left of screen
|
||||
* @param slop Margin of error within which we count x for valid click
|
||||
* @param left Left of shelf, from left of screen
|
||||
* @param right Right of shelf, from left of screen
|
||||
* @param slop Margin of error within which we count x for valid click
|
||||
* @param left Left of shelf, from left of screen
|
||||
* @param right Right of shelf, from left of screen
|
||||
* @return Whether click x was in view
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@@ -293,8 +303,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
|
||||
/**
|
||||
* @param localY Click y from top of shelf
|
||||
* @param slop Margin of error within which we count y for valid click
|
||||
* @param top Top of shelf
|
||||
* @param slop Margin of error within which we count y for valid click
|
||||
* @param top Top of shelf
|
||||
* @param bottom Height of shelf
|
||||
* @return Whether click y was in view
|
||||
*/
|
||||
@@ -306,7 +316,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
/**
|
||||
* @param localX Click x
|
||||
* @param localY Click y
|
||||
* @param slop Margin of error for valid click
|
||||
* @param slop Margin of error for valid click
|
||||
* @return Whether this click was on the visible (non-clipped) part of the shelf
|
||||
*/
|
||||
@Override
|
||||
@@ -478,13 +488,15 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCornerRoundnessOnScroll(ActivatableNotificationView anv, float viewStart,
|
||||
private void updateCornerRoundnessOnScroll(
|
||||
ActivatableNotificationView anv,
|
||||
float viewStart,
|
||||
float shelfStart) {
|
||||
|
||||
final boolean isUnlockedHeadsUp = !mAmbientState.isOnKeyguard()
|
||||
&& !mAmbientState.isShadeExpanded()
|
||||
&& anv instanceof ExpandableNotificationRow
|
||||
&& ((ExpandableNotificationRow) anv).isHeadsUp();
|
||||
&& anv.isHeadsUp();
|
||||
|
||||
final boolean isHunGoingToShade = mAmbientState.isShadeExpanded()
|
||||
&& anv == mAmbientState.getTrackedHeadsUpRow();
|
||||
@@ -506,41 +518,40 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
* mAmbientState.getExpansionFraction();
|
||||
final float cornerAnimationTop = shelfStart - cornerAnimationDistance;
|
||||
|
||||
if (viewEnd >= cornerAnimationTop) {
|
||||
// Round bottom corners within animation bounds
|
||||
final float changeFraction = MathUtils.saturate(
|
||||
(viewEnd - cornerAnimationTop) / cornerAnimationDistance);
|
||||
anv.requestBottomRoundness(
|
||||
/* value = */ anv.isLastInSection() ? 1f : changeFraction,
|
||||
/* animate = */ false,
|
||||
SourceType.OnScroll);
|
||||
|
||||
} else if (viewEnd < cornerAnimationTop) {
|
||||
// Fast scroll skips frames and leaves corners with unfinished rounding.
|
||||
// Reset top and bottom corners outside of animation bounds.
|
||||
anv.requestBottomRoundness(
|
||||
/* value = */ anv.isLastInSection() ? 1f : 0f,
|
||||
/* animate = */ false,
|
||||
SourceType.OnScroll);
|
||||
final SourceType sourceType;
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
sourceType = SHELF_SCROLL;
|
||||
} else {
|
||||
sourceType = LegacySourceType.OnScroll;
|
||||
}
|
||||
|
||||
if (viewStart >= cornerAnimationTop) {
|
||||
final float topValue;
|
||||
if (!mUseRoundnessSourceTypes && anv.isFirstInSection()) {
|
||||
topValue = 1f;
|
||||
} else if (viewStart >= cornerAnimationTop) {
|
||||
// Round top corners within animation bounds
|
||||
final float changeFraction = MathUtils.saturate(
|
||||
topValue = MathUtils.saturate(
|
||||
(viewStart - cornerAnimationTop) / cornerAnimationDistance);
|
||||
anv.requestTopRoundness(
|
||||
/* value = */ anv.isFirstInSection() ? 1f : changeFraction,
|
||||
/* animate = */ false,
|
||||
SourceType.OnScroll);
|
||||
|
||||
} else if (viewStart < cornerAnimationTop) {
|
||||
} else {
|
||||
// Fast scroll skips frames and leaves corners with unfinished rounding.
|
||||
// Reset top and bottom corners outside of animation bounds.
|
||||
anv.requestTopRoundness(
|
||||
/* value = */ anv.isFirstInSection() ? 1f : 0f,
|
||||
/* animate = */ false,
|
||||
SourceType.OnScroll);
|
||||
topValue = 0f;
|
||||
}
|
||||
anv.requestTopRoundness(topValue, sourceType, /* animate = */ false);
|
||||
|
||||
final float bottomValue;
|
||||
if (!mUseRoundnessSourceTypes && anv.isLastInSection()) {
|
||||
bottomValue = 1f;
|
||||
} else if (viewEnd >= cornerAnimationTop) {
|
||||
// Round bottom corners within animation bounds
|
||||
bottomValue = MathUtils.saturate(
|
||||
(viewEnd - cornerAnimationTop) / cornerAnimationDistance);
|
||||
} else {
|
||||
// Fast scroll skips frames and leaves corners with unfinished rounding.
|
||||
// Reset top and bottom corners outside of animation bounds.
|
||||
bottomValue = 0f;
|
||||
}
|
||||
anv.requestBottomRoundness(bottomValue, sourceType, /* animate = */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -626,10 +637,11 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
|
||||
/**
|
||||
* Update the clipping of this view.
|
||||
*
|
||||
* @return the amount that our own top should be clipped
|
||||
*/
|
||||
private int updateNotificationClipHeight(ExpandableView view,
|
||||
float notificationClipEnd, int childIndex) {
|
||||
float notificationClipEnd, int childIndex) {
|
||||
float viewEnd = view.getTranslationY() + view.getActualHeight();
|
||||
boolean isPinned = (view.isPinned() || view.isHeadsUpAnimatingAway())
|
||||
&& !mAmbientState.isDozingAndNotPulsing(view);
|
||||
@@ -657,7 +669,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
|
||||
@Override
|
||||
public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
|
||||
int outlineTranslation) {
|
||||
int outlineTranslation) {
|
||||
if (!mHasItemsInStableShelf) {
|
||||
shadowIntensity = 0.0f;
|
||||
}
|
||||
@@ -665,18 +677,24 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
}
|
||||
|
||||
/**
|
||||
* @param i Index of the view in the host layout.
|
||||
* @param view The current ExpandableView.
|
||||
* @param scrollingFast Whether we are scrolling fast.
|
||||
* @param i Index of the view in the host layout.
|
||||
* @param view The current ExpandableView.
|
||||
* @param scrollingFast Whether we are scrolling fast.
|
||||
* @param expandingAnimated Whether we are expanding a notification.
|
||||
* @param isLastChild Whether this is the last view.
|
||||
* @param shelfClipStart The point at which notifications start getting clipped by the shelf.
|
||||
* @param isLastChild Whether this is the last view.
|
||||
* @param shelfClipStart The point at which notifications start getting clipped by the shelf.
|
||||
* @return The amount how much this notification is in the shelf.
|
||||
* 0f is not in shelf. 1f is completely in shelf.
|
||||
* 0f is not in shelf. 1f is completely in shelf.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public float getAmountInShelf(int i, ExpandableView view, boolean scrollingFast,
|
||||
boolean expandingAnimated, boolean isLastChild, float shelfClipStart) {
|
||||
public float getAmountInShelf(
|
||||
int i,
|
||||
ExpandableView view,
|
||||
boolean scrollingFast,
|
||||
boolean expandingAnimated,
|
||||
boolean isLastChild,
|
||||
float shelfClipStart
|
||||
) {
|
||||
|
||||
// Let's calculate how much the view is in the shelf
|
||||
float viewStart = view.getTranslationY();
|
||||
@@ -755,8 +773,13 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
return start;
|
||||
}
|
||||
|
||||
private void updateIconPositioning(ExpandableView view, float iconTransitionAmount,
|
||||
boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) {
|
||||
private void updateIconPositioning(
|
||||
ExpandableView view,
|
||||
float iconTransitionAmount,
|
||||
boolean scrollingFast,
|
||||
boolean expandingAnimated,
|
||||
boolean isLastChild
|
||||
) {
|
||||
StatusBarIconView icon = view.getShelfIcon();
|
||||
NotificationIconContainer.IconState iconState = getIconState(icon);
|
||||
if (iconState == null) {
|
||||
@@ -817,7 +840,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
|| row.showingPulsing()
|
||||
|| row.getTranslationZ() > mAmbientState.getBaseZHeight();
|
||||
|
||||
iconState.iconAppearAmount = iconState.hidden? 0f : transitionAmount;
|
||||
iconState.iconAppearAmount = iconState.hidden ? 0f : transitionAmount;
|
||||
|
||||
// Fade in icons at shelf start
|
||||
// This is important for conversation icons, which are badged and need x reset
|
||||
@@ -847,7 +870,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
}
|
||||
|
||||
private float getFullyClosedTranslation() {
|
||||
return - (getIntrinsicHeight() - mStatusBarHeight) / 2;
|
||||
return -(getIntrinsicHeight() - mStatusBarHeight) / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -904,7 +927,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
|
||||
/**
|
||||
* @return whether the shelf has any icons in it when a potential animation has finished, i.e
|
||||
* if the current state would be applied right now
|
||||
* if the current state would be applied right now
|
||||
*/
|
||||
public boolean hasItemsInStableShelf() {
|
||||
return mHasItemsInStableShelf;
|
||||
@@ -962,7 +985,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
|
||||
int oldTop, int oldRight, int oldBottom) {
|
||||
int oldTop, int oldRight, int oldBottom) {
|
||||
updateRelativeOffset();
|
||||
}
|
||||
|
||||
@@ -981,12 +1004,11 @@ public class NotificationShelf extends ActivatableNotificationView implements
|
||||
|
||||
/**
|
||||
* This method resets the OnScroll roundness of a view to 0f
|
||||
*
|
||||
* <p>
|
||||
* Note: This should be the only class that handles roundness {@code SourceType.OnScroll}
|
||||
*/
|
||||
public static void resetOnScrollRoundness(ExpandableView expandableView) {
|
||||
expandableView.requestTopRoundness(0f, false, SourceType.OnScroll);
|
||||
expandableView.requestBottomRoundness(0f, false, SourceType.OnScroll);
|
||||
public static void resetLegacyOnScrollRoundness(ExpandableView expandableView) {
|
||||
expandableView.requestRoundnessReset(LegacySourceType.OnScroll);
|
||||
}
|
||||
|
||||
public class ShelfState extends ExpandableViewState {
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
|
||||
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
|
||||
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
|
||||
@@ -42,14 +44,17 @@ public class NotificationShelfController {
|
||||
private AmbientState mAmbientState;
|
||||
|
||||
@Inject
|
||||
public NotificationShelfController(NotificationShelf notificationShelf,
|
||||
public NotificationShelfController(
|
||||
NotificationShelf notificationShelf,
|
||||
ActivatableNotificationViewController activatableNotificationViewController,
|
||||
KeyguardBypassController keyguardBypassController,
|
||||
SysuiStatusBarStateController statusBarStateController) {
|
||||
SysuiStatusBarStateController statusBarStateController,
|
||||
FeatureFlags featureFlags) {
|
||||
mView = notificationShelf;
|
||||
mActivatableNotificationViewController = activatableNotificationViewController;
|
||||
mKeyguardBypassController = keyguardBypassController;
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mView.useRoundnessSourceTypes(featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES));
|
||||
mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
@@ -88,7 +93,7 @@ public class NotificationShelfController {
|
||||
|
||||
public @View.Visibility int getVisibility() {
|
||||
return mView.getVisibility();
|
||||
};
|
||||
}
|
||||
|
||||
public void setCollapsedIcons(NotificationIconContainer notificationIcons) {
|
||||
mView.setCollapsedIcons(notificationIcons);
|
||||
|
||||
@@ -74,8 +74,8 @@ interface Roundable {
|
||||
@JvmDefault
|
||||
fun requestTopRoundness(
|
||||
@FloatRange(from = 0.0, to = 1.0) value: Float,
|
||||
animate: Boolean,
|
||||
sourceType: SourceType,
|
||||
animate: Boolean,
|
||||
): Boolean {
|
||||
val roundnessMap = roundableState.topRoundnessMap
|
||||
val lastValue = roundnessMap.values.maxOrNull() ?: 0f
|
||||
@@ -104,6 +104,30 @@ interface Roundable {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the top roundness [value] for a specific [sourceType]. Animate the roundness if the
|
||||
* view is shown.
|
||||
*
|
||||
* 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 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,
|
||||
sourceType: SourceType,
|
||||
): Boolean {
|
||||
return requestTopRoundness(
|
||||
value = value,
|
||||
sourceType = sourceType,
|
||||
animate = roundableState.targetView.isShown
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the bottom roundness [value] for a specific [sourceType].
|
||||
*
|
||||
@@ -119,8 +143,8 @@ interface Roundable {
|
||||
@JvmDefault
|
||||
fun requestBottomRoundness(
|
||||
@FloatRange(from = 0.0, to = 1.0) value: Float,
|
||||
animate: Boolean,
|
||||
sourceType: SourceType,
|
||||
animate: Boolean,
|
||||
): Boolean {
|
||||
val roundnessMap = roundableState.bottomRoundnessMap
|
||||
val lastValue = roundnessMap.values.maxOrNull() ?: 0f
|
||||
@@ -149,9 +173,101 @@ interface Roundable {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the bottom roundness [value] for a specific [sourceType]. Animate the roundness if
|
||||
* the view is shown.
|
||||
*
|
||||
* 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 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,
|
||||
sourceType: SourceType,
|
||||
): Boolean {
|
||||
return requestBottomRoundness(
|
||||
value = value,
|
||||
sourceType = sourceType,
|
||||
animate = roundableState.targetView.isShown
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the roundness [value] for a specific [sourceType].
|
||||
*
|
||||
* The top/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 top top value between 0f and 1f.
|
||||
* @param bottom bottom value between 0f and 1f.
|
||||
* @param sourceType the source from which the request for roundness comes.
|
||||
* @param animate true if it should animate to that value.
|
||||
* @return Whether the roundness was changed.
|
||||
*/
|
||||
@JvmDefault
|
||||
fun requestRoundness(
|
||||
@FloatRange(from = 0.0, to = 1.0) top: Float,
|
||||
@FloatRange(from = 0.0, to = 1.0) bottom: Float,
|
||||
sourceType: SourceType,
|
||||
animate: Boolean,
|
||||
): Boolean {
|
||||
val hasTopChanged =
|
||||
requestTopRoundness(value = top, sourceType = sourceType, animate = animate)
|
||||
val hasBottomChanged =
|
||||
requestBottomRoundness(value = bottom, sourceType = sourceType, animate = animate)
|
||||
return hasTopChanged || hasBottomChanged
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the roundness [value] for a specific [sourceType]. Animate the roundness if the view
|
||||
* is shown.
|
||||
*
|
||||
* The top/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 top top value between 0f and 1f.
|
||||
* @param bottom bottom value between 0f and 1f.
|
||||
* @param sourceType the source from which the request for roundness comes.
|
||||
* @return Whether the roundness was changed.
|
||||
*/
|
||||
@JvmDefault
|
||||
fun requestRoundness(
|
||||
@FloatRange(from = 0.0, to = 1.0) top: Float,
|
||||
@FloatRange(from = 0.0, to = 1.0) bottom: Float,
|
||||
sourceType: SourceType,
|
||||
): Boolean {
|
||||
return requestRoundness(
|
||||
top = top,
|
||||
bottom = bottom,
|
||||
sourceType = sourceType,
|
||||
animate = roundableState.targetView.isShown,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the roundness 0f for a [SourceType]. Animate the roundness if the view is shown.
|
||||
*
|
||||
* The top/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 sourceType the source from which the request for roundness comes.
|
||||
*/
|
||||
@JvmDefault
|
||||
fun requestRoundnessReset(sourceType: SourceType) {
|
||||
requestRoundness(top = 0f, bottom = 0f, sourceType = sourceType)
|
||||
}
|
||||
|
||||
/** Apply the roundness changes, usually means invalidate the [RoundableState.targetView]. */
|
||||
@JvmDefault
|
||||
fun applyRoundness() {
|
||||
fun applyRoundnessAndInvalidate() {
|
||||
roundableState.targetView.invalidate()
|
||||
}
|
||||
|
||||
@@ -227,7 +343,7 @@ class RoundableState(
|
||||
/** Set the current top roundness */
|
||||
internal fun setTopRoundness(
|
||||
value: Float,
|
||||
animated: Boolean = targetView.isShown,
|
||||
animated: Boolean,
|
||||
) {
|
||||
PropertyAnimator.setProperty(targetView, topAnimatable, value, DURATION, animated)
|
||||
}
|
||||
@@ -235,11 +351,19 @@ class RoundableState(
|
||||
/** Set the current bottom roundness */
|
||||
internal fun setBottomRoundness(
|
||||
value: Float,
|
||||
animated: Boolean = targetView.isShown,
|
||||
animated: Boolean,
|
||||
) {
|
||||
PropertyAnimator.setProperty(targetView, bottomAnimatable, value, DURATION, animated)
|
||||
}
|
||||
|
||||
fun debugString() = buildString {
|
||||
append("TargetView: ${targetView.hashCode()} ")
|
||||
append("Top: $topRoundness ")
|
||||
append(topRoundnessMap.map { "${it.key} ${it.value}" })
|
||||
append(" Bottom: $bottomRoundness ")
|
||||
append(bottomRoundnessMap.map { "${it.key} ${it.value}" })
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DURATION: AnimationProperties =
|
||||
AnimationProperties()
|
||||
@@ -252,7 +376,7 @@ class RoundableState(
|
||||
|
||||
override fun setValue(view: View, value: Float) {
|
||||
roundable.roundableState.topRoundness = value
|
||||
roundable.applyRoundness()
|
||||
roundable.applyRoundnessAndInvalidate()
|
||||
}
|
||||
},
|
||||
R.id.top_roundess_animator_tag,
|
||||
@@ -267,7 +391,7 @@ class RoundableState(
|
||||
|
||||
override fun setValue(view: View, value: Float) {
|
||||
roundable.roundableState.bottomRoundness = value
|
||||
roundable.applyRoundness()
|
||||
roundable.applyRoundnessAndInvalidate()
|
||||
}
|
||||
},
|
||||
R.id.bottom_roundess_animator_tag,
|
||||
@@ -277,7 +401,31 @@ class RoundableState(
|
||||
}
|
||||
}
|
||||
|
||||
enum class SourceType {
|
||||
/**
|
||||
* Interface used to define the owner of a roundness. Usually the [SourceType] is defined as a
|
||||
* private property of a class.
|
||||
*/
|
||||
interface SourceType {
|
||||
companion object {
|
||||
/**
|
||||
* This is the most convenient way to define a new [SourceType].
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```kotlin
|
||||
* private val SECTION = SourceType.from("Section")
|
||||
* ```
|
||||
*/
|
||||
@JvmStatic
|
||||
fun from(name: String) =
|
||||
object : SourceType {
|
||||
override fun toString() = name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Use SourceType.from() instead", ReplaceWith("SourceType.from()"))
|
||||
enum class LegacySourceType : SourceType {
|
||||
DefaultValue,
|
||||
OnDismissAnimation,
|
||||
OnScroll,
|
||||
|
||||
@@ -39,9 +39,13 @@ import com.android.systemui.animation.Interpolators;
|
||||
import com.android.systemui.statusbar.NotificationShelf;
|
||||
import com.android.systemui.statusbar.notification.FakeShadowView;
|
||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||
import com.android.systemui.statusbar.notification.SourceType;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
||||
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationShelf}
|
||||
* to implement dimming/activating on Keyguard for the double-tap gesture
|
||||
@@ -91,6 +95,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
|
||||
= new PathInterpolator(0.6f, 0, 0.5f, 1);
|
||||
private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
|
||||
= new PathInterpolator(0, 0, 0.5f, 1);
|
||||
private final Set<SourceType> mOnDetachResetRoundness = new HashSet<>();
|
||||
private int mTintedRippleColor;
|
||||
private int mNormalRippleColor;
|
||||
private Gefingerpoken mTouchHandler;
|
||||
@@ -134,6 +139,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
|
||||
private boolean mDismissed;
|
||||
private boolean mRefocusOnDismiss;
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
protected boolean mUseRoundnessSourceTypes;
|
||||
|
||||
public ActivatableNotificationView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@@ -613,9 +619,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
|
||||
protected void resetAllContentAlphas() {}
|
||||
|
||||
@Override
|
||||
public void applyRoundness() {
|
||||
super.applyRoundness();
|
||||
public void applyRoundnessAndInvalidate() {
|
||||
applyBackgroundRoundness(getTopCornerRadius(), getBottomCornerRadius());
|
||||
super.applyRoundnessAndInvalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -775,6 +781,33 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
|
||||
mAccessibilityManager = accessibilityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the support for rounded corner based on the SourceType
|
||||
* @param enabled true if is supported
|
||||
*/
|
||||
public void useRoundnessSourceTypes(boolean enabled) {
|
||||
mUseRoundnessSourceTypes = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (mUseRoundnessSourceTypes && !mOnDetachResetRoundness.isEmpty()) {
|
||||
for (SourceType sourceType : mOnDetachResetRoundness) {
|
||||
requestRoundnessReset(sourceType);
|
||||
}
|
||||
mOnDetachResetRoundness.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SourceType which should be reset when this View is detached
|
||||
* @param sourceType will be reset on View detached
|
||||
*/
|
||||
public void addOnDetachResetRoundness(SourceType sourceType) {
|
||||
mOnDetachResetRoundness.add(sourceType);
|
||||
}
|
||||
|
||||
public interface OnActivatedListener {
|
||||
void onActivated(ActivatableNotificationView view);
|
||||
void onActivationReset(ActivatableNotificationView view);
|
||||
|
||||
@@ -91,6 +91,7 @@ import com.android.systemui.statusbar.StatusBarIconView;
|
||||
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
|
||||
import com.android.systemui.statusbar.notification.FeedbackIcon;
|
||||
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
|
||||
import com.android.systemui.statusbar.notification.LegacySourceType;
|
||||
import com.android.systemui.statusbar.notification.NotificationFadeAware;
|
||||
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
|
||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||
@@ -143,6 +144,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
private static final int MENU_VIEW_INDEX = 0;
|
||||
public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
|
||||
private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
|
||||
private static final SourceType BASE_VALUE = SourceType.from("BaseValue");
|
||||
private static final SourceType FROM_PARENT = SourceType.from("FromParent(ENR)");
|
||||
private static final SourceType PINNED = SourceType.from("Pinned");
|
||||
|
||||
// We don't correctly track dark mode until the content views are inflated, so always update
|
||||
// the background on first content update just in case it happens to be during a theme change.
|
||||
@@ -150,6 +154,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
private boolean mNotificationTranslationFinished = false;
|
||||
private boolean mIsSnoozed;
|
||||
private boolean mIsFaded;
|
||||
private boolean mAnimatePinnedRoundness = false;
|
||||
|
||||
/**
|
||||
* Listener for when {@link ExpandableNotificationRow} is laid out.
|
||||
@@ -376,7 +381,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
|
||||
private float mTopRoundnessDuringLaunchAnimation;
|
||||
private float mBottomRoundnessDuringLaunchAnimation;
|
||||
private boolean mIsNotificationGroupCornerEnabled;
|
||||
private float mSmallRoundness;
|
||||
|
||||
/**
|
||||
* Returns whether the given {@code statusBarNotification} is a system notification.
|
||||
@@ -844,7 +849,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
onAttachedChildrenCountChanged();
|
||||
row.setIsChildInGroup(false, null);
|
||||
row.requestBottomRoundness(0.0f, /* animate = */ false, SourceType.DefaultValue);
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
row.requestBottomRoundness(0.0f, LegacySourceType.DefaultValue, /* animate = */ false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -860,7 +867,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
if (child.keepInParentForDismissAnimation()) {
|
||||
mChildrenContainer.removeNotification(child);
|
||||
child.setIsChildInGroup(false, null);
|
||||
child.requestBottomRoundness(0.0f, /* animate = */ false, SourceType.DefaultValue);
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
LegacySourceType sourceType = LegacySourceType.DefaultValue;
|
||||
child.requestBottomRoundness(0f, sourceType, /* animate = */ false);
|
||||
}
|
||||
child.setKeepInParentForDismissAnimation(false);
|
||||
logKeepInParentChildDetached(child);
|
||||
childCountChanged = true;
|
||||
@@ -915,6 +925,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
mNotificationParent.updateBackgroundForGroupState();
|
||||
}
|
||||
updateBackgroundClipping();
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
updateBaseRoundness();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1033,6 +1046,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
if (isAboveShelf() != wasAboveShelf) {
|
||||
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
|
||||
}
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
if (pinned) {
|
||||
// Should be animated if someone explicitly set it to 0 and the row is shown.
|
||||
boolean animated = mAnimatePinnedRoundness && isShown();
|
||||
requestRoundness(/* top = */ 1f, /* bottom = */ 1f, PINNED, animated);
|
||||
} else {
|
||||
requestRoundnessReset(PINNED);
|
||||
mAnimatePinnedRoundness = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1607,6 +1630,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
super(context, attrs);
|
||||
mImageResolver = new NotificationInlineImageResolver(context,
|
||||
new NotificationInlineImageCache());
|
||||
float radius = getResources().getDimension(R.dimen.notification_corner_radius_small);
|
||||
mSmallRoundness = radius / getMaxRadius();
|
||||
initDimens();
|
||||
}
|
||||
|
||||
@@ -1839,7 +1864,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
mChildrenContainer.setIsLowPriority(mIsLowPriority);
|
||||
mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
|
||||
mChildrenContainer.onNotificationUpdated();
|
||||
mChildrenContainer.enableNotificationGroupCorner(mIsNotificationGroupCornerEnabled);
|
||||
mChildrenContainer.useRoundnessSourceTypes(mUseRoundnessSourceTypes);
|
||||
|
||||
mTranslateableViews.add(mChildrenContainer);
|
||||
});
|
||||
@@ -2271,7 +2296,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
|
||||
@Override
|
||||
public float getTopRoundness() {
|
||||
if (mExpandAnimationRunning) {
|
||||
if (!mUseRoundnessSourceTypes && mExpandAnimationRunning) {
|
||||
return mTopRoundnessDuringLaunchAnimation;
|
||||
}
|
||||
|
||||
@@ -2280,7 +2305,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
|
||||
@Override
|
||||
public float getBottomRoundness() {
|
||||
if (mExpandAnimationRunning) {
|
||||
if (!mUseRoundnessSourceTypes && mExpandAnimationRunning) {
|
||||
return mBottomRoundnessDuringLaunchAnimation;
|
||||
}
|
||||
|
||||
@@ -3436,17 +3461,24 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoundness() {
|
||||
super.applyRoundness();
|
||||
public void applyRoundnessAndInvalidate() {
|
||||
applyChildrenRoundness();
|
||||
super.applyRoundnessAndInvalidate();
|
||||
}
|
||||
|
||||
private void applyChildrenRoundness() {
|
||||
if (mIsSummaryWithChildren) {
|
||||
mChildrenContainer.requestBottomRoundness(
|
||||
getBottomRoundness(),
|
||||
/* animate = */ false,
|
||||
SourceType.DefaultValue);
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
mChildrenContainer.requestRoundness(
|
||||
/* top = */ getTopRoundness(),
|
||||
/* bottom = */ getBottomRoundness(),
|
||||
FROM_PARENT);
|
||||
} else {
|
||||
mChildrenContainer.requestBottomRoundness(
|
||||
getBottomRoundness(),
|
||||
LegacySourceType.DefaultValue,
|
||||
/* animate = */ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3605,6 +3637,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
} else {
|
||||
pw.println("no viewState!!!");
|
||||
}
|
||||
pw.println("Roundness: " + getRoundableState().debugString());
|
||||
|
||||
if (mIsSummaryWithChildren) {
|
||||
pw.println();
|
||||
@@ -3649,14 +3682,38 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
return mTargetPoint;
|
||||
}
|
||||
|
||||
/** Update the minimum roundness based on current state */
|
||||
private void updateBaseRoundness() {
|
||||
if (isChildInGroup()) {
|
||||
requestRoundnessReset(BASE_VALUE);
|
||||
} else {
|
||||
requestRoundness(mSmallRoundness, mSmallRoundness, BASE_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the support for rounded corner in notification group
|
||||
* Enable the support for rounded corner based on the SourceType
|
||||
* @param enabled true if is supported
|
||||
*/
|
||||
public void enableNotificationGroupCorner(boolean enabled) {
|
||||
mIsNotificationGroupCornerEnabled = enabled;
|
||||
@Override
|
||||
public void useRoundnessSourceTypes(boolean enabled) {
|
||||
super.useRoundnessSourceTypes(enabled);
|
||||
if (mChildrenContainer != null) {
|
||||
mChildrenContainer.enableNotificationGroupCorner(mIsNotificationGroupCornerEnabled);
|
||||
mChildrenContainer.useRoundnessSourceTypes(mUseRoundnessSourceTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String roundableStateDebug = "RoundableState = " + getRoundableState().debugString();
|
||||
return "ExpandableNotificationRow:" + hashCode() + " { " + roundableStateDebug + " }";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
updateBaseRoundness();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,8 +255,8 @@ public class ExpandableNotificationRowController implements NotifViewController
|
||||
mStatusBarStateController.removeCallback(mStatusBarStateListener);
|
||||
}
|
||||
});
|
||||
mView.enableNotificationGroupCorner(
|
||||
mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_CORNER));
|
||||
mView.useRoundnessSourceTypes(
|
||||
mFeatureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES));
|
||||
}
|
||||
|
||||
private final StatusBarStateController.StateListener mStatusBarStateListener =
|
||||
|
||||
@@ -219,9 +219,9 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoundness() {
|
||||
public void applyRoundnessAndInvalidate() {
|
||||
invalidateOutline();
|
||||
super.applyRoundness();
|
||||
super.applyRoundnessAndInvalidate();
|
||||
}
|
||||
|
||||
protected void setBackgroundTop(int backgroundTop) {
|
||||
@@ -233,7 +233,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
||||
|
||||
public void onDensityOrFontScaleChanged() {
|
||||
initDimens();
|
||||
applyRoundness();
|
||||
applyRoundnessAndInvalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -241,7 +241,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
||||
int previousHeight = getActualHeight();
|
||||
super.setActualHeight(actualHeight, notifyListeners);
|
||||
if (previousHeight != actualHeight) {
|
||||
applyRoundness();
|
||||
applyRoundnessAndInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
||||
int previousAmount = getClipTopAmount();
|
||||
super.setClipTopAmount(clipTopAmount);
|
||||
if (previousAmount != clipTopAmount) {
|
||||
applyRoundness();
|
||||
applyRoundnessAndInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,14 +259,14 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
||||
int previousAmount = getClipBottomAmount();
|
||||
super.setClipBottomAmount(clipBottomAmount);
|
||||
if (previousAmount != clipBottomAmount) {
|
||||
applyRoundness();
|
||||
applyRoundnessAndInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setOutlineAlpha(float alpha) {
|
||||
if (alpha != mOutlineAlpha) {
|
||||
mOutlineAlpha = alpha;
|
||||
applyRoundness();
|
||||
applyRoundnessAndInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
||||
setOutlineRect(rect.left, rect.top, rect.right, rect.bottom);
|
||||
} else {
|
||||
mCustomOutline = false;
|
||||
applyRoundness();
|
||||
applyRoundnessAndInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +340,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
|
||||
// Outlines need to be at least 1 dp
|
||||
mOutlineRect.bottom = (int) Math.max(top, mOutlineRect.bottom);
|
||||
mOutlineRect.right = (int) Math.max(left, mOutlineRect.right);
|
||||
applyRoundness();
|
||||
applyRoundnessAndInvalidate();
|
||||
}
|
||||
|
||||
public Path getCustomClipPath(View child) {
|
||||
|
||||
@@ -343,4 +343,14 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper imple
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface that handle the Roundness changes
|
||||
*/
|
||||
public interface RoundnessChangedListener {
|
||||
/**
|
||||
* This method will be called when this class call applyRoundnessAndInvalidate()
|
||||
*/
|
||||
void applyRoundnessAndInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.android.systemui.statusbar.CrossFadeHelper;
|
||||
import com.android.systemui.statusbar.NotificationGroupingUtil;
|
||||
import com.android.systemui.statusbar.NotificationShelf;
|
||||
import com.android.systemui.statusbar.notification.FeedbackIcon;
|
||||
import com.android.systemui.statusbar.notification.LegacySourceType;
|
||||
import com.android.systemui.statusbar.notification.NotificationFadeAware;
|
||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||
import com.android.systemui.statusbar.notification.Roundable;
|
||||
@@ -83,6 +84,7 @@ public class NotificationChildrenContainer extends ViewGroup
|
||||
return mAnimationFilter;
|
||||
}
|
||||
}.setDuration(200);
|
||||
private static final SourceType FROM_PARENT = SourceType.from("FromParent(NCC)");
|
||||
|
||||
private final List<View> mDividers = new ArrayList<>();
|
||||
private final List<ExpandableNotificationRow> mAttachedChildren = new ArrayList<>();
|
||||
@@ -131,7 +133,7 @@ public class NotificationChildrenContainer extends ViewGroup
|
||||
private int mUntruncatedChildCount;
|
||||
private boolean mContainingNotificationIsFaded = false;
|
||||
private RoundableState mRoundableState;
|
||||
private boolean mIsNotificationGroupCornerEnabled;
|
||||
private boolean mUseRoundnessSourceTypes;
|
||||
|
||||
public NotificationChildrenContainer(Context context) {
|
||||
this(context, null);
|
||||
@@ -313,9 +315,12 @@ public class NotificationChildrenContainer extends ViewGroup
|
||||
row.setContentTransformationAmount(0, false /* isLastChild */);
|
||||
row.setNotificationFaded(mContainingNotificationIsFaded);
|
||||
|
||||
// This is a workaround, the NotificationShelf should be the owner of `OnScroll` roundness.
|
||||
// Here we should reset the `OnScroll` roundness only on top-level rows.
|
||||
NotificationShelf.resetOnScrollRoundness(row);
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
// This is a workaround, the NotificationShelf should be the owner of `OnScroll`
|
||||
// roundness.
|
||||
// Here we should reset the `OnScroll` roundness only on top-level rows.
|
||||
NotificationShelf.resetLegacyOnScrollRoundness(row);
|
||||
}
|
||||
|
||||
// It doesn't make sense to keep old animations around, lets cancel them!
|
||||
ExpandableViewState viewState = row.getViewState();
|
||||
@@ -323,6 +328,10 @@ public class NotificationChildrenContainer extends ViewGroup
|
||||
viewState.cancelAnimations(row);
|
||||
row.cancelAppearDrawing();
|
||||
}
|
||||
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
applyRoundnessAndInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureRemovedFromTransientContainer(View v) {
|
||||
@@ -356,6 +365,11 @@ public class NotificationChildrenContainer extends ViewGroup
|
||||
if (!row.isRemoved()) {
|
||||
mGroupingUtil.restoreChildNotification(row);
|
||||
}
|
||||
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
row.requestRoundnessReset(FROM_PARENT);
|
||||
applyRoundnessAndInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -841,7 +855,7 @@ public class NotificationChildrenContainer extends ViewGroup
|
||||
|
||||
isCanvasChanged = true;
|
||||
canvas.save();
|
||||
if (mIsNotificationGroupCornerEnabled && translation != 0f) {
|
||||
if (mUseRoundnessSourceTypes && translation != 0f) {
|
||||
clipPath.offset(translation, 0f);
|
||||
canvas.clipPath(clipPath);
|
||||
clipPath.offset(-translation, 0f);
|
||||
@@ -1392,24 +1406,28 @@ public class NotificationChildrenContainer extends ViewGroup
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoundness() {
|
||||
Roundable.super.applyRoundness();
|
||||
public void applyRoundnessAndInvalidate() {
|
||||
boolean last = true;
|
||||
for (int i = mAttachedChildren.size() - 1; i >= 0; i--) {
|
||||
ExpandableNotificationRow child = mAttachedChildren.get(i);
|
||||
if (child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
child.requestTopRoundness(
|
||||
/* value = */ 0f,
|
||||
/* animate = */ isShown(),
|
||||
SourceType.DefaultValue);
|
||||
child.requestBottomRoundness(
|
||||
/* value = */ last ? getBottomRoundness() : 0f,
|
||||
/* animate = */ isShown(),
|
||||
SourceType.DefaultValue);
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
child.requestRoundness(
|
||||
/* top = */ 0f,
|
||||
/* bottom = */ last ? getBottomRoundness() : 0f,
|
||||
FROM_PARENT);
|
||||
} else {
|
||||
child.requestRoundness(
|
||||
/* top = */ 0f,
|
||||
/* bottom = */ last ? getBottomRoundness() : 0f,
|
||||
LegacySourceType.DefaultValue,
|
||||
/* animate = */ isShown());
|
||||
}
|
||||
last = false;
|
||||
}
|
||||
Roundable.super.applyRoundnessAndInvalidate();
|
||||
}
|
||||
|
||||
public void setHeaderVisibleAmount(float headerVisibleAmount) {
|
||||
@@ -1467,10 +1485,17 @@ public class NotificationChildrenContainer extends ViewGroup
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the support for rounded corner in notification group
|
||||
* Enable the support for rounded corner based on the SourceType
|
||||
*
|
||||
* @param enabled true if is supported
|
||||
*/
|
||||
public void enableNotificationGroupCorner(boolean enabled) {
|
||||
mIsNotificationGroupCornerEnabled = enabled;
|
||||
public void useRoundnessSourceTypes(boolean enabled) {
|
||||
mUseRoundnessSourceTypes = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String roundableStateDebug = "RoundableState = " + getRoundableState().debugString();
|
||||
return "NotificationChildrenContainer:" + hashCode() + " { " + roundableStateDebug + " }";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.statusbar.notification.LegacySourceType;
|
||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
||||
import com.android.systemui.statusbar.notification.Roundable;
|
||||
import com.android.systemui.statusbar.notification.SourceType;
|
||||
@@ -45,6 +48,7 @@ import javax.inject.Inject;
|
||||
public class NotificationRoundnessManager implements Dumpable {
|
||||
|
||||
private static final String TAG = "NotificationRoundnessManager";
|
||||
private static final SourceType DISMISS_ANIMATION = SourceType.from("DismissAnimation");
|
||||
|
||||
private final ExpandableView[] mFirstInSectionViews;
|
||||
private final ExpandableView[] mLastInSectionViews;
|
||||
@@ -63,12 +67,14 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
private ExpandableView mSwipedView = null;
|
||||
private Roundable mViewBeforeSwipedView = null;
|
||||
private Roundable mViewAfterSwipedView = null;
|
||||
private boolean mUseRoundnessSourceTypes;
|
||||
|
||||
@Inject
|
||||
NotificationRoundnessManager(
|
||||
NotificationSectionsFeatureManager sectionsFeatureManager,
|
||||
NotificationRoundnessLogger notifLogger,
|
||||
DumpManager dumpManager) {
|
||||
DumpManager dumpManager,
|
||||
FeatureFlags featureFlags) {
|
||||
int numberOfSections = sectionsFeatureManager.getNumberOfBuckets();
|
||||
mFirstInSectionViews = new ExpandableView[numberOfSections];
|
||||
mLastInSectionViews = new ExpandableView[numberOfSections];
|
||||
@@ -76,6 +82,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
mTmpLastInSectionViews = new ExpandableView[numberOfSections];
|
||||
mNotifLogger = notifLogger;
|
||||
mDumpManager = dumpManager;
|
||||
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
|
||||
|
||||
mDumpManager.registerDumpable(TAG, this);
|
||||
}
|
||||
@@ -94,6 +101,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
}
|
||||
|
||||
public void updateView(ExpandableView view, boolean animate) {
|
||||
if (mUseRoundnessSourceTypes) return;
|
||||
boolean changed = updateViewWithoutCallback(view, animate);
|
||||
if (changed) {
|
||||
mRoundingChangedCallback.run();
|
||||
@@ -110,6 +118,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
boolean updateViewWithoutCallback(
|
||||
ExpandableView view,
|
||||
boolean animate) {
|
||||
if (mUseRoundnessSourceTypes) return false;
|
||||
if (view == null
|
||||
|| view == mViewBeforeSwipedView
|
||||
|| view == mViewAfterSwipedView) {
|
||||
@@ -118,13 +127,13 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
|
||||
final boolean isTopChanged = view.requestTopRoundness(
|
||||
getRoundnessDefaultValue(view, true /* top */),
|
||||
animate,
|
||||
SourceType.DefaultValue);
|
||||
LegacySourceType.DefaultValue,
|
||||
animate);
|
||||
|
||||
final boolean isBottomChanged = view.requestBottomRoundness(
|
||||
getRoundnessDefaultValue(view, /* top = */ false),
|
||||
animate,
|
||||
SourceType.DefaultValue);
|
||||
LegacySourceType.DefaultValue,
|
||||
animate);
|
||||
|
||||
final boolean isFirstInSection = isFirstInSection(view);
|
||||
final boolean isLastInSection = isLastInSection(view);
|
||||
@@ -139,6 +148,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
}
|
||||
|
||||
private boolean isFirstInSection(ExpandableView view) {
|
||||
if (mUseRoundnessSourceTypes) return false;
|
||||
for (int i = 0; i < mFirstInSectionViews.length; i++) {
|
||||
if (view == mFirstInSectionViews[i]) {
|
||||
return true;
|
||||
@@ -148,6 +158,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
}
|
||||
|
||||
private boolean isLastInSection(ExpandableView view) {
|
||||
if (mUseRoundnessSourceTypes) return false;
|
||||
for (int i = mLastInSectionViews.length - 1; i >= 0; i--) {
|
||||
if (view == mLastInSectionViews[i]) {
|
||||
return true;
|
||||
@@ -160,9 +171,6 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
Roundable viewBefore,
|
||||
ExpandableView viewSwiped,
|
||||
Roundable viewAfter) {
|
||||
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
|
||||
@@ -172,31 +180,34 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
if (mSwipedView != null) oldViews.add(mSwipedView);
|
||||
if (mViewAfterSwipedView != null) oldViews.add(mViewAfterSwipedView);
|
||||
|
||||
final SourceType source;
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
source = DISMISS_ANIMATION;
|
||||
} else {
|
||||
source = LegacySourceType.OnDismissAnimation;
|
||||
}
|
||||
|
||||
mViewBeforeSwipedView = viewBefore;
|
||||
if (viewBefore != null) {
|
||||
oldViews.remove(viewBefore);
|
||||
viewBefore.requestTopRoundness(0f, animate, source);
|
||||
viewBefore.requestBottomRoundness(1f, animate, source);
|
||||
viewBefore.requestRoundness(/* top = */ 0f, /* bottom = */ 1f, source);
|
||||
}
|
||||
|
||||
mSwipedView = viewSwiped;
|
||||
if (viewSwiped != null) {
|
||||
oldViews.remove(viewSwiped);
|
||||
viewSwiped.requestTopRoundness(1f, animate, source);
|
||||
viewSwiped.requestBottomRoundness(1f, animate, source);
|
||||
viewSwiped.requestRoundness(/* top = */ 1f, /* bottom = */ 1f, source);
|
||||
}
|
||||
|
||||
mViewAfterSwipedView = viewAfter;
|
||||
if (viewAfter != null) {
|
||||
oldViews.remove(viewAfter);
|
||||
viewAfter.requestTopRoundness(1f, animate, source);
|
||||
viewAfter.requestBottomRoundness(0f, animate, source);
|
||||
viewAfter.requestRoundness(/* top = */ 1f, /* bottom = */ 0f, 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);
|
||||
oldView.requestRoundnessReset(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +215,23 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
mIsClearAllInProgress = isClearingAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if "Clear all" notifications is in progress.
|
||||
*/
|
||||
public boolean isClearAllInProgress() {
|
||||
return mIsClearAllInProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we can request the `Pulsing` roundness for notification.
|
||||
*/
|
||||
public boolean shouldRoundNotificationPulsing() {
|
||||
return mRoundForPulsingViews;
|
||||
}
|
||||
|
||||
private float getRoundnessDefaultValue(Roundable view, boolean top) {
|
||||
if (mUseRoundnessSourceTypes) return 0f;
|
||||
|
||||
if (view == null) {
|
||||
return 0f;
|
||||
}
|
||||
@@ -250,6 +277,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
}
|
||||
|
||||
public void setExpanded(float expandedHeight, float appearFraction) {
|
||||
if (mUseRoundnessSourceTypes) return;
|
||||
mExpanded = expandedHeight != 0.0f;
|
||||
mAppearFraction = appearFraction;
|
||||
if (mTrackedHeadsUp != null) {
|
||||
@@ -258,6 +286,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
}
|
||||
|
||||
public void updateRoundedChildren(NotificationSection[] sections) {
|
||||
if (mUseRoundnessSourceTypes) return;
|
||||
boolean anyChanged = false;
|
||||
for (int i = 0; i < sections.length; i++) {
|
||||
mTmpFirstInSectionViews[i] = mFirstInSectionViews[i];
|
||||
@@ -280,6 +309,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
NotificationSection[] sections,
|
||||
ExpandableView[] oldViews,
|
||||
boolean first) {
|
||||
if (mUseRoundnessSourceTypes) return false;
|
||||
boolean anyChanged = false;
|
||||
for (ExpandableView oldView : oldViews) {
|
||||
if (oldView != null) {
|
||||
@@ -313,6 +343,7 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
NotificationSection[] sections,
|
||||
ExpandableView[] oldViews,
|
||||
boolean first) {
|
||||
if (mUseRoundnessSourceTypes) return false;
|
||||
boolean anyChanged = false;
|
||||
for (NotificationSection section : sections) {
|
||||
ExpandableView newView =
|
||||
@@ -339,6 +370,15 @@ public class NotificationRoundnessManager implements Dumpable {
|
||||
mAnimatedChildren = animatedChildren;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the view should be animated
|
||||
* @param view target view
|
||||
* @return true, if is in the AnimatedChildren set
|
||||
*/
|
||||
public boolean isAnimatedChild(ExpandableView view) {
|
||||
return mAnimatedChildren.contains(view);
|
||||
}
|
||||
|
||||
public void setOnRoundingChangedCallback(Runnable roundingChangedCallback) {
|
||||
mRoundingChangedCallback = roundingChangedCallback;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@ import android.annotation.ColorInt
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import com.android.internal.annotations.VisibleForTesting
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.media.controls.ui.KeyguardMediaController
|
||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
|
||||
import com.android.systemui.statusbar.notification.SourceType
|
||||
import com.android.systemui.statusbar.notification.collection.render.MediaContainerController
|
||||
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController
|
||||
import com.android.systemui.statusbar.notification.dagger.AlertingHeader
|
||||
@@ -44,12 +47,16 @@ class NotificationSectionsManager @Inject internal constructor(
|
||||
private val keyguardMediaController: KeyguardMediaController,
|
||||
private val sectionsFeatureManager: NotificationSectionsFeatureManager,
|
||||
private val mediaContainerController: MediaContainerController,
|
||||
private val notificationRoundnessManager: NotificationRoundnessManager,
|
||||
@IncomingHeader private val incomingHeaderController: SectionHeaderController,
|
||||
@PeopleHeader private val peopleHeaderController: SectionHeaderController,
|
||||
@AlertingHeader private val alertingHeaderController: SectionHeaderController,
|
||||
@SilentHeader private val silentHeaderController: SectionHeaderController
|
||||
@SilentHeader private val silentHeaderController: SectionHeaderController,
|
||||
featureFlags: FeatureFlags
|
||||
) : SectionProvider {
|
||||
|
||||
private val useRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)
|
||||
|
||||
private val configurationListener = object : ConfigurationController.ConfigurationListener {
|
||||
override fun onLocaleListChanged() {
|
||||
reinflateViews()
|
||||
@@ -177,11 +184,49 @@ class NotificationSectionsManager @Inject internal constructor(
|
||||
size = sections.size,
|
||||
operation = SectionBounds::addNotif
|
||||
)
|
||||
|
||||
// Build a set of the old first/last Views of the sections
|
||||
val oldFirstChildren = sections.mapNotNull { it.firstVisibleChild }.toSet().toMutableSet()
|
||||
val oldLastChildren = sections.mapNotNull { it.lastVisibleChild }.toSet().toMutableSet()
|
||||
|
||||
// Update each section with the associated boundary, tracking if there was a change
|
||||
val changed = sections.fold(false) { changed, section ->
|
||||
val bounds = sectionBounds[section.bucket] ?: SectionBounds.None
|
||||
bounds.updateSection(section) || changed
|
||||
val isSectionChanged = bounds.updateSection(section)
|
||||
isSectionChanged || changed
|
||||
}
|
||||
|
||||
if (useRoundnessSourceTypes) {
|
||||
val newFirstChildren = sections.mapNotNull { it.firstVisibleChild }
|
||||
val newLastChildren = sections.mapNotNull { it.lastVisibleChild }
|
||||
|
||||
// Update the roundness of Views that weren't already in the first/last position
|
||||
newFirstChildren.forEach { firstChild ->
|
||||
val wasFirstChild = oldFirstChildren.remove(firstChild)
|
||||
if (!wasFirstChild) {
|
||||
val notAnimatedChild = !notificationRoundnessManager.isAnimatedChild(firstChild)
|
||||
val animated = firstChild.isShown && notAnimatedChild
|
||||
firstChild.requestTopRoundness(1f, SECTION, animated)
|
||||
}
|
||||
}
|
||||
newLastChildren.forEach { lastChild ->
|
||||
val wasLastChild = oldLastChildren.remove(lastChild)
|
||||
if (!wasLastChild) {
|
||||
val notAnimatedChild = !notificationRoundnessManager.isAnimatedChild(lastChild)
|
||||
val animated = lastChild.isShown && notAnimatedChild
|
||||
lastChild.requestBottomRoundness(1f, SECTION, animated)
|
||||
}
|
||||
}
|
||||
|
||||
// The Views left in the set are no longer in the first/last position
|
||||
oldFirstChildren.forEach { noMoreFirstChild ->
|
||||
noMoreFirstChild.requestTopRoundness(0f, SECTION)
|
||||
}
|
||||
oldLastChildren.forEach { noMoreLastChild ->
|
||||
noMoreLastChild.requestBottomRoundness(0f, SECTION)
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
logSections(sections)
|
||||
}
|
||||
@@ -215,5 +260,6 @@ class NotificationSectionsManager @Inject internal constructor(
|
||||
companion object {
|
||||
private const val TAG = "NotifSectionsManager"
|
||||
private const val DEBUG = false
|
||||
private val SECTION = SourceType.from("Section")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,10 +191,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
|
||||
private final boolean mDebugLines;
|
||||
private Paint mDebugPaint;
|
||||
/** Used to track the Y positions that were already used to draw debug text labels. */
|
||||
/**
|
||||
* Used to track the Y positions that were already used to draw debug text labels.
|
||||
*/
|
||||
private Set<Integer> mDebugTextUsedYPositions;
|
||||
private final boolean mDebugRemoveAnimation;
|
||||
private final boolean mSimplifiedAppearFraction;
|
||||
private final boolean mUseRoundnessSourceTypes;
|
||||
|
||||
private int mContentHeight;
|
||||
private float mIntrinsicContentHeight;
|
||||
@@ -355,15 +358,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
private final Rect mQsHeaderBound = new Rect();
|
||||
private boolean mContinuousShadowUpdate;
|
||||
private boolean mContinuousBackgroundUpdate;
|
||||
private final ViewTreeObserver.OnPreDrawListener mShadowUpdater
|
||||
= () -> {
|
||||
updateViewShadows();
|
||||
return true;
|
||||
};
|
||||
private final ViewTreeObserver.OnPreDrawListener mShadowUpdater = () -> {
|
||||
updateViewShadows();
|
||||
return true;
|
||||
};
|
||||
private final ViewTreeObserver.OnPreDrawListener mBackgroundUpdater = () -> {
|
||||
updateBackground();
|
||||
return true;
|
||||
};
|
||||
updateBackground();
|
||||
return true;
|
||||
};
|
||||
private final Comparator<ExpandableView> mViewPositionComparator = (view, otherView) -> {
|
||||
float endY = view.getTranslationY() + view.getActualHeight();
|
||||
float otherEndY = otherView.getTranslationY() + otherView.getActualHeight();
|
||||
@@ -419,7 +421,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
*/
|
||||
private int mMaxDisplayedNotifications = -1;
|
||||
private float mKeyguardBottomPadding = -1;
|
||||
@VisibleForTesting int mStatusBarHeight;
|
||||
@VisibleForTesting
|
||||
int mStatusBarHeight;
|
||||
private int mMinInteractionHeight;
|
||||
private final Rect mClipRect = new Rect();
|
||||
private boolean mIsClipped;
|
||||
@@ -568,6 +571,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
|
||||
@Nullable
|
||||
private OnClickListener mManageButtonClickListener;
|
||||
@Nullable
|
||||
private OnNotificationRemovedListener mOnNotificationRemovedListener;
|
||||
|
||||
public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, 0, 0);
|
||||
@@ -576,6 +581,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
mDebugLines = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES);
|
||||
mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
|
||||
mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION);
|
||||
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
|
||||
mSectionsManager = Dependency.get(NotificationSectionsManager.class);
|
||||
mScreenOffAnimationController =
|
||||
Dependency.get(ScreenOffAnimationController.class);
|
||||
@@ -741,7 +747,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
}
|
||||
|
||||
private void logHunSkippedForUnexpectedState(ExpandableNotificationRow enr,
|
||||
boolean expected, boolean actual) {
|
||||
boolean expected, boolean actual) {
|
||||
if (mLogger == null) return;
|
||||
mLogger.hunSkippedForUnexpectedState(enr.getEntry(), expected, actual);
|
||||
}
|
||||
@@ -868,13 +874,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
|
||||
/**
|
||||
* Draws round rects for each background section.
|
||||
*
|
||||
* <p>
|
||||
* We want to draw a round rect for each background section as defined by {@link #mSections}.
|
||||
* However, if two sections are directly adjacent with no gap between them (e.g. on the
|
||||
* lockscreen where the shelf can appear directly below the high priority section, or while
|
||||
* scrolling the shade so that the top of the shelf is right at the bottom of the high priority
|
||||
* section), we don't want to round the adjacent corners.
|
||||
*
|
||||
* <p>
|
||||
* Since {@link Canvas} doesn't provide a way to draw a half-rounded rect, this means that we
|
||||
* need to coalesce the backgrounds for adjacent sections and draw them as a single round rect.
|
||||
* This method tracks the top of each rect we need to draw, then iterates through the visible
|
||||
@@ -883,7 +889,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
* the current section. When we're done iterating we will always have one rect left to draw.
|
||||
*/
|
||||
private void drawBackgroundRects(Canvas canvas, int left, int right, int top,
|
||||
int animationYOffset) {
|
||||
int animationYOffset) {
|
||||
int backgroundRectTop = top;
|
||||
int lastSectionBottom =
|
||||
mSections[0].getCurrentBounds().bottom + animationYOffset;
|
||||
@@ -974,7 +980,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
|
||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||
void initView(Context context, NotificationSwipeHelper swipeHelper,
|
||||
NotificationStackSizeCalculator notificationStackSizeCalculator) {
|
||||
NotificationStackSizeCalculator notificationStackSizeCalculator) {
|
||||
mScroller = new OverScroller(getContext());
|
||||
mSwipeHelper = swipeHelper;
|
||||
mNotificationStackSizeCalculator = notificationStackSizeCalculator;
|
||||
@@ -1304,18 +1310,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
/**
|
||||
* @return Whether we should skip stack height updates.
|
||||
* True when
|
||||
* 1) Unlock hint is running
|
||||
* 2) Swiping up on lockscreen or flinging down after swipe up
|
||||
* 1) Unlock hint is running
|
||||
* 2) Swiping up on lockscreen or flinging down after swipe up
|
||||
*/
|
||||
private boolean shouldSkipHeightUpdate() {
|
||||
return mAmbientState.isOnKeyguard()
|
||||
&& (mAmbientState.isUnlockHintRunning()
|
||||
|| mAmbientState.isSwipingUp()
|
||||
|| mAmbientState.isFlingingAfterSwipeUpOnLockscreen());
|
||||
|| mAmbientState.isSwipingUp()
|
||||
|| mAmbientState.isFlingingAfterSwipeUpOnLockscreen());
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply expansion fraction to the y position and height of the notifications panel.
|
||||
*
|
||||
* @param listenerNeedsAnimation does the listener need to animate?
|
||||
*/
|
||||
private void updateStackPosition(boolean listenerNeedsAnimation) {
|
||||
@@ -1708,7 +1715,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
*/
|
||||
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
||||
ExpandableView getChildAtPosition(float touchX, float touchY,
|
||||
boolean requireMinHeight, boolean ignoreDecors) {
|
||||
boolean requireMinHeight, boolean ignoreDecors) {
|
||||
// find the view under the pointer, accounting for GONE views
|
||||
final int count = getChildCount();
|
||||
for (int childIdx = 0; childIdx < count; childIdx++) {
|
||||
@@ -1868,9 +1875,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
public void dismissViewAnimated(
|
||||
View child, Consumer<Boolean> endRunnable, int delay, long duration) {
|
||||
if (child instanceof SectionHeaderView) {
|
||||
((StackScrollerDecorView) child).setContentVisible(
|
||||
false /* visible */, true /* animate */, endRunnable);
|
||||
return;
|
||||
((StackScrollerDecorView) child).setContentVisible(
|
||||
false /* visible */, true /* animate */, endRunnable);
|
||||
return;
|
||||
}
|
||||
mSwipeHelper.dismissChild(
|
||||
child,
|
||||
@@ -2032,10 +2039,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
/**
|
||||
* Scrolls by the given delta, overscrolling if needed. If called during a fling and the delta
|
||||
* would cause us to exceed the provided maximum overscroll, springs back instead.
|
||||
*
|
||||
* <p>
|
||||
* This method performs the determination of whether we're exceeding the overscroll and clamps
|
||||
* the scroll amount if so. The actual scrolling/overscrolling happens in
|
||||
* {@link #onCustomOverScrolled(int, boolean)}
|
||||
*
|
||||
* @param deltaY The (signed) number of pixels to scroll.
|
||||
* @param scrollY The current scroll position (absolute scrolling only).
|
||||
* @param scrollRangeY The maximum allowable scroll position (absolute scrolling only).
|
||||
@@ -2098,7 +2106,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
*/
|
||||
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
|
||||
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
|
||||
boolean cancelAnimators) {
|
||||
boolean cancelAnimators) {
|
||||
setOverScrollAmount(amount, onTop, animate, cancelAnimators, isRubberbanded(onTop));
|
||||
}
|
||||
|
||||
@@ -2114,7 +2122,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
*/
|
||||
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
|
||||
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
|
||||
boolean cancelAnimators, boolean isRubberbanded) {
|
||||
boolean cancelAnimators, boolean isRubberbanded) {
|
||||
if (cancelAnimators) {
|
||||
mStateAnimator.cancelOverScrollAnimators(onTop);
|
||||
}
|
||||
@@ -2123,7 +2131,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
|
||||
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
|
||||
private void setOverScrollAmountInternal(float amount, boolean onTop, boolean animate,
|
||||
boolean isRubberbanded) {
|
||||
boolean isRubberbanded) {
|
||||
amount = Math.max(0, amount);
|
||||
if (animate) {
|
||||
mStateAnimator.animateOverScrollToAmount(amount, onTop, isRubberbanded);
|
||||
@@ -2179,7 +2187,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
* Scrolls to the given position, overscrolling if needed. If called during a fling and the
|
||||
* position exceeds the provided maximum overscroll, springs back instead.
|
||||
*
|
||||
* @param scrollY The target scroll position.
|
||||
* @param scrollY The target scroll position.
|
||||
* @param clampedY Whether this value was clamped by the calling method, meaning we've reached
|
||||
* the overscroll limit.
|
||||
*/
|
||||
@@ -2288,8 +2296,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
if (row.isSummaryWithChildren() && row.areChildrenExpanded()) {
|
||||
List<ExpandableNotificationRow> notificationChildren =
|
||||
row.getAttachedChildren();
|
||||
for (int childIndex = 0; childIndex < notificationChildren.size();
|
||||
childIndex++) {
|
||||
int childrenSize = notificationChildren.size();
|
||||
for (int childIndex = 0; childIndex < childrenSize; childIndex++) {
|
||||
ExpandableNotificationRow rowChild = notificationChildren.get(childIndex);
|
||||
if (rowChild.getTranslationY() + rowTranslation >= translationY) {
|
||||
return rowChild;
|
||||
@@ -2365,10 +2373,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
/**
|
||||
* Calculate the gap height between two different views
|
||||
*
|
||||
* @param previous the previousView
|
||||
* @param current the currentView
|
||||
* @param previous the previousView
|
||||
* @param current the currentView
|
||||
* @param visibleIndex the visible index in the list
|
||||
*
|
||||
* @return the gap height needed before the current view
|
||||
*/
|
||||
public float calculateGapHeight(
|
||||
@@ -2376,7 +2383,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
ExpandableView current,
|
||||
int visibleIndex
|
||||
) {
|
||||
return mStackScrollAlgorithm.getGapHeightForChild(mSectionsManager, visibleIndex, current,
|
||||
return mStackScrollAlgorithm.getGapHeightForChild(mSectionsManager, visibleIndex, current,
|
||||
previous, mAmbientState.getFractionToShade(), mAmbientState.isOnKeyguard());
|
||||
}
|
||||
|
||||
@@ -2642,15 +2649,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
return mScrolledToTopOnFirstDown
|
||||
&& !mExpandedInThisMotion
|
||||
&& (initialVelocity > mMinimumVelocity
|
||||
|| (topOverScroll > mMinTopOverScrollToEscape && initialVelocity > 0));
|
||||
|| (topOverScroll > mMinTopOverScrollToEscape && initialVelocity > 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the top padding of the notifications, taking {@link #getIntrinsicPadding()} into
|
||||
* account.
|
||||
*
|
||||
* @param qsHeight the top padding imposed by the quick settings panel
|
||||
* @param animate whether to animate the change
|
||||
* @param qsHeight the top padding imposed by the quick settings panel
|
||||
* @param animate whether to animate the change
|
||||
*/
|
||||
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
|
||||
public void updateTopPadding(float qsHeight, boolean animate) {
|
||||
@@ -2724,21 +2731,34 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||
public void setChildTransferInProgress(boolean childTransferInProgress) {
|
||||
Assert.isMainThread();
|
||||
mChildTransferInProgress = childTransferInProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the remove notification listener
|
||||
* @param listener callback for notification removed
|
||||
*/
|
||||
public void setOnNotificationRemovedListener(OnNotificationRemovedListener listener) {
|
||||
mOnNotificationRemovedListener = listener;
|
||||
}
|
||||
|
||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||
@Override
|
||||
public void onViewRemoved(View child) {
|
||||
super.onViewRemoved(child);
|
||||
// we only call our internal methods if this is actually a removal and not just a
|
||||
// notification which becomes a child notification
|
||||
ExpandableView expandableView = (ExpandableView) child;
|
||||
if (!mChildTransferInProgress) {
|
||||
onViewRemovedInternal((ExpandableView) child, this);
|
||||
onViewRemovedInternal(expandableView, this);
|
||||
}
|
||||
if (mOnNotificationRemovedListener != null) {
|
||||
mOnNotificationRemovedListener.onNotificationRemoved(
|
||||
expandableView,
|
||||
mChildTransferInProgress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2998,8 +3018,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
mAnimateNextSectionBoundsChange = false;
|
||||
}
|
||||
mAmbientState.setLastVisibleBackgroundChild(lastChild);
|
||||
// TODO: Refactor SectionManager and put the RoundnessManager there.
|
||||
mController.getNotificationRoundnessManager().updateRoundedChildren(mSections);
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
// TODO: Refactor SectionManager and put the RoundnessManager there.
|
||||
mController.getNotificationRoundnessManager().updateRoundedChildren(mSections);
|
||||
}
|
||||
mAnimateBottomOnLayout = false;
|
||||
invalidate();
|
||||
}
|
||||
@@ -3206,7 +3228,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
// Only animate if we still have pinned heads up, otherwise we just have the
|
||||
// regular collapse animation of the lock screen
|
||||
|| (mKeyguardBypassEnabled && onKeyguard()
|
||||
&& mInHeadsUpPinnedMode);
|
||||
&& mInHeadsUpPinnedMode);
|
||||
if (performDisappearAnimation && !isHeadsUp) {
|
||||
type = row.wasJustClicked()
|
||||
? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
|
||||
@@ -3351,7 +3373,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
AnimationEvent animEvent = duration == null
|
||||
? new AnimationEvent(child, AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION)
|
||||
: new AnimationEvent(
|
||||
child, AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION, duration);
|
||||
child, AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION, duration);
|
||||
mAnimationEvents.add(animEvent);
|
||||
}
|
||||
mChildrenChangingPositions.clear();
|
||||
@@ -3442,7 +3464,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
|
||||
@ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
|
||||
protected StackScrollAlgorithm createStackScrollAlgorithm(Context context) {
|
||||
return new StackScrollAlgorithm(context, this);
|
||||
StackScrollAlgorithm stackScrollAlgorithm = new StackScrollAlgorithm(context, this);
|
||||
stackScrollAlgorithm.useRoundnessSourceTypes(mUseRoundnessSourceTypes);
|
||||
return stackScrollAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3772,7 +3796,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
}
|
||||
|
||||
private void logEmptySpaceClick(MotionEvent ev, boolean isTouchBelowLastNotification,
|
||||
int statusBarState, boolean touchIsClick) {
|
||||
int statusBarState, boolean touchIsClick) {
|
||||
if (mLogger == null) {
|
||||
return;
|
||||
}
|
||||
@@ -3957,7 +3981,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
mOnEmptySpaceClickListener = listener;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
@ShadeViewRefactor(RefactorComponent.INPUT)
|
||||
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
|
||||
@@ -4728,7 +4754,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
return touchY > mTopPadding + mStackTranslation;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||
public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
|
||||
@@ -5353,7 +5381,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
return canChildBeCleared(row) && matchesSelection(row, selection);
|
||||
}
|
||||
|
||||
/** Register a {@link View.OnClickListener} to be invoked when the Manage button is clicked. */
|
||||
/**
|
||||
* Register a {@link View.OnClickListener} to be invoked when the Manage button is clicked.
|
||||
*/
|
||||
public void setManageButtonClickListener(@Nullable OnClickListener listener) {
|
||||
mManageButtonClickListener = listener;
|
||||
if (mFooterView != null) {
|
||||
@@ -5418,6 +5448,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
/**
|
||||
* Set how far the wake up is when waking up from pulsing. This is a height and will adjust the
|
||||
* notification positions accordingly.
|
||||
*
|
||||
* @param height the new wake up height
|
||||
* @return the overflow how much the height is further than he lowest notification
|
||||
*/
|
||||
@@ -5649,7 +5680,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
* Set rounded rect clipping bounds on this view.
|
||||
*/
|
||||
public void setRoundedClippingBounds(int left, int top, int right, int bottom, int topRadius,
|
||||
int bottomRadius) {
|
||||
int bottomRadius) {
|
||||
if (mRoundedRectClippingLeft == left && mRoundedRectClippingRight == right
|
||||
&& mRoundedRectClippingBottom == bottom && mRoundedRectClippingTop == top
|
||||
&& mBgCornerRadii[0] == topRadius && mBgCornerRadii[5] == bottomRadius) {
|
||||
@@ -5710,7 +5741,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
mLaunchingNotification = launching;
|
||||
mLaunchingNotificationNeedsToBeClipped = mLaunchAnimationParams != null
|
||||
&& (mLaunchAnimationParams.getStartRoundedTopClipping() > 0
|
||||
|| mLaunchAnimationParams.getParentStartRoundedTopClipping() > 0);
|
||||
|| mLaunchAnimationParams.getParentStartRoundedTopClipping() > 0);
|
||||
if (!mLaunchingNotificationNeedsToBeClipped || !mLaunchingNotification) {
|
||||
mLaunchedNotificationClipPath.reset();
|
||||
}
|
||||
@@ -5748,7 +5779,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
mLaunchAnimationParams.getProgress(0,
|
||||
NotificationLaunchAnimatorController.ANIMATION_DURATION_TOP_ROUNDING));
|
||||
int top = (int) Math.min(MathUtils.lerp(mRoundedRectClippingTop,
|
||||
mLaunchAnimationParams.getTop(), expandProgress),
|
||||
mLaunchAnimationParams.getTop(), expandProgress),
|
||||
mRoundedRectClippingTop);
|
||||
float topRadius = mLaunchAnimationParams.getTopCornerRadius();
|
||||
float bottomRadius = mLaunchAnimationParams.getBottomCornerRadius();
|
||||
@@ -5872,25 +5903,25 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||
public interface OnOverscrollTopChangedListener {
|
||||
|
||||
/**
|
||||
* Notifies a listener that the overscroll has changed.
|
||||
*
|
||||
* @param amount the amount of overscroll, in pixels
|
||||
* @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an
|
||||
* unrubberbanded motion to directly expand overscroll view (e.g
|
||||
* expand
|
||||
* QS)
|
||||
*/
|
||||
void onOverscrollTopChanged(float amount, boolean isRubberbanded);
|
||||
/**
|
||||
* Notifies a listener that the overscroll has changed.
|
||||
*
|
||||
* @param amount the amount of overscroll, in pixels
|
||||
* @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an
|
||||
* unrubberbanded motion to directly expand overscroll view (e.g
|
||||
* expand
|
||||
* QS)
|
||||
*/
|
||||
void onOverscrollTopChanged(float amount, boolean isRubberbanded);
|
||||
|
||||
/**
|
||||
* Notify a listener that the scroller wants to escape from the scrolling motion and
|
||||
* start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS)
|
||||
*
|
||||
* @param velocity The velocity that the Scroller had when over flinging
|
||||
* @param open Should the fling open or close the overscroll view.
|
||||
*/
|
||||
void flingTopOverscroll(float velocity, boolean open);
|
||||
/**
|
||||
* Notify a listener that the scroller wants to escape from the scrolling motion and
|
||||
* start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS)
|
||||
*
|
||||
* @param velocity The velocity that the Scroller had when over flinging
|
||||
* @param open Should the fling open or close the overscroll view.
|
||||
*/
|
||||
void flingTopOverscroll(float velocity, boolean open);
|
||||
}
|
||||
|
||||
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
|
||||
@@ -6252,7 +6283,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
}
|
||||
};
|
||||
|
||||
public HeadsUpTouchHelper.Callback getHeadsUpCallback() { return mHeadsUpCallback; }
|
||||
public HeadsUpTouchHelper.Callback getHeadsUpCallback() {
|
||||
return mHeadsUpCallback;
|
||||
}
|
||||
|
||||
void onGroupExpandChanged(ExpandableNotificationRow changedRow, boolean expanded) {
|
||||
boolean animated = mAnimationsEnabled && (mIsExpanded || changedRow.isPinned());
|
||||
@@ -6357,15 +6390,25 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
return mLastSentExpandedHeight;
|
||||
}
|
||||
|
||||
/** Enum for selecting some or all notification rows (does not included non-notif views). */
|
||||
/**
|
||||
* Enum for selecting some or all notification rows (does not included non-notif views).
|
||||
*/
|
||||
@Retention(SOURCE)
|
||||
@IntDef({ROWS_ALL, ROWS_HIGH_PRIORITY, ROWS_GENTLE})
|
||||
@interface SelectedRows {}
|
||||
/** All rows representing notifs. */
|
||||
@interface SelectedRows {
|
||||
}
|
||||
|
||||
/**
|
||||
* All rows representing notifs.
|
||||
*/
|
||||
public static final int ROWS_ALL = 0;
|
||||
/** Only rows where entry.isHighPriority() is true. */
|
||||
/**
|
||||
* Only rows where entry.isHighPriority() is true.
|
||||
*/
|
||||
public static final int ROWS_HIGH_PRIORITY = 1;
|
||||
/** Only rows where entry.isHighPriority() is false. */
|
||||
/**
|
||||
* Only rows where entry.isHighPriority() is false.
|
||||
*/
|
||||
public static final int ROWS_GENTLE = 2;
|
||||
|
||||
interface ClearAllListener {
|
||||
@@ -6380,4 +6423,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
void onAnimationEnd(
|
||||
List<ExpandableNotificationRow> viewsToRemove, @SelectedRows int selectedRows);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface OnNotificationRemovedListener {
|
||||
/**
|
||||
*
|
||||
* @param child
|
||||
* @param isTransferInProgress
|
||||
*/
|
||||
void onNotificationRemoved(ExpandableView child, boolean isTransferInProgress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,10 +182,12 @@ public class NotificationStackScrollLayoutController {
|
||||
private NotificationStackScrollLayout mView;
|
||||
private boolean mFadeNotificationsOnDismiss;
|
||||
private NotificationSwipeHelper mSwipeHelper;
|
||||
@Nullable private Boolean mHistoryEnabled;
|
||||
@Nullable
|
||||
private Boolean mHistoryEnabled;
|
||||
private int mBarState;
|
||||
private HeadsUpAppearanceController mHeadsUpAppearanceController;
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
private final boolean mUseRoundnessSourceTypes;
|
||||
private final NotificationTargetsHelper mNotificationTargetsHelper;
|
||||
|
||||
private View mLongPressedView;
|
||||
@@ -391,7 +393,7 @@ public class NotificationStackScrollLayoutController {
|
||||
if (item != null) {
|
||||
Point origin = provider.getRevealAnimationOrigin();
|
||||
mNotificationGutsManager.openGuts(row, origin.x, origin.y, item);
|
||||
} else {
|
||||
} else {
|
||||
Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no "
|
||||
+ "menu item in menuItemtoExposeOnSnap. Skipping.");
|
||||
}
|
||||
@@ -420,7 +422,7 @@ public class NotificationStackScrollLayoutController {
|
||||
|
||||
@Override
|
||||
public void onSnooze(StatusBarNotification sbn,
|
||||
NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
|
||||
NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
|
||||
mCentralSurfaces.setNotificationSnoozed(sbn, snoozeOption);
|
||||
}
|
||||
|
||||
@@ -544,7 +546,7 @@ public class NotificationStackScrollLayoutController {
|
||||
|
||||
@Override
|
||||
public boolean updateSwipeProgress(View animView, boolean dismissable,
|
||||
float swipeProgress) {
|
||||
float swipeProgress) {
|
||||
// Returning true prevents alpha fading.
|
||||
return !mFadeNotificationsOnDismiss;
|
||||
}
|
||||
@@ -584,16 +586,22 @@ public class NotificationStackScrollLayoutController {
|
||||
|
||||
@Override
|
||||
public void onHeadsUpPinned(NotificationEntry entry) {
|
||||
mNotificationRoundnessManager.updateView(entry.getRow(), false /* animate */);
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
mNotificationRoundnessManager.updateView(
|
||||
entry.getRow(),
|
||||
/* animate = */ false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeadsUpUnPinned(NotificationEntry entry) {
|
||||
ExpandableNotificationRow row = entry.getRow();
|
||||
// update the roundedness posted, because we might be animating away the
|
||||
// headsup soon, so no need to set the roundedness to 0 and then back to 1.
|
||||
row.post(() -> mNotificationRoundnessManager.updateView(row,
|
||||
true /* animate */));
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
ExpandableNotificationRow row = entry.getRow();
|
||||
// update the roundedness posted, because we might be animating away the
|
||||
// headsup soon, so no need to set the roundedness to 0 and then back to 1.
|
||||
row.post(() -> mNotificationRoundnessManager.updateView(row,
|
||||
true /* animate */));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -603,8 +611,10 @@ public class NotificationStackScrollLayoutController {
|
||||
mView.setNumHeadsUp(numEntries);
|
||||
mView.setTopHeadsUpEntry(topEntry);
|
||||
generateHeadsUpAnimation(entry, isHeadsUp);
|
||||
ExpandableNotificationRow row = entry.getRow();
|
||||
mNotificationRoundnessManager.updateView(row, true /* animate */);
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
ExpandableNotificationRow row = entry.getRow();
|
||||
mNotificationRoundnessManager.updateView(row, true /* animate */);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -697,6 +707,7 @@ public class NotificationStackScrollLayoutController {
|
||||
mSeenNotificationsProvider = seenNotificationsProvider;
|
||||
mShadeController = shadeController;
|
||||
mFeatureFlags = featureFlags;
|
||||
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
|
||||
mNotificationTargetsHelper = notificationTargetsHelper;
|
||||
updateResources();
|
||||
}
|
||||
@@ -763,8 +774,10 @@ public class NotificationStackScrollLayoutController {
|
||||
mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
|
||||
|
||||
mFadeNotificationsOnDismiss = mFeatureFlags.isEnabled(Flags.NOTIFICATION_DISMISSAL_FADE);
|
||||
mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
|
||||
mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
|
||||
mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
|
||||
}
|
||||
|
||||
mVisibilityLocationProviderDelegator.setDelegate(this::isInVisibleLocation);
|
||||
|
||||
@@ -997,9 +1010,11 @@ public class NotificationStackScrollLayoutController {
|
||||
Log.wtf(TAG, "isHistoryEnabled failed to initialize its value");
|
||||
return false;
|
||||
}
|
||||
mHistoryEnabled = historyEnabled =
|
||||
Settings.Secure.getIntForUser(mView.getContext().getContentResolver(),
|
||||
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
|
||||
mHistoryEnabled = historyEnabled = Settings.Secure.getIntForUser(
|
||||
mView.getContext().getContentResolver(),
|
||||
Settings.Secure.NOTIFICATION_HISTORY_ENABLED,
|
||||
0,
|
||||
UserHandle.USER_CURRENT) == 1;
|
||||
}
|
||||
return historyEnabled;
|
||||
}
|
||||
@@ -1029,7 +1044,7 @@ public class NotificationStackScrollLayoutController {
|
||||
}
|
||||
|
||||
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
|
||||
boolean cancelAnimators) {
|
||||
boolean cancelAnimators) {
|
||||
mView.setOverScrollAmount(amount, onTop, animate, cancelAnimators);
|
||||
}
|
||||
|
||||
@@ -1207,7 +1222,7 @@ public class NotificationStackScrollLayoutController {
|
||||
|
||||
/**
|
||||
* Update whether we should show the empty shade view ("no notifications" in the shade).
|
||||
*
|
||||
* <p>
|
||||
* When in split mode, notifications are always visible regardless of the state of the
|
||||
* QuickSettings panel. That being the case, empty view is always shown if the other conditions
|
||||
* are true.
|
||||
@@ -1233,7 +1248,7 @@ public class NotificationStackScrollLayoutController {
|
||||
|
||||
/**
|
||||
* @return true if {@link StatusBarStateController} is in transition to the KEYGUARD
|
||||
* and false otherwise.
|
||||
* and false otherwise.
|
||||
*/
|
||||
private boolean isInTransitionToKeyguard() {
|
||||
final int currentState = mStatusBarStateController.getState();
|
||||
@@ -1265,7 +1280,9 @@ public class NotificationStackScrollLayoutController {
|
||||
mView.setExpandedHeight(expandedHeight);
|
||||
}
|
||||
|
||||
/** Sets the QS header. Used to check if a touch is within its bounds. */
|
||||
/**
|
||||
* Sets the QS header. Used to check if a touch is within its bounds.
|
||||
*/
|
||||
public void setQsHeader(ViewGroup view) {
|
||||
mView.setQsHeader(view);
|
||||
}
|
||||
@@ -1328,7 +1345,7 @@ public class NotificationStackScrollLayoutController {
|
||||
public RemoteInputController.Delegate createDelegate() {
|
||||
return new RemoteInputController.Delegate() {
|
||||
public void setRemoteInputActive(NotificationEntry entry,
|
||||
boolean remoteInputActive) {
|
||||
boolean remoteInputActive) {
|
||||
mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
|
||||
entry.notifyHeightChanged(true /* needsAnimation */);
|
||||
updateFooter();
|
||||
@@ -1459,7 +1476,7 @@ public class NotificationStackScrollLayoutController {
|
||||
}
|
||||
|
||||
private void onAnimationEnd(List<ExpandableNotificationRow> viewsToRemove,
|
||||
@SelectedRows int selectedRows) {
|
||||
@SelectedRows int selectedRows) {
|
||||
if (selectedRows == ROWS_ALL) {
|
||||
mNotifCollection.dismissAllNotifications(
|
||||
mLockscreenUserManager.getCurrentUserId());
|
||||
@@ -1502,8 +1519,8 @@ public class NotificationStackScrollLayoutController {
|
||||
|
||||
/**
|
||||
* @return the inset during the full shade transition, that needs to be added to the position
|
||||
* of the quick settings edge. This is relevant for media, that is transitioning
|
||||
* from the keyguard host to the quick settings one.
|
||||
* of the quick settings edge. This is relevant for media, that is transitioning
|
||||
* from the keyguard host to the quick settings one.
|
||||
*/
|
||||
public int getFullShadeTransitionInset() {
|
||||
MediaContainerView view = mKeyguardMediaController.getSinglePaneContainer();
|
||||
@@ -1517,10 +1534,10 @@ public class NotificationStackScrollLayoutController {
|
||||
/**
|
||||
* @param fraction The fraction of lockscreen to shade transition.
|
||||
* 0f for all other states.
|
||||
*
|
||||
* Once the lockscreen to shade transition completes and the shade is 100% open,
|
||||
* LockscreenShadeTransitionController resets amount and fraction to 0, where they remain
|
||||
* until the next lockscreen-to-shade transition.
|
||||
* <p>
|
||||
* Once the lockscreen to shade transition completes and the shade is 100% open,
|
||||
* LockscreenShadeTransitionController resets amount and fraction to 0, where
|
||||
* they remain until the next lockscreen-to-shade transition.
|
||||
*/
|
||||
public void setTransitionToFullShadeAmount(float fraction) {
|
||||
mView.setFractionToShade(fraction);
|
||||
@@ -1533,7 +1550,9 @@ public class NotificationStackScrollLayoutController {
|
||||
mView.setExtraTopInsetForFullShadeTransition(overScrollAmount);
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void setWillExpand(boolean willExpand) {
|
||||
mView.setWillExpand(willExpand);
|
||||
}
|
||||
@@ -1549,7 +1568,7 @@ public class NotificationStackScrollLayoutController {
|
||||
* Set rounded rect clipping bounds on this view.
|
||||
*/
|
||||
public void setRoundedClippingBounds(int left, int top, int right, int bottom, int topRadius,
|
||||
int bottomRadius) {
|
||||
int bottomRadius) {
|
||||
mView.setRoundedClippingBounds(left, top, right, bottom, topRadius, bottomRadius);
|
||||
}
|
||||
|
||||
@@ -1568,6 +1587,15 @@ public class NotificationStackScrollLayoutController {
|
||||
return mNotificationTargetsHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the remove notification listener
|
||||
* @param listener callback for notification removed
|
||||
*/
|
||||
public void setOnNotificationRemovedListener(
|
||||
NotificationStackScrollLayout.OnNotificationRemovedListener listener) {
|
||||
mView.setOnNotificationRemovedListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum for UiEvent logged from this class
|
||||
*/
|
||||
@@ -1578,10 +1606,13 @@ public class NotificationStackScrollLayoutController {
|
||||
@UiEvent(doc = "User dismissed all silent notifications from notification panel.")
|
||||
DISMISS_SILENT_NOTIFICATIONS_PANEL(314);
|
||||
private final int mId;
|
||||
|
||||
NotificationPanelEvent(int id) {
|
||||
mId = id;
|
||||
}
|
||||
@Override public int getId() {
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
@@ -1722,8 +1753,12 @@ public class NotificationStackScrollLayoutController {
|
||||
@Override
|
||||
public void bindRow(ExpandableNotificationRow row) {
|
||||
row.setHeadsUpAnimatingAwayListener(animatingAway -> {
|
||||
mNotificationRoundnessManager.updateView(row, false);
|
||||
mHeadsUpAppearanceController.updateHeader(row.getEntry());
|
||||
if (!mUseRoundnessSourceTypes) {
|
||||
mNotificationRoundnessManager.updateView(row, false);
|
||||
}
|
||||
NotificationEntry entry = row.getEntry();
|
||||
mHeadsUpAppearanceController.updateHeader(entry);
|
||||
mHeadsUpAppearanceController.updateHeadsUpAndPulsingRoundness(entry);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.android.systemui.statusbar.notification.stack;
|
||||
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_ROW_SWIPE;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
@@ -34,9 +35,11 @@ import com.android.internal.jank.InteractionJankMonitor;
|
||||
import com.android.systemui.SwipeHelper;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
|
||||
import com.android.systemui.statusbar.notification.SourceType;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
||||
|
||||
@@ -49,6 +52,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|
||||
@VisibleForTesting
|
||||
protected static final long COVER_MENU_DELAY = 4000;
|
||||
private static final String TAG = "NotificationSwipeHelper";
|
||||
private static final SourceType SWIPE_DISMISS = SourceType.from("SwipeDismiss");
|
||||
private final Runnable mFalsingCheck;
|
||||
private View mTranslatingParentView;
|
||||
private View mMenuExposedView;
|
||||
@@ -64,13 +68,21 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|
||||
private WeakReference<NotificationMenuRowPlugin> mCurrMenuRowRef;
|
||||
private boolean mIsExpanded;
|
||||
private boolean mPulsing;
|
||||
private final NotificationRoundnessManager mNotificationRoundnessManager;
|
||||
private final boolean mUseRoundnessSourceTypes;
|
||||
|
||||
NotificationSwipeHelper(
|
||||
Resources resources, ViewConfiguration viewConfiguration,
|
||||
FalsingManager falsingManager, FeatureFlags featureFlags,
|
||||
int swipeDirection, NotificationCallback callback,
|
||||
NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
|
||||
Resources resources,
|
||||
ViewConfiguration viewConfiguration,
|
||||
FalsingManager falsingManager,
|
||||
FeatureFlags featureFlags,
|
||||
int swipeDirection,
|
||||
NotificationCallback callback,
|
||||
NotificationMenuRowPlugin.OnMenuEventListener menuListener,
|
||||
NotificationRoundnessManager notificationRoundnessManager) {
|
||||
super(swipeDirection, callback, resources, viewConfiguration, falsingManager, featureFlags);
|
||||
mNotificationRoundnessManager = notificationRoundnessManager;
|
||||
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
|
||||
mMenuListener = menuListener;
|
||||
mCallback = callback;
|
||||
mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */);
|
||||
@@ -304,6 +316,33 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|
||||
handleMenuCoveredOrDismissed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareDismissAnimation(View view, Animator anim) {
|
||||
super.prepareDismissAnimation(view, anim);
|
||||
|
||||
if (mUseRoundnessSourceTypes
|
||||
&& view instanceof ExpandableNotificationRow
|
||||
&& mNotificationRoundnessManager.isClearAllInProgress()) {
|
||||
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
row.requestRoundness(/* top = */ 1f, /* bottom = */ 1f, SWIPE_DISMISS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
row.requestRoundnessReset(SWIPE_DISMISS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
row.requestRoundnessReset(SWIPE_DISMISS);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void superDismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
|
||||
super.dismissChild(view, velocity, useAccelerateInterpolator);
|
||||
@@ -521,14 +560,17 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|
||||
private int mSwipeDirection;
|
||||
private NotificationCallback mNotificationCallback;
|
||||
private NotificationMenuRowPlugin.OnMenuEventListener mOnMenuEventListener;
|
||||
private NotificationRoundnessManager mNotificationRoundnessManager;
|
||||
|
||||
@Inject
|
||||
Builder(@Main Resources resources, ViewConfiguration viewConfiguration,
|
||||
FalsingManager falsingManager, FeatureFlags featureFlags) {
|
||||
FalsingManager falsingManager, FeatureFlags featureFlags,
|
||||
NotificationRoundnessManager notificationRoundnessManager) {
|
||||
mResources = resources;
|
||||
mViewConfiguration = viewConfiguration;
|
||||
mFalsingManager = falsingManager;
|
||||
mFeatureFlags = featureFlags;
|
||||
mNotificationRoundnessManager = notificationRoundnessManager;
|
||||
}
|
||||
|
||||
Builder setSwipeDirection(int swipeDirection) {
|
||||
@@ -549,7 +591,8 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
|
||||
|
||||
NotificationSwipeHelper build() {
|
||||
return new NotificationSwipeHelper(mResources, mViewConfiguration, mFalsingManager,
|
||||
mFeatureFlags, mSwipeDirection, mNotificationCallback, mOnMenuEventListener);
|
||||
mFeatureFlags, mSwipeDirection, mNotificationCallback, mOnMenuEventListener,
|
||||
mNotificationRoundnessManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,7 @@ class NotificationTargetsHelper
|
||||
constructor(
|
||||
featureFlags: FeatureFlags,
|
||||
) {
|
||||
private val isNotificationGroupCornerEnabled =
|
||||
featureFlags.isEnabled(Flags.NOTIFICATION_GROUP_CORNER)
|
||||
private val useRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)
|
||||
|
||||
/**
|
||||
* This method looks for views that can be rounded (and implement [Roundable]) during a
|
||||
@@ -48,7 +47,7 @@ constructor(
|
||||
if (notificationParent != null && childrenContainer != null) {
|
||||
// We are inside a notification group
|
||||
|
||||
if (!isNotificationGroupCornerEnabled) {
|
||||
if (!useRoundnessSourceTypes) {
|
||||
return RoundableTargets(null, null, null)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.animation.ShadeInterpolation;
|
||||
import com.android.systemui.statusbar.EmptyShadeView;
|
||||
import com.android.systemui.statusbar.NotificationShelf;
|
||||
import com.android.systemui.statusbar.notification.LegacySourceType;
|
||||
import com.android.systemui.statusbar.notification.SourceType;
|
||||
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
@@ -51,6 +52,7 @@ public class StackScrollAlgorithm {
|
||||
|
||||
private static final String TAG = "StackScrollAlgorithm";
|
||||
private static final Boolean DEBUG = false;
|
||||
private static final SourceType STACK_SCROLL_ALGO = SourceType.from("StackScrollAlgorithm");
|
||||
|
||||
private final ViewGroup mHostView;
|
||||
private float mPaddingBetweenElements;
|
||||
@@ -70,6 +72,7 @@ public class StackScrollAlgorithm {
|
||||
private float mQuickQsOffsetHeight;
|
||||
private float mSmallCornerRadius;
|
||||
private float mLargeCornerRadius;
|
||||
private boolean mUseRoundnessSourceTypes;
|
||||
|
||||
public StackScrollAlgorithm(
|
||||
Context context,
|
||||
@@ -129,7 +132,7 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
|
||||
private void updateAlphaState(StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState) {
|
||||
AmbientState ambientState) {
|
||||
for (ExpandableView view : algorithmState.visibleChildren) {
|
||||
final ViewState viewState = view.getViewState();
|
||||
|
||||
@@ -229,7 +232,7 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
|
||||
private void getNotificationChildrenStates(StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState) {
|
||||
AmbientState ambientState) {
|
||||
int childCount = algorithmState.visibleChildren.size();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
ExpandableView v = algorithmState.visibleChildren.get(i);
|
||||
@@ -241,7 +244,7 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
|
||||
private void updateSpeedBumpState(StackScrollAlgorithmState algorithmState,
|
||||
int speedBumpIndex) {
|
||||
int speedBumpIndex) {
|
||||
int childCount = algorithmState.visibleChildren.size();
|
||||
int belowSpeedBump = speedBumpIndex;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
@@ -268,7 +271,7 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
|
||||
private void updateClipping(StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState) {
|
||||
AmbientState ambientState) {
|
||||
float drawStart = ambientState.isOnKeyguard() ? 0
|
||||
: ambientState.getStackY() - ambientState.getScrollY();
|
||||
float clipStart = 0;
|
||||
@@ -314,7 +317,7 @@ public class StackScrollAlgorithm {
|
||||
* Updates the dimmed, activated and hiding sensitive states of the children.
|
||||
*/
|
||||
private void updateDimmedActivatedHideSensitive(AmbientState ambientState,
|
||||
StackScrollAlgorithmState algorithmState) {
|
||||
StackScrollAlgorithmState algorithmState) {
|
||||
boolean dimmed = ambientState.isDimmed();
|
||||
boolean hideSensitive = ambientState.isHideSensitive();
|
||||
View activatedChild = ambientState.getActivatedChild();
|
||||
@@ -408,7 +411,7 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
|
||||
private int updateNotGoneIndex(StackScrollAlgorithmState state, int notGoneIndex,
|
||||
ExpandableView v) {
|
||||
ExpandableView v) {
|
||||
ExpandableViewState viewState = v.getViewState();
|
||||
viewState.notGoneIndex = notGoneIndex;
|
||||
state.visibleChildren.add(v);
|
||||
@@ -434,7 +437,7 @@ public class StackScrollAlgorithm {
|
||||
* @param ambientState The current ambient state
|
||||
*/
|
||||
protected void updatePositionsForState(StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState) {
|
||||
AmbientState ambientState) {
|
||||
if (!ambientState.isOnKeyguard()
|
||||
|| (ambientState.isBypassEnabled() && ambientState.isPulseExpanding())) {
|
||||
algorithmState.mCurrentYPosition += mNotificationScrimPadding;
|
||||
@@ -448,7 +451,7 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
|
||||
private void setLocation(ExpandableViewState expandableViewState, float currentYPosition,
|
||||
int i) {
|
||||
int i) {
|
||||
expandableViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
|
||||
if (currentYPosition <= 0) {
|
||||
expandableViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
|
||||
@@ -496,9 +499,13 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void maybeUpdateHeadsUpIsVisible(ExpandableViewState viewState, boolean isShadeExpanded,
|
||||
boolean mustStayOnScreen, boolean topVisible, float viewEnd, float hunMax) {
|
||||
|
||||
void maybeUpdateHeadsUpIsVisible(
|
||||
ExpandableViewState viewState,
|
||||
boolean isShadeExpanded,
|
||||
boolean mustStayOnScreen,
|
||||
boolean topVisible,
|
||||
float viewEnd,
|
||||
float hunMax) {
|
||||
if (isShadeExpanded && mustStayOnScreen && topVisible) {
|
||||
viewState.headsUpIsVisible = viewEnd < hunMax;
|
||||
}
|
||||
@@ -676,7 +683,7 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
|
||||
private void updatePulsingStates(StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState) {
|
||||
AmbientState ambientState) {
|
||||
int childCount = algorithmState.visibleChildren.size();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View child = algorithmState.visibleChildren.get(i);
|
||||
@@ -693,7 +700,7 @@ public class StackScrollAlgorithm {
|
||||
}
|
||||
|
||||
private void updateHeadsUpStates(StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState) {
|
||||
AmbientState ambientState) {
|
||||
int childCount = algorithmState.visibleChildren.size();
|
||||
|
||||
// Move the tracked heads up into position during the appear animation, by interpolating
|
||||
@@ -777,7 +784,7 @@ public class StackScrollAlgorithm {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void clampHunToTop(float quickQsOffsetHeight, float stackTranslation, float collapsedHeight,
|
||||
ExpandableViewState viewState) {
|
||||
ExpandableViewState viewState) {
|
||||
|
||||
final float newTranslation = Math.max(quickQsOffsetHeight + stackTranslation,
|
||||
viewState.getYTranslation());
|
||||
@@ -792,7 +799,7 @@ public class StackScrollAlgorithm {
|
||||
// Pin HUN to bottom of expanded QS
|
||||
// while the rest of notifications are scrolled offscreen.
|
||||
private void clampHunToMaxTranslation(AmbientState ambientState, ExpandableNotificationRow row,
|
||||
ExpandableViewState childState) {
|
||||
ExpandableViewState childState) {
|
||||
float maxHeadsUpTranslation = ambientState.getMaxHeadsUpTranslation();
|
||||
final float maxShelfPosition = ambientState.getInnerHeight() + ambientState.getTopPadding()
|
||||
+ ambientState.getStackTranslation();
|
||||
@@ -807,14 +814,19 @@ public class StackScrollAlgorithm {
|
||||
// Animate pinned HUN bottom corners to and from original roundness.
|
||||
final float originalCornerRadius =
|
||||
row.isLastInSection() ? 1f : (mSmallCornerRadius / mLargeCornerRadius);
|
||||
final float roundness = computeCornerRoundnessForPinnedHun(mHostView.getHeight(),
|
||||
final float bottomValue = computeCornerRoundnessForPinnedHun(mHostView.getHeight(),
|
||||
ambientState.getStackY(), getMaxAllowedChildHeight(row), originalCornerRadius);
|
||||
row.requestBottomRoundness(roundness, /* animate = */ false, SourceType.OnScroll);
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
row.requestBottomRoundness(bottomValue, STACK_SCROLL_ALGO);
|
||||
row.addOnDetachResetRoundness(STACK_SCROLL_ALGO);
|
||||
} else {
|
||||
row.requestBottomRoundness(bottomValue, LegacySourceType.OnScroll);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
float computeCornerRoundnessForPinnedHun(float hostViewHeight, float stackY,
|
||||
float viewMaxHeight, float originalCornerRadius) {
|
||||
float viewMaxHeight, float originalCornerRadius) {
|
||||
|
||||
// Compute y where corner roundness should be in its original unpinned state.
|
||||
// We use view max height because the pinned collapsed HUN expands to max height
|
||||
@@ -844,7 +856,7 @@ public class StackScrollAlgorithm {
|
||||
* @param ambientState The ambient state of the algorithm
|
||||
*/
|
||||
private void updateZValuesForState(StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState) {
|
||||
AmbientState ambientState) {
|
||||
int childCount = algorithmState.visibleChildren.size();
|
||||
float childrenOnTop = 0.0f;
|
||||
|
||||
@@ -876,9 +888,9 @@ public class StackScrollAlgorithm {
|
||||
* previous HUNs whose Z positions are greater than 0.
|
||||
*/
|
||||
protected float updateChildZValue(int i, float childrenOnTop,
|
||||
StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState,
|
||||
boolean isTopHun) {
|
||||
StackScrollAlgorithmState algorithmState,
|
||||
AmbientState ambientState,
|
||||
boolean isTopHun) {
|
||||
ExpandableView child = algorithmState.visibleChildren.get(i);
|
||||
ExpandableViewState childViewState = child.getViewState();
|
||||
float baseZ = ambientState.getBaseZHeight();
|
||||
@@ -950,6 +962,14 @@ public class StackScrollAlgorithm {
|
||||
this.mIsExpanded = isExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the support for rounded corner based on the SourceType
|
||||
* @param enabled true if is supported
|
||||
*/
|
||||
public void useRoundnessSourceTypes(boolean enabled) {
|
||||
mUseRoundnessSourceTypes = enabled;
|
||||
}
|
||||
|
||||
public static class StackScrollAlgorithmState {
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,11 +19,14 @@ package com.android.systemui.statusbar.phone;
|
||||
import static com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentModule.OPERATOR_NAME_FRAME_VIEW;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.util.MathUtils;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.widget.ViewClippingUtil;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.plugins.DarkIconDispatcher;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shade.NotificationPanelViewController;
|
||||
@@ -32,8 +35,10 @@ import com.android.systemui.statusbar.CrossFadeHelper;
|
||||
import com.android.systemui.statusbar.HeadsUpStatusBarView;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
||||
import com.android.systemui.statusbar.notification.SourceType;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
|
||||
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope;
|
||||
import com.android.systemui.statusbar.policy.Clock;
|
||||
@@ -51,6 +56,7 @@ import javax.inject.Named;
|
||||
|
||||
/**
|
||||
* Controls the appearance of heads up notifications in the icon area and the header itself.
|
||||
* It also controls the roundness of the heads up notifications and the pulsing notifications.
|
||||
*/
|
||||
@StatusBarFragmentScope
|
||||
public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBarView>
|
||||
@@ -59,12 +65,17 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
NotificationWakeUpCoordinator.WakeUpListener {
|
||||
public static final int CONTENT_FADE_DURATION = 110;
|
||||
public static final int CONTENT_FADE_DELAY = 100;
|
||||
|
||||
private static final SourceType HEADS_UP = SourceType.from("HeadsUp");
|
||||
private static final SourceType PULSING = SourceType.from("Pulsing");
|
||||
private final NotificationIconAreaController mNotificationIconAreaController;
|
||||
private final HeadsUpManagerPhone mHeadsUpManager;
|
||||
private final NotificationStackScrollLayoutController mStackScrollerController;
|
||||
|
||||
private final DarkIconDispatcher mDarkIconDispatcher;
|
||||
private final NotificationPanelViewController mNotificationPanelViewController;
|
||||
private final NotificationRoundnessManager mNotificationRoundnessManager;
|
||||
private final boolean mUseRoundnessSourceTypes;
|
||||
private final Consumer<ExpandableNotificationRow>
|
||||
mSetTrackingHeadsUp = this::setTrackingHeadsUp;
|
||||
private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
|
||||
@@ -105,11 +116,15 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
CommandQueue commandQueue,
|
||||
NotificationStackScrollLayoutController stackScrollerController,
|
||||
NotificationPanelViewController notificationPanelViewController,
|
||||
NotificationRoundnessManager notificationRoundnessManager,
|
||||
FeatureFlags featureFlags,
|
||||
HeadsUpStatusBarView headsUpStatusBarView,
|
||||
Clock clockView,
|
||||
@Named(OPERATOR_NAME_FRAME_VIEW) Optional<View> operatorNameViewOptional) {
|
||||
super(headsUpStatusBarView);
|
||||
mNotificationIconAreaController = notificationIconAreaController;
|
||||
mNotificationRoundnessManager = notificationRoundnessManager;
|
||||
mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
|
||||
mHeadsUpManager = headsUpManager;
|
||||
|
||||
// We may be mid-HUN-expansion when this controller is re-created (for example, if the user
|
||||
@@ -179,6 +194,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
public void onHeadsUpPinned(NotificationEntry entry) {
|
||||
updateTopEntry();
|
||||
updateHeader(entry);
|
||||
updateHeadsUpAndPulsingRoundness(entry);
|
||||
}
|
||||
|
||||
private void updateTopEntry() {
|
||||
@@ -316,6 +332,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
public void onHeadsUpUnPinned(NotificationEntry entry) {
|
||||
updateTopEntry();
|
||||
updateHeader(entry);
|
||||
updateHeadsUpAndPulsingRoundness(entry);
|
||||
}
|
||||
|
||||
public void setAppearFraction(float expandedHeight, float appearFraction) {
|
||||
@@ -346,7 +363,9 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
ExpandableNotificationRow previousTracked = mTrackedChild;
|
||||
mTrackedChild = trackedChild;
|
||||
if (previousTracked != null) {
|
||||
updateHeader(previousTracked.getEntry());
|
||||
NotificationEntry entry = previousTracked.getEntry();
|
||||
updateHeader(entry);
|
||||
updateHeadsUpAndPulsingRoundness(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,6 +376,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
private void updateHeadsUpHeaders() {
|
||||
mHeadsUpManager.getAllEntries().forEach(entry -> {
|
||||
updateHeader(entry);
|
||||
updateHeadsUpAndPulsingRoundness(entry);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -370,6 +390,31 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
|
||||
row.setHeaderVisibleAmount(headerVisibleAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the HeadsUp and the Pulsing roundness based on current state
|
||||
* @param entry target notification
|
||||
*/
|
||||
public void updateHeadsUpAndPulsingRoundness(NotificationEntry entry) {
|
||||
if (mUseRoundnessSourceTypes) {
|
||||
ExpandableNotificationRow row = entry.getRow();
|
||||
boolean isTrackedChild = row == mTrackedChild;
|
||||
if (row.isPinned() || row.isHeadsUpAnimatingAway() || isTrackedChild) {
|
||||
float roundness = MathUtils.saturate(1f - mAppearFraction);
|
||||
row.requestRoundness(roundness, roundness, HEADS_UP);
|
||||
} else {
|
||||
row.requestRoundnessReset(HEADS_UP);
|
||||
}
|
||||
if (mNotificationRoundnessManager.shouldRoundNotificationPulsing()) {
|
||||
if (row.showingPulsing()) {
|
||||
row.requestRoundness(/* top = */ 1f, /* bottom = */ 1f, PULSING);
|
||||
} else {
|
||||
row.requestRoundnessReset(PULSING);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
|
||||
mView.onDarkChanged(areas, darkIntensity, tint);
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.android.systemui.statusbar.notification
|
||||
|
||||
import android.view.View
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.mockito.Mockito.atLeastOnce
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
|
||||
@SmallTest
|
||||
@RunWith(JUnit4::class)
|
||||
class RoundableTest : SysuiTestCase() {
|
||||
val targetView: View = mock()
|
||||
val roundable = FakeRoundable(targetView)
|
||||
|
||||
@Test
|
||||
fun defaultConfig_shouldNotHaveRoundedCorner() {
|
||||
// the expected default value for the roundness is top = 0f, bottom = 0f
|
||||
assertEquals(0f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0f, roundable.roundableState.bottomRoundness)
|
||||
assertEquals(false, roundable.hasRoundedCorner())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun applyRoundnessAndInvalidate_should_invalidate_targetView() {
|
||||
roundable.applyRoundnessAndInvalidate()
|
||||
|
||||
verify(targetView, times(1)).invalidate()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun requestTopRoundness_update_and_invalidate_targetView() {
|
||||
roundable.requestTopRoundness(value = 1f, sourceType = SOURCE1)
|
||||
|
||||
assertEquals(1f, roundable.roundableState.topRoundness)
|
||||
verify(targetView, times(1)).invalidate()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun requestBottomRoundness_update_and_invalidate_targetView() {
|
||||
roundable.requestBottomRoundness(value = 1f, sourceType = SOURCE1)
|
||||
|
||||
assertEquals(1f, roundable.roundableState.bottomRoundness)
|
||||
verify(targetView, times(1)).invalidate()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun requestRoundness_update_and_invalidate_targetView() {
|
||||
roundable.requestRoundness(top = 1f, bottom = 1f, sourceType = SOURCE1)
|
||||
|
||||
assertEquals(1f, roundable.roundableState.topRoundness)
|
||||
assertEquals(1f, roundable.roundableState.bottomRoundness)
|
||||
verify(targetView, atLeastOnce()).invalidate()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun requestRoundnessReset_update_and_invalidate_targetView() {
|
||||
roundable.requestRoundness(1f, 1f, SOURCE1)
|
||||
assertEquals(1f, roundable.roundableState.topRoundness)
|
||||
assertEquals(1f, roundable.roundableState.bottomRoundness)
|
||||
|
||||
roundable.requestRoundnessReset(sourceType = SOURCE1)
|
||||
|
||||
assertEquals(0f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0f, roundable.roundableState.bottomRoundness)
|
||||
verify(targetView, atLeastOnce()).invalidate()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hasRoundedCorner_return_true_ifRoundnessIsGreaterThenZero() {
|
||||
roundable.requestRoundness(top = 1f, bottom = 1f, sourceType = SOURCE1)
|
||||
assertEquals(true, roundable.hasRoundedCorner())
|
||||
|
||||
roundable.requestRoundness(top = 1f, bottom = 0f, sourceType = SOURCE1)
|
||||
assertEquals(true, roundable.hasRoundedCorner())
|
||||
|
||||
roundable.requestRoundness(top = 0f, bottom = 1f, sourceType = SOURCE1)
|
||||
assertEquals(true, roundable.hasRoundedCorner())
|
||||
|
||||
roundable.requestRoundness(top = 0f, bottom = 0f, sourceType = SOURCE1)
|
||||
assertEquals(false, roundable.hasRoundedCorner())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun roundness_take_maxValue_onMultipleSources_first_lower() {
|
||||
roundable.requestRoundness(0.1f, 0.1f, SOURCE1)
|
||||
assertEquals(0.1f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.1f, roundable.roundableState.bottomRoundness)
|
||||
|
||||
roundable.requestRoundness(0.2f, 0.2f, SOURCE2)
|
||||
// SOURCE1 has 0.1f - SOURCE2 has 0.2f
|
||||
assertEquals(0.2f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.2f, roundable.roundableState.bottomRoundness)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun roundness_take_maxValue_onMultipleSources_first_higher() {
|
||||
roundable.requestRoundness(0.5f, 0.5f, SOURCE1)
|
||||
assertEquals(0.5f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.5f, roundable.roundableState.bottomRoundness)
|
||||
|
||||
roundable.requestRoundness(0.1f, 0.1f, SOURCE2)
|
||||
// SOURCE1 has 0.5f - SOURCE2 has 0.1f
|
||||
assertEquals(0.5f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.5f, roundable.roundableState.bottomRoundness)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun roundness_take_maxValue_onMultipleSources_first_higher_second_step() {
|
||||
roundable.requestRoundness(0.1f, 0.1f, SOURCE1)
|
||||
assertEquals(0.1f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.1f, roundable.roundableState.bottomRoundness)
|
||||
|
||||
roundable.requestRoundness(0.2f, 0.2f, SOURCE2)
|
||||
// SOURCE1 has 0.1f - SOURCE2 has 0.2f
|
||||
assertEquals(0.2f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.2f, roundable.roundableState.bottomRoundness)
|
||||
|
||||
roundable.requestRoundness(0.3f, 0.3f, SOURCE1)
|
||||
// SOURCE1 has 0.3f - SOURCE2 has 0.2f
|
||||
assertEquals(0.3f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.3f, roundable.roundableState.bottomRoundness)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun roundness_take_maxValue_onMultipleSources_first_lower_second_step() {
|
||||
roundable.requestRoundness(0.5f, 0.5f, SOURCE1)
|
||||
assertEquals(0.5f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.5f, roundable.roundableState.bottomRoundness)
|
||||
|
||||
roundable.requestRoundness(0.2f, 0.2f, SOURCE2)
|
||||
// SOURCE1 has 0.5f - SOURCE2 has 0.2f
|
||||
assertEquals(0.5f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.5f, roundable.roundableState.bottomRoundness)
|
||||
|
||||
roundable.requestRoundness(0.1f, 0.1f, SOURCE1)
|
||||
// SOURCE1 has 0.1f - SOURCE2 has 0.2f
|
||||
assertEquals(0.2f, roundable.roundableState.topRoundness)
|
||||
assertEquals(0.2f, roundable.roundableState.bottomRoundness)
|
||||
}
|
||||
|
||||
class FakeRoundable(
|
||||
targetView: View,
|
||||
radius: Float = MAX_RADIUS,
|
||||
) : Roundable {
|
||||
override val roundableState =
|
||||
RoundableState(
|
||||
targetView = targetView,
|
||||
roundable = this,
|
||||
maxRadius = radius,
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAX_RADIUS = 10f
|
||||
private val SOURCE1 = SourceType.from("Source1")
|
||||
private val SOURCE2 = SourceType.from("Source2")
|
||||
}
|
||||
}
|
||||
@@ -215,8 +215,7 @@ public class NotificationTestHelper {
|
||||
SourceType sourceType
|
||||
) throws Exception {
|
||||
ExpandableNotificationRow row = createRow();
|
||||
row.requestTopRoundness(topRoundness, false, sourceType);
|
||||
row.requestBottomRoundness(bottomRoundness, /*animate = */ false, sourceType);
|
||||
row.requestRoundness(topRoundness, bottomRoundness, sourceType, /*animate = */ false);
|
||||
assertEquals(topRoundness, row.getTopRoundness(), /* delta = */ 0f);
|
||||
assertEquals(bottomRoundness, row.getBottomRoundness(), /* delta = */ 0f);
|
||||
return row;
|
||||
|
||||
@@ -25,7 +25,7 @@ import android.view.View;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.notification.SourceType;
|
||||
import com.android.systemui.statusbar.notification.LegacySourceType;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
|
||||
|
||||
@@ -158,7 +158,7 @@ public class NotificationChildrenContainerTest extends SysuiTestCase {
|
||||
ExpandableNotificationRow row = mNotificationTestHelper.createRowWithRoundness(
|
||||
/* topRoundness = */ 1f,
|
||||
/* bottomRoundness = */ 1f,
|
||||
/* sourceType = */ SourceType.OnScroll);
|
||||
/* sourceType = */ LegacySourceType.OnScroll);
|
||||
|
||||
mChildrenContainer.addNotification(row, 0);
|
||||
|
||||
@@ -171,11 +171,11 @@ public class NotificationChildrenContainerTest extends SysuiTestCase {
|
||||
ExpandableNotificationRow row1 = mNotificationTestHelper.createRowWithRoundness(
|
||||
/* topRoundness = */ 1f,
|
||||
/* bottomRoundness = */ 1f,
|
||||
/* sourceType = */ SourceType.DefaultValue);
|
||||
/* sourceType = */ LegacySourceType.DefaultValue);
|
||||
ExpandableNotificationRow row2 = mNotificationTestHelper.createRowWithRoundness(
|
||||
/* topRoundness = */ 1f,
|
||||
/* bottomRoundness = */ 1f,
|
||||
/* sourceType = */ SourceType.OnDismissAnimation);
|
||||
/* sourceType = */ LegacySourceType.OnDismissAnimation);
|
||||
|
||||
mChildrenContainer.addNotification(row1, 0);
|
||||
mChildrenContainer.addNotification(row2, 0);
|
||||
|
||||
@@ -35,6 +35,7 @@ import androidx.test.filters.SmallTest;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.logging.NotificationRoundnessLogger;
|
||||
@@ -73,7 +74,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
||||
mRoundnessManager = new NotificationRoundnessManager(
|
||||
new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext),
|
||||
mLogger,
|
||||
mock(DumpManager.class));
|
||||
mock(DumpManager.class),
|
||||
mock(FeatureFlags.class));
|
||||
allowTestableLooperAsMainThread();
|
||||
NotificationTestHelper testHelper = new NotificationTestHelper(
|
||||
mContext,
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.view.ViewGroup;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.media.controls.ui.KeyguardMediaController;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
@@ -59,10 +60,12 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
|
||||
@Mock private KeyguardMediaController mKeyguardMediaController;
|
||||
@Mock private NotificationSectionsFeatureManager mSectionsFeatureManager;
|
||||
@Mock private MediaContainerController mMediaContainerController;
|
||||
@Mock private NotificationRoundnessManager mNotificationRoundnessManager;
|
||||
@Mock private SectionHeaderController mIncomingHeaderController;
|
||||
@Mock private SectionHeaderController mPeopleHeaderController;
|
||||
@Mock private SectionHeaderController mAlertingHeaderController;
|
||||
@Mock private SectionHeaderController mSilentHeaderController;
|
||||
@Mock private FeatureFlags mFeatureFlag;
|
||||
|
||||
private NotificationSectionsManager mSectionsManager;
|
||||
|
||||
@@ -89,10 +92,12 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
|
||||
mKeyguardMediaController,
|
||||
mSectionsFeatureManager,
|
||||
mMediaContainerController,
|
||||
mNotificationRoundnessManager,
|
||||
mIncomingHeaderController,
|
||||
mPeopleHeaderController,
|
||||
mAlertingHeaderController,
|
||||
mSilentHeaderController
|
||||
mSilentHeaderController,
|
||||
mFeatureFlag
|
||||
);
|
||||
// Required in order for the header inflation to work properly
|
||||
when(mNssl.generateLayoutParams(any(AttributeSet.class)))
|
||||
|
||||
@@ -9,7 +9,7 @@ import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.animation.ShadeInterpolation
|
||||
import com.android.systemui.statusbar.NotificationShelf
|
||||
import com.android.systemui.statusbar.StatusBarIconView
|
||||
import com.android.systemui.statusbar.notification.SourceType
|
||||
import com.android.systemui.statusbar.notification.LegacySourceType
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableView
|
||||
import com.android.systemui.statusbar.notification.row.NotificationTestHelper
|
||||
@@ -314,9 +314,9 @@ class NotificationShelfTest : SysuiTestCase() {
|
||||
val row: ExpandableNotificationRow = notificationTestHelper.createRowWithRoundness(
|
||||
/* topRoundness = */ 1f,
|
||||
/* bottomRoundness = */ 1f,
|
||||
/* sourceType = */ SourceType.OnScroll)
|
||||
/* sourceType = */ LegacySourceType.OnScroll)
|
||||
|
||||
NotificationShelf.resetOnScrollRoundness(row)
|
||||
NotificationShelf.resetLegacyOnScrollRoundness(row)
|
||||
|
||||
assertEquals(0f, row.topRoundness)
|
||||
assertEquals(0f, row.bottomRoundness)
|
||||
@@ -327,14 +327,14 @@ class NotificationShelfTest : SysuiTestCase() {
|
||||
val row1: ExpandableNotificationRow = notificationTestHelper.createRowWithRoundness(
|
||||
/* topRoundness = */ 1f,
|
||||
/* bottomRoundness = */ 1f,
|
||||
/* sourceType = */ SourceType.DefaultValue)
|
||||
/* sourceType = */ LegacySourceType.DefaultValue)
|
||||
val row2: ExpandableNotificationRow = notificationTestHelper.createRowWithRoundness(
|
||||
/* topRoundness = */ 1f,
|
||||
/* bottomRoundness = */ 1f,
|
||||
/* sourceType = */ SourceType.OnDismissAnimation)
|
||||
/* sourceType = */ LegacySourceType.OnDismissAnimation)
|
||||
|
||||
NotificationShelf.resetOnScrollRoundness(row1)
|
||||
NotificationShelf.resetOnScrollRoundness(row2)
|
||||
NotificationShelf.resetLegacyOnScrollRoundness(row1)
|
||||
NotificationShelf.resetLegacyOnScrollRoundness(row2)
|
||||
|
||||
assertEquals(1f, row1.topRoundness)
|
||||
assertEquals(1f, row1.bottomRoundness)
|
||||
|
||||
@@ -74,6 +74,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
|
||||
private NotificationSwipeHelper mSwipeHelper;
|
||||
private NotificationSwipeHelper.NotificationCallback mCallback;
|
||||
private NotificationMenuRowPlugin.OnMenuEventListener mListener;
|
||||
private NotificationRoundnessManager mNotificationRoundnessManager;
|
||||
private View mView;
|
||||
private MotionEvent mEvent;
|
||||
private NotificationMenuRowPlugin mMenuRow;
|
||||
@@ -92,10 +93,17 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
|
||||
public void setUp() throws Exception {
|
||||
mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
|
||||
mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
|
||||
mNotificationRoundnessManager = mock(NotificationRoundnessManager.class);
|
||||
mFeatureFlags = mock(FeatureFlags.class);
|
||||
mSwipeHelper = spy(new NotificationSwipeHelper(
|
||||
mContext.getResources(), ViewConfiguration.get(mContext),
|
||||
new FalsingManagerFake(), mFeatureFlags, SwipeHelper.X, mCallback, mListener));
|
||||
mContext.getResources(),
|
||||
ViewConfiguration.get(mContext),
|
||||
new FalsingManagerFake(),
|
||||
mFeatureFlags,
|
||||
SwipeHelper.X,
|
||||
mCallback,
|
||||
mListener,
|
||||
mNotificationRoundnessManager));
|
||||
mView = mock(View.class);
|
||||
mEvent = mock(MotionEvent.class);
|
||||
mMenuRow = mock(NotificationMenuRowPlugin.class);
|
||||
|
||||
@@ -35,7 +35,7 @@ class NotificationTargetsHelperTest : SysuiTestCase() {
|
||||
) =
|
||||
NotificationTargetsHelper(
|
||||
FakeFeatureFlags().apply {
|
||||
set(Flags.NOTIFICATION_GROUP_CORNER, notificationGroupCorner)
|
||||
set(Flags.USE_ROUNDNESS_SOURCETYPES, notificationGroupCorner)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.widget.TextView;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.plugins.DarkIconDispatcher;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shade.NotificationPanelViewController;
|
||||
@@ -40,6 +41,7 @@ import com.android.systemui.statusbar.HeadsUpStatusBarView;
|
||||
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
|
||||
import com.android.systemui.statusbar.policy.Clock;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
@@ -71,6 +73,8 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
|
||||
private NotificationWakeUpCoordinator mWakeUpCoordinator;
|
||||
private KeyguardStateController mKeyguardStateController;
|
||||
private CommandQueue mCommandQueue;
|
||||
private NotificationRoundnessManager mNotificationRoundnessManager;
|
||||
private FeatureFlags mFeatureFlag;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -89,6 +93,8 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
|
||||
mWakeUpCoordinator = mock(NotificationWakeUpCoordinator.class);
|
||||
mKeyguardStateController = mock(KeyguardStateController.class);
|
||||
mCommandQueue = mock(CommandQueue.class);
|
||||
mNotificationRoundnessManager = mock(NotificationRoundnessManager.class);
|
||||
mFeatureFlag = mock(FeatureFlags.class);
|
||||
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
|
||||
mock(NotificationIconAreaController.class),
|
||||
mHeadsUpManager,
|
||||
@@ -100,6 +106,8 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
|
||||
mCommandQueue,
|
||||
mStackScrollerController,
|
||||
mPanelView,
|
||||
mNotificationRoundnessManager,
|
||||
mFeatureFlag,
|
||||
mHeadsUpStatusBarView,
|
||||
new Clock(mContext, null),
|
||||
Optional.of(mOperatorNameView));
|
||||
@@ -182,6 +190,8 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
|
||||
mCommandQueue,
|
||||
mStackScrollerController,
|
||||
mPanelView,
|
||||
mNotificationRoundnessManager,
|
||||
mFeatureFlag,
|
||||
mHeadsUpStatusBarView,
|
||||
new Clock(mContext, null),
|
||||
Optional.empty());
|
||||
|
||||
Reference in New Issue
Block a user