Fix status bar app name/icon overlap
This issue was caused by a missing check for if there is a
waiting entry for the given key in BaseHeadsUpManager.removeEntry
Also add more stack call tracing to HeadsUpManagerLogger to
improve debugging
Fixes: 340334234
Test: manual with test app:
send default notifs to get notif icons in status bar
tap add 3 times fast
during the initial appear animation, tap cancel all
=> see that app name is replaced by app icons
Change-Id: I5d7a59e83cf98d96297d40750ed7d8243b098709
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 4c3c7d5..8841870 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -159,7 +159,7 @@
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (shouldBeVisible()) {
- updateTopEntry();
+ updateTopEntry("onLayoutChange");
// trigger scroller to notify the latest panel translation
mStackScrollerController.requestLayout();
@@ -220,7 +220,7 @@
@Override
public void onHeadsUpPinned(NotificationEntry entry) {
- updateTopEntry();
+ updateTopEntry("onHeadsUpPinned");
updateHeader(entry);
updateHeadsUpAndPulsingRoundness(entry);
}
@@ -231,7 +231,7 @@
mPhoneStatusBarTransitions.onHeadsUpStateChanged(isHeadsUp);
}
- private void updateTopEntry() {
+ private void updateTopEntry(String reason) {
NotificationEntry newEntry = null;
if (shouldBeVisible()) {
newEntry = mHeadsUpManager.getTopEntry();
@@ -369,7 +369,7 @@
@Override
public void onHeadsUpUnPinned(NotificationEntry entry) {
- updateTopEntry();
+ updateTopEntry("onHeadsUpUnPinned");
updateHeader(entry);
updateHeadsUpAndPulsingRoundness(entry);
}
@@ -387,7 +387,7 @@
updateHeadsUpHeaders();
}
if (isExpanded() != oldIsExpanded) {
- updateTopEntry();
+ updateTopEntry("setAppearFraction");
}
}
@@ -461,11 +461,11 @@
}
public void onStateChanged() {
- updateTopEntry();
+ updateTopEntry("onStateChanged");
}
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
- updateTopEntry();
+ updateTopEntry("onFullyHiddenChanged");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 68457ea..ffc859e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -249,7 +249,7 @@
for (NotificationEntry entry : mEntriesToRemoveAfterExpand) {
if (isHeadsUpEntry(entry.getKey())) {
// Maybe the heads-up was removed already
- removeEntry(entry.getKey());
+ removeEntry(entry.getKey(), "onExpandingFinished");
}
}
}
@@ -381,7 +381,7 @@
for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
if (isHeadsUpEntry(entry.getKey())) {
// Maybe the heads-up was removed already
- removeEntry(entry.getKey());
+ removeEntry(entry.getKey(), "mOnReorderingAllowedListener");
}
}
mEntriesToRemoveWhenReorderingAllowed.clear();
@@ -572,7 +572,7 @@
} else if (mTrackingHeadsUp) {
mEntriesToRemoveAfterExpand.add(entry);
} else {
- removeEntry(entry.getKey());
+ removeEntry(entry.getKey(), "createRemoveRunnable");
}
};
}
@@ -661,7 +661,7 @@
}
}
for (String key : keysToRemove) {
- removeEntry(key);
+ removeEntry(key, "mStatusBarStateListener");
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
index 8b48bd3..2169154 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -79,7 +79,8 @@
runnable.run()
return
}
- val fn = "[$label] => AvalancheController.update [${getKey(entry)}]"
+ log { "\n "}
+ val fn = "$label => AvalancheController.update ${getKey(entry)}"
if (entry == null) {
log { "Entry is NULL, stop update." }
return
@@ -88,13 +89,13 @@
debugRunnableLabelMap[runnable] = label
}
if (isShowing(entry)) {
- log { "\n$fn => [update showing]" }
+ log { "\n$fn => update showing" }
runnable.run()
} else if (entry in nextMap) {
- log { "\n$fn => [update next]" }
+ log { "\n$fn => update next" }
nextMap[entry]?.add(runnable)
} else if (headsUpEntryShowing == null) {
- log { "\n$fn => [showNow]" }
+ log { "\n$fn => showNow" }
showNow(entry, arrayListOf(runnable))
} else {
// Clean up invalid state when entry is in list but not map and vice versa
@@ -133,20 +134,22 @@
runnable.run()
return
}
- val fn = "[$label] => AvalancheController.delete " + getKey(entry)
+ log { "\n "}
+ val fn = "$label => AvalancheController.delete " + getKey(entry)
if (entry == null) {
- log { "$fn => cannot remove NULL entry" }
+ log { "$fn => entry NULL, running runnable" }
+ runnable.run()
return
}
if (entry in nextMap) {
- log { "$fn => [remove from next]" }
+ log { "$fn => remove from next" }
if (entry in nextMap) nextMap.remove(entry)
if (entry in nextList) nextList.remove(entry)
} else if (entry in debugDropSet) {
- log { "$fn => [remove from dropset]" }
+ log { "$fn => remove from dropset" }
debugDropSet.remove(entry)
} else if (isShowing(entry)) {
- log { "$fn => [remove showing ${getKey(entry)}]" }
+ log { "$fn => remove showing ${getKey(entry)}" }
previousHunKey = getKey(headsUpEntryShowing)
// Show the next HUN before removing this one, so that we don't tell listeners
// onHeadsUpPinnedModeChanged, which causes
@@ -155,7 +158,7 @@
showNext()
runnable.run()
} else {
- log { "$fn => [removing untracked ${getKey(entry)}]" }
+ log { "$fn => removing untracked ${getKey(entry)}" }
}
logState("after $fn")
}
@@ -239,6 +242,18 @@
return keyList
}
+ fun getWaitingEntry(key: String): HeadsUpEntry? {
+ if (!NotificationThrottleHun.isEnabled) {
+ return null
+ }
+ for (headsUpEntry in nextMap.keys) {
+ if (headsUpEntry.mEntry?.key.equals(key)) {
+ return headsUpEntry
+ }
+ }
+ return null
+ }
+
private fun isShowing(entry: HeadsUpEntry): Boolean {
return headsUpEntryShowing != null && entry.mEntry?.key == headsUpEntryShowing?.mEntry?.key
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index a7fe49b..2ee98bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -195,26 +195,29 @@
*/
@Override
public boolean removeNotification(@NonNull String key, boolean releaseImmediately) {
- mLogger.logRemoveNotification(key, releaseImmediately);
+ final boolean isWaiting = mAvalancheController.isWaiting(key);
+ mLogger.logRemoveNotification(key, releaseImmediately, isWaiting);
if (mAvalancheController.isWaiting(key)) {
- removeEntry(key);
+ removeEntry(key, "removeNotification (isWaiting)");
return true;
}
HeadsUpEntry headsUpEntry = mHeadsUpEntryMap.get(key);
if (headsUpEntry == null) {
return true;
}
- if (releaseImmediately || canRemoveImmediately(key)) {
- removeEntry(key);
- } else {
- headsUpEntry.removeAsSoonAsPossible();
- return false;
+ if (releaseImmediately) {
+ removeEntry(key, "removeNotification (releaseImmediately)");
+ return true;
}
- return true;
+ if (canRemoveImmediately(key)) {
+ removeEntry(key, "removeNotification (canRemoveImmediately)");
+ return true;
+ }
+ headsUpEntry.removeAsSoonAsPossible();
+ return false;
}
-
/**
* Called when the notification state has been updated.
* @param key the key of the entry that was updated
@@ -245,7 +248,8 @@
if (shouldHeadsUpAgain) {
headsUpEntry.updateEntry(true /* updatePostTime */, "updateNotification");
if (headsUpEntry != null) {
- setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(headsUpEntry.mEntry));
+ setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(headsUpEntry.mEntry),
+ "updateNotificationInternal");
}
}
}
@@ -264,10 +268,10 @@
List<String> waitingKeysToRemove = mAvalancheController.getWaitingKeys();
for (String key : keysToRemove) {
- removeEntry(key);
+ removeEntry(key, "releaseAllImmediately (keysToRemove)");
}
for (String key : waitingKeysToRemove) {
- removeEntry(key);
+ removeEntry(key, "releaseAllImmediately (waitingKeysToRemove)");
}
}
@@ -338,8 +342,9 @@
}
protected void setEntryPinned(
- @NonNull BaseHeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned) {
- mLogger.logSetEntryPinned(headsUpEntry.mEntry, isPinned);
+ @NonNull BaseHeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned,
+ String reason) {
+ mLogger.logSetEntryPinned(headsUpEntry.mEntry, isPinned, reason);
NotificationEntry entry = headsUpEntry.mEntry;
if (!isPinned) {
headsUpEntry.mWasUnpinned = true;
@@ -376,7 +381,7 @@
entry.setHeadsUp(true);
final boolean shouldPin = shouldHeadsUpBecomePinned(entry);
- setEntryPinned(headsUpEntry, shouldPin);
+ setEntryPinned(headsUpEntry, shouldPin, "onEntryAdded");
EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 1 /* visible */);
for (OnHeadsUpChangedListener listener : mListeners) {
listener.onHeadsUpStateChanged(entry, true);
@@ -387,17 +392,24 @@
* Remove a notification from the alerting entries.
* @param key key of notification to remove
*/
- protected final void removeEntry(@NonNull String key) {
+ protected final void removeEntry(@NonNull String key, String reason) {
HeadsUpEntry headsUpEntry = mHeadsUpEntryMap.get(key);
- mLogger.logRemoveEntryRequest(key);
-
+ boolean isWaiting;
+ if (headsUpEntry == null) {
+ headsUpEntry = mAvalancheController.getWaitingEntry(key);
+ isWaiting = true;
+ } else {
+ isWaiting = false;
+ }
+ mLogger.logRemoveEntryRequest(key, reason, isWaiting);
+ HeadsUpEntry finalHeadsUpEntry = headsUpEntry;
Runnable runnable = () -> {
- mLogger.logRemoveEntry(key);
+ mLogger.logRemoveEntry(key, reason, isWaiting);
- if (headsUpEntry == null) {
+ if (finalHeadsUpEntry == null) {
return;
}
- NotificationEntry entry = headsUpEntry.mEntry;
+ NotificationEntry entry = finalHeadsUpEntry.mEntry;
// If the notification is animating, we will remove it at the end of the animation.
if (entry != null && entry.isExpandAnimationRunning()) {
@@ -405,13 +417,13 @@
}
entry.demoteStickyHun();
mHeadsUpEntryMap.remove(key);
- onEntryRemoved(headsUpEntry);
+ onEntryRemoved(finalHeadsUpEntry);
// TODO(b/328390331) move accessibility events to the view layer
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
if (NotificationsHeadsUpRefactor.isEnabled()) {
- headsUpEntry.cancelAutoRemovalCallbacks("removeEntry");
+ finalHeadsUpEntry.cancelAutoRemovalCallbacks("removeEntry");
} else {
- headsUpEntry.reset();
+ finalHeadsUpEntry.reset();
}
};
mAvalancheController.delete(headsUpEntry, runnable, "removeEntry");
@@ -424,7 +436,7 @@
protected void onEntryRemoved(HeadsUpEntry headsUpEntry) {
NotificationEntry entry = headsUpEntry.mEntry;
entry.setHeadsUp(false);
- setEntryPinned(headsUpEntry, false /* isPinned */);
+ setEntryPinned(headsUpEntry, false /* isPinned */, "onEntryRemoved");
EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 0 /* visible */);
mLogger.logNotificationActuallyRemoved(entry);
for (OnHeadsUpChangedListener listener : mListeners) {
@@ -584,7 +596,7 @@
Runnable runnable = () -> {
mLogger.logUnpinEntry(key);
- setEntryPinned(headsUpEntry, false /* isPinned */);
+ setEntryPinned(headsUpEntry, false /* isPinned */, "unpinAll");
// maybe it got un sticky
headsUpEntry.updateEntry(false /* updatePostTime */, "unpinAll");
@@ -985,7 +997,7 @@
/** Creates a runnable to remove this notification from the alerting entries. */
protected Runnable createRemoveRunnable(NotificationEntry entry) {
- return () -> removeEntry(entry.getKey());
+ return () -> removeEntry(entry.getKey(), "createRemoveRunnable");
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
index 11cbc9c..6ffb162 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
@@ -121,19 +121,23 @@
})
}
- fun logRemoveEntryRequest(key: String) {
+ fun logRemoveEntryRequest(key: String, reason: String, isWaiting: Boolean) {
buffer.log(TAG, INFO, {
str1 = logKey(key)
+ str2 = reason
+ bool1 = isWaiting
}, {
- "request: remove entry $str1"
+ "request: $str2 => remove entry $str1 isWaiting: $isWaiting"
})
}
- fun logRemoveEntry(key: String) {
+ fun logRemoveEntry(key: String, reason: String, isWaiting: Boolean) {
buffer.log(TAG, INFO, {
str1 = logKey(key)
+ str2 = reason
+ bool1 = isWaiting
}, {
- "remove entry $str1"
+ "$str2 => remove entry $str1 isWaiting: $isWaiting"
})
}
@@ -153,12 +157,13 @@
})
}
- fun logRemoveNotification(key: String, releaseImmediately: Boolean) {
+ fun logRemoveNotification(key: String, releaseImmediately: Boolean, isWaiting: Boolean) {
buffer.log(TAG, INFO, {
str1 = logKey(key)
bool1 = releaseImmediately
+ bool2 = isWaiting
}, {
- "remove notification $str1 releaseImmediately: $bool1"
+ "remove notification $str1 releaseImmediately: $bool1 isWaiting: $bool2"
})
}
@@ -208,12 +213,13 @@
})
}
- fun logSetEntryPinned(entry: NotificationEntry, isPinned: Boolean) {
+ fun logSetEntryPinned(entry: NotificationEntry, isPinned: Boolean, reason: String) {
buffer.log(TAG, VERBOSE, {
str1 = entry.logKey
bool1 = isPinned
+ str2 = reason
}, {
- "set entry pinned $str1 pinned: $bool1"
+ "$str2 => set entry pinned $str1 pinned: $bool1"
})
}