Improved the performance of the notification shelf
The shelf had a few inefficiencies that were adding up
when calculating the positions.
Test: runtest systemui-jank -c android.platform.systemui.tests.jank.SystemUiJankTests -m testNotificationListPull_manyNotifications
Bug: 32437839
Change-Id: Iac08a7c364a924f1d0c14258461383b431f0542b
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 173f160..d4b478a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -103,7 +103,7 @@
private boolean mDimmed;
private boolean mDark;
- private int mBgTint = 0;
+ private int mBgTint = NO_COLOR;
private float mBgAlpha = 1f;
/**
@@ -481,8 +481,10 @@
* Sets the tint color of the background
*/
public void setTintColor(int color, boolean animated) {
- mBgTint = color;
- updateBackgroundTint(animated);
+ if (color != mBgTint) {
+ mBgTint = color;
+ updateBackgroundTint(animated);
+ }
}
/**
@@ -541,13 +543,15 @@
}
private void setBackgroundTintColor(int color) {
- mCurrentBackgroundTint = color;
- if (color == mNormalColor) {
- // We don't need to tint a normal notification
- color = 0;
+ if (color != mCurrentBackgroundTint) {
+ mCurrentBackgroundTint = color;
+ if (color == mNormalColor) {
+ // We don't need to tint a normal notification
+ color = 0;
+ }
+ mBackgroundDimmed.setTint(color);
+ mBackgroundNormal.setTint(color);
}
- mBackgroundDimmed.setTint(color);
- mBackgroundNormal.setTint(color);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index e4654e6..996e2ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1685,13 +1685,17 @@
@Override
public void setClipBottomAmount(int clipBottomAmount) {
- super.setClipBottomAmount(clipBottomAmount);
- mPrivateLayout.setClipBottomAmount(clipBottomAmount);
- mPublicLayout.setClipBottomAmount(clipBottomAmount);
- if (mGuts != null) {
- mGuts.setClipBottomAmount(clipBottomAmount);
+ if (clipBottomAmount != mClipBottomAmount) {
+ super.setClipBottomAmount(clipBottomAmount);
+ mPrivateLayout.setClipBottomAmount(clipBottomAmount);
+ mPublicLayout.setClipBottomAmount(clipBottomAmount);
+ if (mGuts != null) {
+ mGuts.setClipBottomAmount(clipBottomAmount);
+ }
}
if (mChildrenContainer != null) {
+ // We have to update this even if it hasn't changed, since the children locations can
+ // have changed
mChildrenContainer.setClipBottomAmount(clipBottomAmount);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 0138ca8..80d4188 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -37,8 +37,6 @@
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackScrollState;
-import java.util.WeakHashMap;
-
/**
* A notification shelf view that is placed inside the notification scroller. It manages the
* overflow icons that don't fit into the regular list anymore.
@@ -165,6 +163,7 @@
mShelfState.notGoneIndex = Math.min(mShelfState.notGoneIndex, mNotGoneIndex);
}
mShelfState.hasItemsInStableShelf = lastViewState.inShelf;
+ mShelfState.hidden = !mAmbientState.isShadeExpanded();
} else {
mShelfState.hidden = true;
mShelfState.location = ExpandableViewState.LOCATION_GONE;
@@ -177,15 +176,15 @@
* the icons from the notification area into the shelf.
*/
public void updateAppearance() {
- WeakHashMap<View, NotificationIconContainer.IconState> iconStates =
- mShelfIcons.resetViewStates();
+ mShelfIcons.resetViewStates();
+ float shelfStart = getTranslationY();
float numViewsInShelf = 0.0f;
View lastChild = mAmbientState.getLastVisibleBackgroundChild();
mNotGoneIndex = -1;
float interpolationStart = mMaxLayoutHeight - getIntrinsicHeight() * 2;
float expandAmount = 0.0f;
- if (getTranslationY() >= interpolationStart) {
- expandAmount = (getTranslationY() - interpolationStart) / getIntrinsicHeight();
+ if (shelfStart >= interpolationStart) {
+ expandAmount = (shelfStart - interpolationStart) / getIntrinsicHeight();
expandAmount = Math.min(1.0f, expandAmount);
}
// find the first view that doesn't overlap with the shelf
@@ -199,6 +198,7 @@
int colorTwoBefore = NO_COLOR;
int previousColor = NO_COLOR;
float transitionAmount = 0.0f;
+ int baseZHeight = mAmbientState.getBaseZHeight();
while (notificationIndex < mHostLayout.getChildCount()) {
ExpandableView child = (ExpandableView) mHostLayout.getChildAt(notificationIndex);
notificationIndex++;
@@ -208,26 +208,26 @@
}
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
float notificationClipEnd;
- float shelfStart = getTranslationY();
- boolean aboveShelf = row.getTranslationZ() > mAmbientState.getBaseZHeight();
+ boolean aboveShelf = row.getTranslationZ() > baseZHeight;
boolean isLastChild = child == lastChild;
+ float rowTranslationY = row.getTranslationY();
if (isLastChild || aboveShelf || backgroundForceHidden) {
notificationClipEnd = shelfStart + getIntrinsicHeight();
} else {
notificationClipEnd = shelfStart - mPaddingBetweenElements;
- float height = notificationClipEnd - row.getTranslationY();
+ float height = notificationClipEnd - rowTranslationY;
if (!row.isBelowSpeedBump() && height <= getNotificationMergeSize()) {
// We want the gap to close when we reached the minimum size and only shrink
// before
notificationClipEnd = Math.min(shelfStart,
- row.getTranslationY() + getNotificationMergeSize());
+ rowTranslationY + getNotificationMergeSize());
}
}
updateNotificationClipHeight(row, notificationClipEnd);
float inShelfAmount = updateIconAppearance(row, expandAmount, isLastChild);
numViewsInShelf += inShelfAmount;
int ownColorUntinted = row.getBackgroundColorWithoutTint();
- if (row.getTranslationY() >= getTranslationY() && mNotGoneIndex == -1) {
+ if (rowTranslationY >= shelfStart && mNotGoneIndex == -1) {
mNotGoneIndex = notGoneIndex;
setTintColor(previousColor);
setOverrideTintColor(colorTwoBefore, transitionAmount);
@@ -250,9 +250,6 @@
}
mShelfIcons.calculateIconTranslations();
mShelfIcons.applyIconStates();
- setVisibility(mAmbientState.isShadeExpanded()
- ? VISIBLE
- : INVISIBLE);
boolean hideBackground = numViewsInShelf < 1.0f;
setHideBackground(hideBackground || backgroundForceHidden);
if (mNotGoneIndex == -1) {
@@ -441,9 +438,11 @@
}
private void setHideBackground(boolean hideBackground) {
- mHideBackground = hideBackground;
- updateBackground();
- updateOutline();
+ if (mHideBackground != hideBackground) {
+ mHideBackground = hideBackground;
+ updateBackground();
+ updateOutline();
+ }
}
public boolean hidesBackground() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 2621e4a..6650e72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -455,6 +455,7 @@
}
public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable) {
+ boolean runnableAdded = false;
if (visibleState != mVisibleState) {
mVisibleState = visibleState;
if (animate) {
@@ -467,20 +468,22 @@
targetAmount = 1.0f;
interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
}
- mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT,
- targetAmount);
- mIconAppearAnimator.setInterpolator(interpolator);
- mIconAppearAnimator.setDuration(100);
- mIconAppearAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mIconAppearAnimator = null;
- if (endRunnable != null) {
- endRunnable.run();
+ float currentAmount = getIconAppearAmount();
+ if (targetAmount != currentAmount) {
+ mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT,
+ currentAmount, targetAmount);
+ mIconAppearAnimator.setInterpolator(interpolator);
+ mIconAppearAnimator.setDuration(100);
+ mIconAppearAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIconAppearAnimator = null;
+ runRunnable(endRunnable);
}
- }
- });
- mIconAppearAnimator.start();
+ });
+ mIconAppearAnimator.start();
+ runnableAdded = true;
+ }
if (mDotAnimator != null) {
mDotAnimator.cancel();
@@ -491,22 +494,39 @@
targetAmount = 1.0f;
interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
}
- mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT,
- targetAmount);
- mDotAnimator.setInterpolator(interpolator);
- mDotAnimator.setDuration(100);
- mDotAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mDotAnimator = null;
- }
- });
- mDotAnimator.start();
+ currentAmount = getDotAppearAmount();
+ if (targetAmount != currentAmount) {
+ mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT,
+ currentAmount, targetAmount);
+ mDotAnimator.setInterpolator(interpolator);
+ mDotAnimator.setDuration(100);
+ final boolean runRunnable = !runnableAdded;
+ mDotAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDotAnimator = null;
+ if (runRunnable) {
+ runRunnable(endRunnable);
+ }
+ }
+ });
+ mDotAnimator.start();
+ runnableAdded = true;
+ }
} else {
setIconAppearAmount(visibleState == STATE_ICON ? 1.0f : 0.0f);
setDotAppearAmount(visibleState == STATE_DOT ? 1.0f : 0.0f);
}
}
+ if (!runnableAdded) {
+ runRunnable(endRunnable);
+ }
+ }
+
+ private void runRunnable(Runnable runnable) {
+ if (runnable != null) {
+ runnable.run();
+ }
}
public void setIconAppearAmount(float iconAppearAmount) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 160b233..2940584 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -31,7 +31,7 @@
import com.android.systemui.statusbar.stack.AnimationProperties;
import com.android.systemui.statusbar.stack.ViewState;
-import java.util.WeakHashMap;
+import java.util.HashMap;
/**
* A container for notification icons. It handles overflowing icons properly and positions them
@@ -80,7 +80,7 @@
}.setDuration(200).setDelay(50);
private boolean mShowAllIcons = true;
- private WeakHashMap<View, IconState> mIconStates = new WeakHashMap<>();
+ private final HashMap<View, IconState> mIconStates = new HashMap<>();
private int mDotPadding;
private int mStaticDotRadius;
private int mActualLayoutWidth = -1;
@@ -200,14 +200,13 @@
return getChildCount();
}
- public WeakHashMap<View, IconState> resetViewStates() {
+ public void resetViewStates() {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
ViewState iconState = mIconStates.get(view);
iconState.initFrom(view);
iconState.alpha = 1.0f;
}
- return mIconStates;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 10d995c..4fb982b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -715,7 +715,6 @@
requestChildrenUpdate();
}
setStackTranslation(translationY);
- requestChildrenUpdate();
}
private void setRequestedClipBounds(Rect clipRect) {