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
This commit is contained in:
Selim Cinek
2016-11-29 15:42:34 -08:00
parent 5ea19572af
commit 65d418ec89
6 changed files with 85 additions and 60 deletions

View File

@@ -103,7 +103,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private boolean mDimmed;
private boolean mDark;
private int mBgTint = 0;
private int mBgTint = NO_COLOR;
private float mBgAlpha = 1f;
/**
@@ -481,8 +481,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
* 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 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
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);
}
/**

View File

@@ -1685,13 +1685,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@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);
}
}

View File

@@ -37,8 +37,6 @@ import com.android.systemui.statusbar.stack.ExpandableViewState;
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 @@ public class NotificationShelf extends ActivatableNotificationView {
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 @@ public class NotificationShelf extends ActivatableNotificationView {
* 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 @@ public class NotificationShelf extends ActivatableNotificationView {
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 @@ public class NotificationShelf extends ActivatableNotificationView {
}
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 @@ public class NotificationShelf extends ActivatableNotificationView {
}
mShelfIcons.calculateIconTranslations();
mShelfIcons.applyIconStates();
setVisibility(mAmbientState.isShadeExpanded()
? VISIBLE
: INVISIBLE);
boolean hideBackground = numViewsInShelf < 1.0f;
setHideBackground(hideBackground || backgroundForceHidden);
if (mNotGoneIndex == -1) {
@@ -441,9 +438,11 @@ public class NotificationShelf extends ActivatableNotificationView {
}
private void setHideBackground(boolean hideBackground) {
mHideBackground = hideBackground;
updateBackground();
updateOutline();
if (mHideBackground != hideBackground) {
mHideBackground = hideBackground;
updateBackground();
updateOutline();
}
}
public boolean hidesBackground() {

View File

@@ -455,6 +455,7 @@ public class StatusBarIconView extends AnimatedImageView {
}
public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable) {
boolean runnableAdded = false;
if (visibleState != mVisibleState) {
mVisibleState = visibleState;
if (animate) {
@@ -467,20 +468,22 @@ public class StatusBarIconView extends AnimatedImageView {
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 @@ public class StatusBarIconView extends AnimatedImageView {
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) {

View File

@@ -31,7 +31,7 @@ import com.android.systemui.statusbar.stack.AnimationFilter;
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 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
}.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 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
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;
}
/**

View File

@@ -715,7 +715,6 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
}
setStackTranslation(translationY);
requestChildrenUpdate();
}
private void setRequestedClipBounds(Rect clipRect) {