diff options
2 files changed, 46 insertions, 5 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt index 92391e7c76f0..e1e30e1d74f0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt @@ -17,7 +17,9 @@ package com.android.systemui.statusbar.notification.icon.ui.viewbinder import android.graphics.Color import android.graphics.Rect +import android.util.Log import android.view.View +import android.view.ViewGroup import android.widget.FrameLayout import androidx.annotation.ColorInt import androidx.collection.ArrayMap @@ -220,7 +222,7 @@ object NotificationIconContainerViewBinder { notifyBindingFailures: (Collection<String>) -> Unit, viewStore: IconViewStore, bindIcon: suspend (iconKey: String, view: StatusBarIconView) -> Unit = { _, _ -> }, - ): Unit = coroutineScope { + ) { val iconSizeFlow: Flow<Int> = configuration.getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size_sp, @@ -235,6 +237,21 @@ object NotificationIconContainerViewBinder { -> FrameLayout.LayoutParams(iconSize + 2 * iconHPadding, statusBarHeight) } + try { + bindIcons(view, layoutParams, notifyBindingFailures, viewStore, bindIcon) + } finally { + // Detach everything so that child SBIVs don't hold onto a reference to the container. + view.detachAllIcons() + } + } + + private suspend fun Flow<NotificationIconsViewData>.bindIcons( + view: NotificationIconContainer, + layoutParams: Flow<FrameLayout.LayoutParams>, + notifyBindingFailures: (Collection<String>) -> Unit, + viewStore: IconViewStore, + bindIcon: suspend (iconKey: String, view: StatusBarIconView) -> Unit, + ): Unit = coroutineScope { val failedBindings = mutableSetOf<String>() val boundViewsByNotifKey = ArrayMap<String, Pair<StatusBarIconView, Job>>() var prevIcons = NotificationIconsViewData() @@ -266,9 +283,17 @@ object NotificationIconContainerViewBinder { continue } failedBindings.remove(notifKey) - // The view might still be transiently added if it was just removed and added - // again - view.removeTransientView(sbiv) + (sbiv.parent as? ViewGroup)?.run { + if (this !== view) { + Log.wtf(TAG, "StatusBarIconView($notifKey) has an unexpected parent") + } + // If the container was re-inflated and re-bound, then SBIVs might still be + // attached to the prior view. + removeView(sbiv) + // The view might still be transiently added if it was just removed and + // added again. + removeTransientView(sbiv) + } view.addView(sbiv, idx) boundViewsByNotifKey.remove(notifKey)?.second?.cancel() boundViewsByNotifKey[notifKey] = @@ -351,7 +376,8 @@ object NotificationIconContainerViewBinder { fun iconView(key: String): StatusBarIconView? } - @ColorInt private val DEFAULT_AOD_ICON_COLOR = Color.WHITE + @ColorInt private const val DEFAULT_AOD_ICON_COLOR = Color.WHITE + private const val TAG = "NotifIconContainerViewBinder" } /** [IconViewStore] for the [com.android.systemui.statusbar.NotificationShelf] */ 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 00e78a49ba19..0dabafbdecb0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -400,6 +400,21 @@ public class NotificationIconContainer extends ViewGroup { } } + /** + * Removes all child {@link StatusBarIconView} instances from this container, immediately and + * without animation. This should be called when tearing down this container so that external + * icon views are not holding onto a reference thru {@link View#getParent()}. + */ + public void detachAllIcons() { + boolean animsWereEnabled = mAnimationsEnabled; + boolean wasChangingPositions = mChangingViewPositions; + mAnimationsEnabled = false; + mChangingViewPositions = true; + removeAllViews(); + mChangingViewPositions = wasChangingPositions; + mAnimationsEnabled = animsWereEnabled; + } + public boolean areIconsOverflowing() { return mIsShowingOverflowDot; } |