Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1182a91d authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[SB][Chips] Don't throw if we can't fetch a StatusBarIconView.

This is theoretically possible when a notification is removed because
we clear out ConnectedDisplaysStatusBarNotificationIconViewStore before
we clear out the chip. SysUI shouldn't crash in this circumstance.
Instead, we'll just show a chip with no icon (which looks bad, but
should rarely-if-ever-happen and is better than crashing).

Fixes: 397713944
Bug: 364653005
Flag: com.android.systemui.shared.status_bar_connected_displays

Verify the following with status_bar_connected_displays flag both on and
off:

Test: trigger chip with missing icon -> verify no crash
Test: trigger chip with icon, verify icon shows & responds to dark/light
theme changes
Test: Post 2 promoted ongoing notifications, then dismiss one -> verify
no crash (b/390231934 doesn't re-occur)
Test: Post 2 promoted ongoing notifications -> verify both chips show
the right icons
Test: Add & remove various chips -> verify the chips always show the
right icon, and SysUI never crashes
Test: Post promoted ongoing notification then switch small icon in
notification -> verify chip updates to correct icon

Change-Id: I2a3c718ad809c84c229ad2e2fcfa0d161d5e4822

Change-Id: Ib5ad082e039f029e0ff1ef30140d5631a7e64dd3
parent e584e114
Loading
Loading
Loading
Loading
+32 −4
Original line number Diff line number Diff line
@@ -16,8 +16,11 @@

package com.android.systemui.statusbar.chips.ui.compose

import android.annotation.IdRes
import android.content.res.ColorStateList
import android.util.Log
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
@@ -234,10 +237,35 @@ private fun StatusBarIcon(
    AndroidView(
        modifier = modifier,
        factory = { _ ->
            iconFactory.invoke()?.apply {
            // Use a wrapper frame layout so that we still return a view even if the icon is null
            val wrapperFrameLayout = FrameLayout(context)

            val icon = iconFactory.invoke()
            if (icon == null) {
                Log.e(TAG, "Missing StatusBarIconView for $notificationKey")
            } else {
                icon.apply {
                    id = CUSTOM_ICON_VIEW_ID
                    layoutParams = ViewGroup.LayoutParams(iconSizePx, iconSizePx)
            } ?: throw IllegalStateException("Missing StatusBarIconView for $notificationKey")
                }
                // If needed, remove the icon from its old parent (views can only be attached
                // to 1 parent at a time)
                (icon.parent as? ViewGroup)?.apply {
                    this.removeView(icon)
                    this.removeTransientView(icon)
                }
                wrapperFrameLayout.addView(icon)
            }

            wrapperFrameLayout
        },
        update = { frameLayout ->
            frameLayout.findViewById<StatusBarIconView>(CUSTOM_ICON_VIEW_ID)?.apply {
                this.imageTintList = colorTintList
            }
        },
        update = { iconView -> iconView.imageTintList = colorTintList },
    )
}

private const val TAG = "OngoingActivityChip"
@IdRes private val CUSTOM_ICON_VIEW_ID = R.id.ongoing_activity_chip_custom_icon