[SB][Call chip] Update call chip to use icon from notification.

This change:
1) Has notification/icon/IconManager.kt create a new icon for the call
   chip. The icon is based on Notification.smallIcon.
2) Updates OngoingCallController to pass that icon to CallChipViewModel.
3) Updates CallChipViewModel to use the icon if the flag is enabled.
4) Updates CollapsedStatusBarViewBinder to use that icon if it exists,
   and manipulates all the view paddings such that things look correct.
   This is required because Notification.smallIcons are required to
   embed their own padding, and we need to account for that.

Note that this change only works if two other flags are also enabled:
- status_bar_use_repos_for_call_chip (due to b/355288215)
- status_bar_screen_sharing_chips (due to too much eng effort required
  to re-implement all these changes in OngoingCallController#updateChip)

Bug: 354930838
Flag: com.android.systemui.status_bar_call_chip_notification_icon

Test: With new flag off, start calls from various apps -> verify chip
always shows default phone icon with good padding
Test: With new flag on, start calls and receive calls from various apps
-> verify chip icon always matches the icon shown in the call
notification small icon slot with good padding
Test: Do screen record, share, and cast -> verify chip shows the right
icons with good padding
Test: Start call then change font size, display size, wallpaper color ->
verify chip updates correctly

Test: atest OngoingCallControllerTest CallChipViewModelTest

Change-Id: I2b0b35cb87041638b5e1c0e2ac5658ca8230b2b4
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 9df739c..37581e5 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -403,6 +403,13 @@
 }
 
 flag {
+    name: "status_bar_call_chip_notification_icon"
+    namespace: "systemui"
+    description: "Use the small icon set on the notification for the status bar call chip"
+    bug: "354930838"
+}
+
+flag {
     name: "compose_bouncer"
     namespace: "systemui"
     description: "Use the new compose bouncer in SystemUI"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index eda7bb0..e5750d2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1729,10 +1729,18 @@
     <dimen name="wallet_button_vertical_padding">8dp</dimen>
 
     <!-- Ongoing activity chip -->
+    <!-- The activity chip side padding, used with the default phone icon. -->
     <dimen name="ongoing_activity_chip_side_padding">12dp</dimen>
+    <!-- The activity chip side padding, used with an icon that has embedded padding (e.g. if the icon comes from the notification's smallIcon field). If the icon has padding, the chip itself can have less padding. -->
+    <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon">6dp</dimen>
+    <!-- The icon size, used with the default phone icon. -->
     <dimen name="ongoing_activity_chip_icon_size">16dp</dimen>
-    <!-- The padding between the icon and the text. -->
+    <!-- The icon size, used with an icon that has embedded padding. (If the icon has embedded padding, we need to make the whole icon larger so the icon itself doesn't look small.) -->
+    <dimen name="ongoing_activity_chip_embedded_padding_icon_size">22dp</dimen>
+    <!-- The padding between the icon and the text. Only used if the default phone icon is used. -->
     <dimen name="ongoing_activity_chip_icon_text_padding">4dp</dimen>
+    <!-- The end padding for the timer text view. Only used if an embedded padding icon is used. -->
+    <dimen name="ongoing_activity_chip_text_end_padding_for_embedded_padding_icon">6dp</dimen>
     <dimen name="ongoing_activity_chip_corner_radius">28dp</dimen>
 
     <!-- Status bar user chip -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 212dae2..e4f900d 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -132,6 +132,7 @@
 
     <!-- Status bar -->
     <item type="id" name="status_bar_dot" />
+    <item type="id" name="ongoing_activity_chip_custom_icon" />
 
     <!-- Default display cutout on the physical top of screen -->
     <item type="id" name="display_cutout" />
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
index 64dedea..108e22b 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.common.ui.binder
 
-import android.view.View
 import android.widget.ImageView
 import com.android.systemui.common.shared.model.Icon
 
@@ -31,13 +30,4 @@
             is Icon.Resource -> view.setImageResource(icon.res)
         }
     }
-
-    fun bindNullable(icon: Icon?, view: ImageView) {
-        if (icon != null) {
-            view.visibility = View.VISIBLE
-            bind(icon, view)
-        } else {
-            view.visibility = View.GONE
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 6e4038d..59de203 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -23,7 +23,13 @@
 import com.android.server.notification.Flags.politeNotifications
 import com.android.server.notification.Flags.vibrateWhileUnlocked
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON
+import com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS
+import com.android.systemui.Flags.FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP
 import com.android.systemui.Flags.communalHub
+import com.android.systemui.Flags.statusBarCallChipNotificationIcon
+import com.android.systemui.Flags.statusBarScreenSharingChips
+import com.android.systemui.Flags.statusBarUseReposForCallChip
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
@@ -38,9 +44,9 @@
 import com.android.systemui.statusbar.notification.shared.NotificationAvalancheSuppression
 import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
 import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
+import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
 import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
-import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
 import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
 import javax.inject.Inject
 
@@ -77,6 +83,10 @@
 
         // QS Fragment using Compose dependencies
         QSComposeFragment.token dependsOn NewQsUI.token
+
+        // Status bar chip dependencies
+        statusBarCallChipNotificationIconToken dependsOn statusBarUseReposForCallChipToken
+        statusBarCallChipNotificationIconToken dependsOn statusBarScreenSharingChipsToken
     }
 
     private inline val politeNotifications
@@ -96,4 +106,17 @@
 
     private inline val communalHub
         get() = FlagToken(FLAG_COMMUNAL_HUB, communalHub())
+
+    private inline val statusBarCallChipNotificationIconToken
+        get() =
+            FlagToken(
+                FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON,
+                statusBarCallChipNotificationIcon()
+            )
+
+    private inline val statusBarScreenSharingChipsToken
+        get() = FlagToken(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, statusBarScreenSharingChips())
+
+    private inline val statusBarUseReposForCallChipToken
+        get() = FlagToken(FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP, statusBarUseReposForCallChip())
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index 59fd0ca..18ea0b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -18,6 +18,7 @@
 
 import android.view.View
 import com.android.internal.jank.InteractionJankMonitor
+import com.android.systemui.Flags
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
@@ -59,12 +60,24 @@
                 when (state) {
                     is OngoingCallModel.NoCall -> OngoingActivityChipModel.Hidden()
                     is OngoingCallModel.InCall -> {
+                        val icon =
+                            if (
+                                Flags.statusBarCallChipNotificationIcon() &&
+                                    state.notificationIconView != null
+                            ) {
+                                OngoingActivityChipModel.ChipIcon.StatusBarView(
+                                    state.notificationIconView
+                                )
+                            } else {
+                                OngoingActivityChipModel.ChipIcon.Basic(phoneIcon)
+                            }
+
                         // This block mimics OngoingCallController#updateChip.
                         if (state.startTimeMs <= 0L) {
                             // If the start time is invalid, don't show a timer and show just an
                             // icon. See b/192379214.
                             OngoingActivityChipModel.Shown.IconOnly(
-                                icon = phoneIcon,
+                                icon = icon,
                                 colors = ColorsModel.Themed,
                                 getOnClickListener(state),
                             )
@@ -73,7 +86,7 @@
                                 state.startTimeMs - systemClock.currentTimeMillis() +
                                     systemClock.elapsedRealtime()
                             OngoingActivityChipModel.Shown.Timer(
-                                icon = phoneIcon,
+                                icon = icon,
                                 colors = ColorsModel.Themed,
                                 startTimeMs = startTimeInElapsedRealtime,
                                 getOnClickListener(state),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
index d9b0504..cf4e707 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
@@ -190,12 +190,14 @@
     ): OngoingActivityChipModel.Shown {
         return OngoingActivityChipModel.Shown.Timer(
             icon =
-                Icon.Resource(
-                    CAST_TO_OTHER_DEVICE_ICON,
-                    // This string is "Casting screen"
-                    ContentDescription.Resource(
-                        R.string.cast_screen_to_other_device_chip_accessibility_label,
-                    ),
+                OngoingActivityChipModel.ChipIcon.Basic(
+                    Icon.Resource(
+                        CAST_TO_OTHER_DEVICE_ICON,
+                        // This string is "Casting screen"
+                        ContentDescription.Resource(
+                            R.string.cast_screen_to_other_device_chip_accessibility_label,
+                        ),
+                    )
                 ),
             colors = ColorsModel.Red,
             // TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.
@@ -213,10 +215,12 @@
     private fun createIconOnlyCastChip(deviceName: String?): OngoingActivityChipModel.Shown {
         return OngoingActivityChipModel.Shown.IconOnly(
             icon =
-                Icon.Resource(
-                    CAST_TO_OTHER_DEVICE_ICON,
-                    // This string is just "Casting"
-                    ContentDescription.Resource(R.string.accessibility_casting),
+                OngoingActivityChipModel.ChipIcon.Basic(
+                    Icon.Resource(
+                        CAST_TO_OTHER_DEVICE_ICON,
+                        // This string is just "Casting"
+                        ContentDescription.Resource(R.string.accessibility_casting),
+                    )
                 ),
             colors = ColorsModel.Red,
             createDialogLaunchOnClickListener(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
index fcf3de4..6ba4fef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
@@ -78,11 +78,13 @@
                     is ScreenRecordChipModel.Recording -> {
                         OngoingActivityChipModel.Shown.Timer(
                             icon =
-                                Icon.Resource(
-                                    ICON,
-                                    ContentDescription.Resource(
-                                        R.string.screenrecord_ongoing_screen_only,
-                                    ),
+                                OngoingActivityChipModel.ChipIcon.Basic(
+                                    Icon.Resource(
+                                        ICON,
+                                        ContentDescription.Resource(
+                                            R.string.screenrecord_ongoing_screen_only,
+                                        ),
+                                    )
                                 ),
                             colors = ColorsModel.Red,
                             startTimeMs = systemClock.elapsedRealtime(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
index 85973fc..7897f93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
@@ -110,9 +110,11 @@
     ): OngoingActivityChipModel.Shown {
         return OngoingActivityChipModel.Shown.Timer(
             icon =
-                Icon.Resource(
-                    SHARE_TO_APP_ICON,
-                    ContentDescription.Resource(R.string.share_to_app_chip_accessibility_label),
+                OngoingActivityChipModel.ChipIcon.Basic(
+                    Icon.Resource(
+                        SHARE_TO_APP_ICON,
+                        ContentDescription.Resource(R.string.share_to_app_chip_accessibility_label),
+                    )
                 ),
             colors = ColorsModel.Red,
             // TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
index 17cf60b..26a2f91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
@@ -17,7 +17,9 @@
 package com.android.systemui.statusbar.chips.ui.model
 
 import android.view.View
+import com.android.systemui.Flags
 import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.statusbar.StatusBarIconView
 
 /** Model representing the display of an ongoing activity as a chip in the status bar. */
 sealed class OngoingActivityChipModel {
@@ -38,7 +40,7 @@
     /** This chip should be shown with the given information. */
     abstract class Shown(
         /** The icon to show on the chip. If null, no icon will be shown. */
-        open val icon: Icon?,
+        open val icon: ChipIcon?,
         /** What colors to use for the chip. */
         open val colors: ColorsModel,
         /**
@@ -50,7 +52,7 @@
 
         /** This chip shows only an icon and nothing else. */
         data class IconOnly(
-            override val icon: Icon,
+            override val icon: ChipIcon,
             override val colors: ColorsModel,
             override val onClickListener: View.OnClickListener?,
         ) : Shown(icon, colors, onClickListener) {
@@ -59,7 +61,7 @@
 
         /** The chip shows a timer, counting up from [startTimeMs]. */
         data class Timer(
-            override val icon: Icon,
+            override val icon: ChipIcon,
             override val colors: ColorsModel,
             /**
              * The time this event started, used to show the timer.
@@ -88,4 +90,23 @@
             override val logName = "Shown.Countdown"
         }
     }
+
+    /** Represents an icon to show on the chip. */
+    sealed interface ChipIcon {
+        /**
+         * The icon is a custom icon, which is set on [impl]. The icon was likely created by an
+         * external app.
+         */
+        data class StatusBarView(val impl: StatusBarIconView) : ChipIcon {
+            init {
+                check(Flags.statusBarCallChipNotificationIcon()) {
+                    "OngoingActivityChipModel.ChipIcon.StatusBarView created even though " +
+                        "Flags.statusBarCallChipNotificationIcon is not enabled"
+                }
+            }
+        }
+
+        /** The icon is a basic resource or drawable icon that System UI created internally. */
+        data class Basic(val impl: Icon) : ChipIcon
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
index 5d2d56a..1008451 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
@@ -25,6 +25,8 @@
 import android.service.notification.StatusBarNotification
 import android.util.ArrayMap
 import com.android.app.tracing.traceSection
+import com.android.systemui.Flags
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.ListEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -128,8 +130,14 @@
         return result
     }
 
-    private fun NotificationEntry.toModel(): ActiveNotificationModel =
-        existingModels.createOrReuse(
+    private fun NotificationEntry.toModel(): ActiveNotificationModel {
+        val statusBarChipIcon =
+            if (Flags.statusBarCallChipNotificationIcon()) {
+                icons.statusBarChipIcon
+            } else {
+                null
+            }
+        return existingModels.createOrReuse(
             key = key,
             groupKey = sbn.groupKey,
             whenTime = sbn.notification.`when`,
@@ -142,6 +150,7 @@
             aodIcon = icons.aodIcon?.sourceIcon,
             shelfIcon = icons.shelfIcon?.sourceIcon,
             statusBarIcon = icons.statusBarIcon?.sourceIcon,
+            statusBarChipIconView = statusBarChipIcon,
             uid = sbn.uid,
             packageName = sbn.packageName,
             contentIntent = sbn.notification.contentIntent,
@@ -150,6 +159,7 @@
             bucket = bucket,
             callType = sbn.toCallType(),
         )
+    }
 }
 
 private fun ActiveNotificationsStore.createOrReuse(
@@ -165,6 +175,7 @@
     aodIcon: Icon?,
     shelfIcon: Icon?,
     statusBarIcon: Icon?,
+    statusBarChipIconView: StatusBarIconView?,
     uid: Int,
     packageName: String,
     contentIntent: PendingIntent?,
@@ -187,6 +198,7 @@
             aodIcon = aodIcon,
             shelfIcon = shelfIcon,
             statusBarIcon = statusBarIcon,
+            statusBarChipIconView = statusBarChipIconView,
             uid = uid,
             instanceId = instanceId,
             isGroupSummary = isGroupSummary,
@@ -209,6 +221,7 @@
             aodIcon = aodIcon,
             shelfIcon = shelfIcon,
             statusBarIcon = statusBarIcon,
+            statusBarChipIconView = statusBarChipIconView,
             uid = uid,
             instanceId = instanceId,
             isGroupSummary = isGroupSummary,
@@ -232,6 +245,7 @@
     aodIcon: Icon?,
     shelfIcon: Icon?,
     statusBarIcon: Icon?,
+    statusBarChipIconView: StatusBarIconView?,
     uid: Int,
     packageName: String,
     contentIntent: PendingIntent?,
@@ -253,6 +267,7 @@
         aodIcon != this.aodIcon -> false
         shelfIcon != this.shelfIcon -> false
         statusBarIcon != this.statusBarIcon -> false
+        statusBarChipIconView != this.statusBarChipIconView -> false
         uid != this.uid -> false
         instanceId != this.instanceId -> false
         isGroupSummary != this.isGroupSummary -> false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
index 331d3cc..dc6ab41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
@@ -123,6 +123,13 @@
             // Construct the status bar icon view.
             val sbIcon = iconBuilder.createIconView(entry)
             sbIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE
+            val sbChipIcon: StatusBarIconView?
+            if (Flags.statusBarCallChipNotificationIcon()) {
+                sbChipIcon = iconBuilder.createIconView(entry)
+                sbChipIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE
+            } else {
+                sbChipIcon = null
+            }
 
             // Construct the shelf icon view.
             val shelfIcon = iconBuilder.createIconView(entry)
@@ -139,9 +146,19 @@
 
             try {
                 setIcon(entry, normalIconDescriptor, sbIcon)
+                if (Flags.statusBarCallChipNotificationIcon() && sbChipIcon != null) {
+                    setIcon(entry, normalIconDescriptor, sbChipIcon)
+                }
                 setIcon(entry, sensitiveIconDescriptor, shelfIcon)
                 setIcon(entry, sensitiveIconDescriptor, aodIcon)
-                entry.icons = IconPack.buildPack(sbIcon, shelfIcon, aodIcon, entry.icons)
+                entry.icons =
+                    IconPack.buildPack(
+                        sbIcon,
+                        sbChipIcon,
+                        shelfIcon,
+                        aodIcon,
+                        entry.icons,
+                    )
             } catch (e: InflationException) {
                 entry.icons = IconPack.buildEmptyPack(entry.icons)
                 throw e
@@ -182,6 +199,11 @@
                 setIcon(entry, normalIconDescriptor, it)
             }
 
+            entry.icons.statusBarChipIcon?.let {
+                it.setNotification(entry.sbn, notificationContentDescription)
+                setIcon(entry, normalIconDescriptor, it)
+            }
+
             entry.icons.shelfIcon?.let {
                 it.setNotification(entry.sbn, notificationContentDescription)
                 setIcon(entry, sensitiveIconDescriptor, it)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconPack.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconPack.java
index d029ce7..611cebc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconPack.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconPack.java
@@ -29,6 +29,7 @@
 
     private final boolean mAreIconsAvailable;
     @Nullable private final StatusBarIconView mStatusBarIcon;
+    @Nullable private final StatusBarIconView mStatusBarChipIcon;
     @Nullable private final StatusBarIconView mShelfIcon;
     @Nullable private final StatusBarIconView mAodIcon;
 
@@ -43,7 +44,7 @@
      * haven't been inflated yet or there was an error while inflating them).
      */
     public static IconPack buildEmptyPack(@Nullable IconPack fromSource) {
-        return new IconPack(false, null, null, null, fromSource);
+        return new IconPack(false, null, null, null, null, fromSource);
     }
 
     /**
@@ -51,20 +52,23 @@
      */
     public static IconPack buildPack(
             @NonNull StatusBarIconView statusBarIcon,
+            @Nullable StatusBarIconView statusBarChipIcon,
             @NonNull StatusBarIconView shelfIcon,
             @NonNull StatusBarIconView aodIcon,
             @Nullable IconPack source) {
-        return new IconPack(true, statusBarIcon, shelfIcon, aodIcon, source);
+        return new IconPack(true, statusBarIcon, statusBarChipIcon, shelfIcon, aodIcon, source);
     }
 
     private IconPack(
             boolean areIconsAvailable,
             @Nullable StatusBarIconView statusBarIcon,
+            @Nullable StatusBarIconView statusBarChipIcon,
             @Nullable StatusBarIconView shelfIcon,
             @Nullable StatusBarIconView aodIcon,
             @Nullable IconPack source) {
         mAreIconsAvailable = areIconsAvailable;
         mStatusBarIcon = statusBarIcon;
+        mStatusBarChipIcon = statusBarChipIcon;
         mShelfIcon = shelfIcon;
         mAodIcon = aodIcon;
         if (source != null) {
@@ -79,6 +83,17 @@
     }
 
     /**
+     * The version of the notification icon that appears inside a chip within the status bar.
+     *
+     * Separate from {@link #getStatusBarIcon()} so that we don't have to worry about detaching and
+     * re-attaching the same view when the chip appears and hides.
+     */
+    @Nullable
+    public StatusBarIconView getStatusBarChipIcon() {
+        return mStatusBarChipIcon;
+    }
+
+    /**
      * The version of the icon that appears in the "shelf" at the bottom of the notification shade.
      * In general, this icon also appears somewhere on the notification and is "sucked" into the
      * shelf as the scrolls beyond it.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
index 6960791..cf19938 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
@@ -17,6 +17,7 @@
 
 import android.app.PendingIntent
 import android.graphics.drawable.Icon
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.notification.stack.PriorityBucket
 
 /**
@@ -59,6 +60,8 @@
     val shelfIcon: Icon?,
     /** Icon to display in the status bar. */
     val statusBarIcon: Icon?,
+    /** Icon to display in the status bar chip. */
+    val statusBarChipIconView: StatusBarIconView?,
     /** The notifying app's [packageName]'s uid. */
     val uid: Int,
     /** The notifying app's packageName. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 7af0666..4368239 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
 import com.android.systemui.statusbar.chips.ui.view.ChipChronometer
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
@@ -114,6 +115,9 @@
                         CallNotificationInfo(
                             entry.sbn.key,
                             entry.sbn.notification.getWhen(),
+                            // In this old listener pattern, we don't have access to the
+                            // notification icon.
+                            notificationIconView = null,
                             entry.sbn.notification.contentIntent,
                             entry.sbn.uid,
                             entry.sbn.notification.extras.getInt(
@@ -223,8 +227,15 @@
                 callNotificationInfo
                     // This shouldn't happen, but protect against it in case
                     ?: return OngoingCallModel.NoCall
+            val icon =
+                if (Flags.statusBarCallChipNotificationIcon()) {
+                    currentInfo.notificationIconView
+                } else {
+                    null
+                }
             return OngoingCallModel.InCall(
                 startTimeMs = currentInfo.callStartTime,
+                notificationIconView = icon,
                 intent = currentInfo.intent,
             )
         } else {
@@ -260,6 +271,7 @@
                 CallNotificationInfo(
                     notifModel.key,
                     notifModel.whenTime,
+                    notifModel.statusBarChipIconView,
                     notifModel.contentIntent,
                     notifModel.uid,
                     isOngoing = true,
@@ -407,6 +419,8 @@
     private data class CallNotificationInfo(
         val key: String,
         val callStartTime: Long,
+        /** The icon set as the [android.app.Notification.getSmallIcon] field. */
+        val notificationIconView: StatusBarIconView?,
         val intent: PendingIntent?,
         val uid: Int,
         /** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
index 2c48487..34bff80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone.ongoingcall.shared.model
 
 import android.app.PendingIntent
+import com.android.systemui.statusbar.StatusBarIconView
 
 /** Represents the state of any ongoing calls. */
 sealed interface OngoingCallModel {
@@ -31,7 +32,13 @@
      *   [com.android.systemui.util.time.SystemClock.currentTimeMillis], **not**
      *   [com.android.systemui.util.time.SystemClock.elapsedRealtime]. This value can be 0 if the
      *   user has started an outgoing call that hasn't been answered yet - see b/192379214.
+     * @property notificationIconView the [android.app.Notification.getSmallIcon] that's set on the
+     *   call notification. We may use this icon in the chip instead of the default phone icon.
      * @property intent the intent associated with the call notification.
      */
-    data class InCall(val startTimeMs: Long, val intent: PendingIntent?) : OngoingCallModel
+    data class InCall(
+        val startTimeMs: Long,
+        val notificationIconView: StatusBarIconView?,
+        val intent: PendingIntent?,
+    ) : OngoingCallModel
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index 16bd7f8..d46aaf4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -18,9 +18,12 @@
 
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
+import android.annotation.IdRes
 import android.content.res.ColorStateList
 import android.graphics.drawable.GradientDrawable
 import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.TextView
 import androidx.lifecycle.Lifecycle
@@ -31,6 +34,7 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.chips.ui.binder.ChipChronometerBinder
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
@@ -90,7 +94,7 @@
                 if (Flags.statusBarScreenSharingChips()) {
                     val chipView: View = view.requireViewById(R.id.ongoing_activity_chip)
                     val chipContext = chipView.context
-                    val chipIconView: ImageView =
+                    val chipDefaultIconView: ImageView =
                         chipView.requireViewById(R.id.ongoing_activity_chip_icon)
                     val chipTimeView: ChipChronometer =
                         chipView.requireViewById(R.id.ongoing_activity_chip_time)
@@ -105,16 +109,25 @@
                             when (chipModel) {
                                 is OngoingActivityChipModel.Shown -> {
                                     // Data
-                                    IconViewBinder.bindNullable(chipModel.icon, chipIconView)
+                                    setChipIcon(chipModel, chipBackgroundView, chipDefaultIconView)
                                     setChipMainContent(chipModel, chipTextView, chipTimeView)
                                     chipView.setOnClickListener(chipModel.onClickListener)
+                                    updateChipPadding(
+                                        chipModel,
+                                        chipBackgroundView,
+                                        chipTextView,
+                                        chipTimeView,
+                                    )
 
                                     // Accessibility
                                     setChipAccessibility(chipModel, chipView, chipBackgroundView)
 
                                     // Colors
                                     val textColor = chipModel.colors.text(chipContext)
-                                    chipIconView.imageTintList = ColorStateList.valueOf(textColor)
+                                    chipDefaultIconView.imageTintList =
+                                        ColorStateList.valueOf(textColor)
+                                    chipBackgroundView.getCustomIconView()?.imageTintList =
+                                        ColorStateList.valueOf(textColor)
                                     chipTimeView.setTextColor(textColor)
                                     chipTextView.setTextColor(textColor)
                                     (chipBackgroundView.background as GradientDrawable).color =
@@ -151,6 +164,69 @@
         }
     }
 
+    private fun setChipIcon(
+        chipModel: OngoingActivityChipModel.Shown,
+        backgroundView: ChipBackgroundContainer,
+        defaultIconView: ImageView,
+    ) {
+        // Always remove any previously set custom icon. If we have a new custom icon, we'll re-add
+        // it.
+        backgroundView.removeView(backgroundView.getCustomIconView())
+
+        when (val icon = chipModel.icon) {
+            null -> {
+                defaultIconView.visibility = View.GONE
+            }
+            is OngoingActivityChipModel.ChipIcon.Basic -> {
+                IconViewBinder.bind(icon.impl, defaultIconView)
+                defaultIconView.visibility = View.VISIBLE
+            }
+            is OngoingActivityChipModel.ChipIcon.StatusBarView -> {
+                // Hide the default icon since we'll show this custom icon instead.
+                defaultIconView.visibility = View.GONE
+
+                // Add the new custom icon:
+                // 1. Set up the right visual params.
+                val iconView = icon.impl
+                with(iconView) {
+                    id = CUSTOM_ICON_VIEW_ID
+                    // TODO(b/354930838): Update the content description to not include "phone" and
+                    // maybe include the app name.
+                    contentDescription =
+                        context.resources.getString(R.string.ongoing_phone_call_content_description)
+                }
+
+                // 2. If we just reinflated the view, we may need to detach the icon view from the
+                // old chip before we reattach it to the new one.
+                // See also: NotificationIconContainerViewBinder#bindIcons.
+                val currentParent = iconView.parent as? ViewGroup
+                if (currentParent != null && currentParent != backgroundView) {
+                    currentParent.removeView(iconView)
+                    currentParent.removeTransientView(iconView)
+                }
+
+                // 3: Add the icon as the starting view.
+                backgroundView.addView(
+                    iconView,
+                    /* index= */ 0,
+                    generateCustomIconLayoutParams(iconView),
+                )
+            }
+        }
+    }
+
+    private fun View.getCustomIconView(): StatusBarIconView? {
+        return this.findViewById(CUSTOM_ICON_VIEW_ID)
+    }
+
+    private fun generateCustomIconLayoutParams(iconView: ImageView): FrameLayout.LayoutParams {
+        val customIconSize =
+            iconView.context.resources.getDimensionPixelSize(
+                R.dimen.ongoing_activity_chip_embedded_padding_icon_size
+            )
+        return FrameLayout.LayoutParams(customIconSize, customIconSize)
+    }
+
     private fun setChipMainContent(
         chipModel: OngoingActivityChipModel.Shown,
         chipTextView: TextView,
@@ -180,37 +256,93 @@
                 chipTimeView.visibility = View.GONE
             }
         }
-        updateChipTextPadding(chipModel, chipTextView, chipTimeView)
     }
 
-    private fun updateChipTextPadding(
+    private fun updateChipPadding(
         chipModel: OngoingActivityChipModel.Shown,
+        backgroundView: View,
         chipTextView: TextView,
         chipTimeView: ChipChronometer,
     ) {
-        val requiresPadding = chipModel.icon != null
-        if (requiresPadding) {
-            chipTextView.addChipTextPaddingStart()
-            chipTimeView.addChipTextPaddingStart()
+        if (chipModel.icon != null) {
+            if (chipModel.icon is OngoingActivityChipModel.ChipIcon.StatusBarView) {
+                // If the icon is a custom [StatusBarIconView], then it should've come from
+                // `Notification.smallIcon`, which is required to embed its own paddings. We need to
+                // adjust the other paddings to make everything look good :)
+                backgroundView.setBackgroundPaddingForEmbeddedPaddingIcon()
+                chipTextView.setTextPaddingForEmbeddedPaddingIcon()
+                chipTimeView.setTextPaddingForEmbeddedPaddingIcon()
+            } else {
+                backgroundView.setBackgroundPaddingForNormalIcon()
+                chipTextView.setTextPaddingForNormalIcon()
+                chipTimeView.setTextPaddingForNormalIcon()
+            }
         } else {
-            chipTextView.removeChipTextPaddingStart()
-            chipTimeView.removeChipTextPaddingStart()
+            backgroundView.setBackgroundPaddingForNoIcon()
+            chipTextView.setTextPaddingForNoIcon()
+            chipTimeView.setTextPaddingForNoIcon()
         }
     }
 
-    private fun View.addChipTextPaddingStart() {
+    private fun View.setTextPaddingForEmbeddedPaddingIcon() {
+        val newPaddingEnd =
+            context.resources.getDimensionPixelSize(
+                R.dimen.ongoing_activity_chip_text_end_padding_for_embedded_padding_icon
+            )
+        setPaddingRelative(
+            // The icon should embed enough padding between the icon and time view.
+            /* start= */ 0,
+            this.paddingTop,
+            newPaddingEnd,
+            this.paddingBottom,
+        )
+    }
+
+    private fun View.setTextPaddingForNormalIcon() {
         this.setPaddingRelative(
             this.context.resources.getDimensionPixelSize(
                 R.dimen.ongoing_activity_chip_icon_text_padding
             ),
             paddingTop,
-            paddingEnd,
+            // The background view will contain the right end padding.
+            /* end= */ 0,
             paddingBottom,
         )
     }
 
-    private fun View.removeChipTextPaddingStart() {
-        this.setPaddingRelative(/* start= */ 0, paddingTop, paddingEnd, paddingBottom)
+    private fun View.setTextPaddingForNoIcon() {
+        // The background view will have even start & end paddings, so we don't want the text view
+        // to add any additional padding.
+        this.setPaddingRelative(/* start= */ 0, paddingTop, /* end= */ 0, paddingBottom)
+    }
+
+    private fun View.setBackgroundPaddingForEmbeddedPaddingIcon() {
+        val sidePadding =
+            context.resources.getDimensionPixelSize(
+                R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon
+            )
+        setPaddingRelative(
+            sidePadding,
+            paddingTop,
+            sidePadding,
+            paddingBottom,
+        )
+    }
+
+    private fun View.setBackgroundPaddingForNormalIcon() {
+        val sidePadding =
+            context.resources.getDimensionPixelSize(R.dimen.ongoing_activity_chip_side_padding)
+        setPaddingRelative(
+            sidePadding,
+            paddingTop,
+            sidePadding,
+            paddingBottom,
+        )
+    }
+
+    private fun View.setBackgroundPaddingForNoIcon() {
+        // The padding for the normal icon is also appropriate for no icon.
+        setBackgroundPaddingForNormalIcon()
     }
 
     private fun setChipAccessibility(
@@ -269,6 +401,10 @@
             )
             .start()
     }
+
+    companion object {
+        @IdRes private val CUSTOM_ICON_VIEW_ID = R.id.ongoing_activity_chip_custom_icon
+    }
 }
 
 /** Listener for various events that may affect the status bar's visibility. */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorTest.kt
index cd8a740..8f41caf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import kotlinx.coroutines.test.runTest
@@ -39,7 +40,7 @@
         kosmos.testScope.runTest {
             val latest by collectLastValue(underTest.ongoingCallState)
 
-            val inCall = OngoingCallModel.InCall(startTimeMs = 1000, intent = null)
+            val inCall = inCallModel(startTimeMs = 1000)
             repo.setOngoingCallState(inCall)
             assertThat(latest).isEqualTo(inCall)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
index 1a6b420..ce79fbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
@@ -17,8 +17,11 @@
 package com.android.systemui.statusbar.chips.call.ui.viewmodel
 
 import android.app.PendingIntent
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.view.View
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.coroutines.collectLastValue
@@ -26,11 +29,13 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.plugins.activityStarter
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.chips.ui.model.ColorsModel
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
 import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
 import com.android.systemui.util.time.fakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
@@ -73,7 +78,7 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 0, intent = null))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 0))
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
         }
@@ -83,7 +88,7 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = -2, intent = null))
+            repo.setOngoingCallState(inCallModel(startTimeMs = -2))
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
         }
@@ -93,7 +98,7 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 345, intent = null))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 345))
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
         }
@@ -106,7 +111,7 @@
             kosmos.fakeSystemClock.setCurrentTimeMillis(3000)
             kosmos.fakeSystemClock.setElapsedRealtime(400_000)
 
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 1000, intent = null))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 1000))
 
             // The OngoingCallModel start time is relative to currentTimeMillis, so this call
             // started 2000ms ago (1000 - 3000). The OngoingActivityChipModel start time needs to be
@@ -117,29 +122,97 @@
         }
 
     @Test
-    fun chip_positiveStartTime_iconIsPhone() =
+    @DisableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
+    fun chip_positiveStartTime_notifIconFlagOff_iconIsPhone() =
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 1000, intent = null))
+            repo.setOngoingCallState(
+                inCallModel(startTimeMs = 1000, notificationIcon = mock<StatusBarIconView>())
+            )
 
-            assertThat(((latest as OngoingActivityChipModel.Shown).icon as Icon.Resource).res)
-                .isEqualTo(com.android.internal.R.drawable.ic_phone)
-            assertThat((latest as OngoingActivityChipModel.Shown).icon!!.contentDescription)
-                .isNotNull()
+            assertThat((latest as OngoingActivityChipModel.Shown).icon)
+                .isInstanceOf(OngoingActivityChipModel.ChipIcon.Basic::class.java)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
+            assertThat(icon.contentDescription).isNotNull()
         }
 
     @Test
-    fun chip_zeroStartTime_iconIsPhone() =
+    @EnableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
+    fun chip_positiveStartTime_notifIconFlagOn_iconIsNotifIcon() =
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 0, intent = null))
+            val notifIcon = mock<StatusBarIconView>()
+            repo.setOngoingCallState(inCallModel(startTimeMs = 1000, notificationIcon = notifIcon))
 
-            assertThat(((latest as OngoingActivityChipModel.Shown).icon as Icon.Resource).res)
-                .isEqualTo(com.android.internal.R.drawable.ic_phone)
-            assertThat((latest as OngoingActivityChipModel.Shown).icon!!.contentDescription)
-                .isNotNull()
+            assertThat((latest as OngoingActivityChipModel.Shown).icon)
+                .isInstanceOf(OngoingActivityChipModel.ChipIcon.StatusBarView::class.java)
+            val actualIcon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.StatusBarView)
+                    .impl
+            assertThat(actualIcon).isEqualTo(notifIcon)
+        }
+
+    @Test
+    @DisableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
+    fun chip_zeroStartTime_notifIconFlagOff_iconIsPhone() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chip)
+
+            repo.setOngoingCallState(
+                inCallModel(startTimeMs = 0, notificationIcon = mock<StatusBarIconView>())
+            )
+
+            assertThat((latest as OngoingActivityChipModel.Shown).icon)
+                .isInstanceOf(OngoingActivityChipModel.ChipIcon.Basic::class.java)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
+            assertThat(icon.contentDescription).isNotNull()
+        }
+
+    @Test
+    @EnableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
+    fun chip_zeroStartTime_notifIconFlagOn_iconIsNotifIcon() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chip)
+
+            val notifIcon = mock<StatusBarIconView>()
+            repo.setOngoingCallState(inCallModel(startTimeMs = 0, notificationIcon = notifIcon))
+
+            assertThat((latest as OngoingActivityChipModel.Shown).icon)
+                .isInstanceOf(OngoingActivityChipModel.ChipIcon.StatusBarView::class.java)
+            val actualIcon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.StatusBarView)
+                    .impl
+            assertThat(actualIcon).isEqualTo(notifIcon)
+        }
+
+    @Test
+    @EnableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
+    fun chip_notifIconFlagOn_butNullNotifIcon_iconIsPhone() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.chip)
+
+            repo.setOngoingCallState(inCallModel(startTimeMs = 1000, notificationIcon = null))
+
+            assertThat((latest as OngoingActivityChipModel.Shown).icon)
+                .isInstanceOf(OngoingActivityChipModel.ChipIcon.Basic::class.java)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
+            assertThat(icon.contentDescription).isNotNull()
         }
 
     @Test
@@ -147,7 +220,7 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 1000, intent = null))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 1000))
 
             assertThat((latest as OngoingActivityChipModel.Shown).colors)
                 .isEqualTo(ColorsModel.Themed)
@@ -158,7 +231,7 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 0, intent = null))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 0))
 
             assertThat((latest as OngoingActivityChipModel.Shown).colors)
                 .isEqualTo(ColorsModel.Themed)
@@ -172,7 +245,7 @@
             kosmos.fakeSystemClock.setElapsedRealtime(400_000)
 
             // Start a call
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 1000, intent = null))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 1000))
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
             assertThat((latest as OngoingActivityChipModel.Shown.Timer).startTimeMs)
                 .isEqualTo(398_000)
@@ -186,7 +259,7 @@
             kosmos.fakeSystemClock.setElapsedRealtime(500_000)
 
             // Start a new call, which started 1000ms ago
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 102_000, intent = null))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 102_000))
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
             assertThat((latest as OngoingActivityChipModel.Shown.Timer).startTimeMs)
                 .isEqualTo(499_000)
@@ -197,7 +270,7 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.chip)
 
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 1000, intent = null))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 1000, intent = null))
 
             assertThat((latest as OngoingActivityChipModel.Shown).onClickListener).isNull()
         }
@@ -208,7 +281,7 @@
             val latest by collectLastValue(underTest.chip)
 
             val intent = mock<PendingIntent>()
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 1000, intent = intent))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 1000, intent = intent))
             val clickListener = (latest as OngoingActivityChipModel.Shown).onClickListener
             assertThat(clickListener).isNotNull()
 
@@ -223,7 +296,7 @@
             val latest by collectLastValue(underTest.chip)
 
             val intent = mock<PendingIntent>()
-            repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 0, intent = intent))
+            repo.setOngoingCallState(inCallModel(startTimeMs = 0, intent = intent))
             val clickListener = (latest as OngoingActivityChipModel.Shown).onClickListener
             assertThat(clickListener).isNotNull()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
index 02764f8..a8d2c5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
@@ -125,8 +125,11 @@
                 )
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(R.drawable.ic_cast_connected)
             assertThat((icon.contentDescription as ContentDescription.Resource).res)
                 .isEqualTo(R.string.cast_screen_to_other_device_chip_accessibility_label)
         }
@@ -141,8 +144,11 @@
                 MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE)
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(R.drawable.ic_cast_connected)
             assertThat((icon.contentDescription as ContentDescription.Resource).res)
                 .isEqualTo(R.string.cast_screen_to_other_device_chip_accessibility_label)
         }
@@ -176,8 +182,11 @@
                 )
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(R.drawable.ic_cast_connected)
             // This content description is just generic "Casting", not "Casting screen"
             assertThat((icon.contentDescription as ContentDescription.Resource).res)
                 .isEqualTo(R.string.accessibility_casting)
@@ -203,8 +212,11 @@
 
             // Only the projection info will show a timer
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(R.drawable.ic_cast_connected)
             // MediaProjection == screen casting, so this content description reflects that we're
             // using the MediaProjection information.
             assertThat((icon.contentDescription as ContentDescription.Resource).res)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
index b4a37ee..e68fa0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
@@ -148,8 +148,11 @@
             screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenrecord)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(R.drawable.ic_screenrecord)
             assertThat(icon.contentDescription).isNotNull()
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
index 2658679..a2ef599 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
@@ -133,8 +133,11 @@
                 )
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_present_to_all)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(R.drawable.ic_present_to_all)
             assertThat(icon.contentDescription).isNotNull()
         }
 
@@ -147,8 +150,11 @@
                 MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
 
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_present_to_all)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(R.drawable.ic_present_to_all)
             assertThat(icon.contentDescription).isNotNull()
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt
index b9049e8..a724cfaa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChipTransitionHelperTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.chips.ui.viewmodel
 
+import androidx.annotation.DrawableRes
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.Icon
@@ -50,7 +51,7 @@
 
             val newChip =
                 OngoingActivityChipModel.Shown.Timer(
-                    icon = Icon.Resource(R.drawable.ic_cake, contentDescription = null),
+                    icon = createIcon(R.drawable.ic_cake),
                     colors = ColorsModel.Themed,
                     startTimeMs = 100L,
                     onClickListener = null,
@@ -62,7 +63,7 @@
 
             val newerChip =
                 OngoingActivityChipModel.Shown.IconOnly(
-                    icon = Icon.Resource(R.drawable.ic_hotspot, contentDescription = null),
+                    icon = createIcon(R.drawable.ic_hotspot),
                     colors = ColorsModel.Themed,
                     onClickListener = null,
                 )
@@ -82,7 +83,7 @@
 
             val shownChip =
                 OngoingActivityChipModel.Shown.Timer(
-                    icon = Icon.Resource(R.drawable.ic_cake, contentDescription = null),
+                    icon = createIcon(R.drawable.ic_cake),
                     colors = ColorsModel.Themed,
                     startTimeMs = 100L,
                     onClickListener = null,
@@ -122,7 +123,7 @@
 
             val shownChip =
                 OngoingActivityChipModel.Shown.Timer(
-                    icon = Icon.Resource(R.drawable.ic_cake, contentDescription = null),
+                    icon = createIcon(R.drawable.ic_cake),
                     colors = ColorsModel.Themed,
                     startTimeMs = 100L,
                     onClickListener = null,
@@ -151,4 +152,7 @@
             advanceTimeBy(2)
             assertThat(latest).isEqualTo(shownChip)
         }
+
+    private fun createIcon(@DrawableRes drawable: Int) =
+        OngoingActivityChipModel.ChipIcon.Basic(Icon.Resource(drawable, contentDescription = null))
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index ee249f0..556ec6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
 import com.android.systemui.util.time.fakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -120,7 +121,7 @@
         testScope.runTest {
             screenRecordState.value = ScreenRecordModel.Recording
 
-            callRepo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 34, intent = null))
+            callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
 
             val latest by collectLastValue(underTest.chip)
 
@@ -146,7 +147,7 @@
             screenRecordState.value = ScreenRecordModel.DoingNothing
             mediaProjectionState.value =
                 MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
-            callRepo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 34, intent = null))
+            callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
 
             val latest by collectLastValue(underTest.chip)
 
@@ -160,7 +161,7 @@
             // MediaProjection covers both share-to-app and cast-to-other-device
             mediaProjectionState.value = MediaProjectionState.NotProjecting
 
-            callRepo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 34, intent = null))
+            callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
 
             val latest by collectLastValue(underTest.chip)
 
@@ -171,7 +172,7 @@
     fun chip_higherPriorityChipAdded_lowerPriorityChipReplaced() =
         testScope.runTest {
             // Start with just the lower priority call chip
-            callRepo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 34, intent = null))
+            callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
             mediaProjectionState.value = MediaProjectionState.NotProjecting
             screenRecordState.value = ScreenRecordModel.DoingNothing
 
@@ -205,7 +206,7 @@
             mediaProjectionState.value =
                 MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
 
-            callRepo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 34, intent = null))
+            callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
 
             val latest by collectLastValue(underTest.chip)
 
@@ -335,21 +336,29 @@
 
         fun assertIsScreenRecordChip(latest: OngoingActivityChipModel?) {
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenrecord)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(R.drawable.ic_screenrecord)
         }
 
         fun assertIsShareToAppChip(latest: OngoingActivityChipModel?) {
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_present_to_all)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(R.drawable.ic_present_to_all)
         }
 
         fun assertIsCallChip(latest: OngoingActivityChipModel?) {
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
-            val icon = (latest as OngoingActivityChipModel.Shown).icon
-            assertThat((icon as Icon.Resource).res)
-                .isEqualTo(com.android.internal.R.drawable.ic_phone)
+            val icon =
+                (((latest as OngoingActivityChipModel.Shown).icon)
+                        as OngoingActivityChipModel.ChipIcon.Basic)
+                    .impl as Icon.Resource
+            assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
index 6a5976e..48ae7a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
@@ -39,6 +39,7 @@
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
@@ -396,9 +397,7 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.statusBarAppearance)
 
-            ongoingCallRepository.setOngoingCallState(
-                OngoingCallModel.InCall(startTimeMs = 34, intent = null)
-            )
+            ongoingCallRepository.setOngoingCallState(inCallModel(startTimeMs = 34))
             onSystemBarAttributesChanged(
                 requestedVisibleTypes = WindowInsets.Type.navigationBars(),
             )
@@ -411,9 +410,8 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.statusBarAppearance)
 
-            ongoingCallRepository.setOngoingCallState(
-                OngoingCallModel.InCall(startTimeMs = 789, intent = null)
-            )
+            ongoingCallRepository.setOngoingCallState(inCallModel(startTimeMs = 789))
+
             onSystemBarAttributesChanged(
                 requestedVisibleTypes = WindowInsets.Type.statusBars(),
                 appearance = APPEARANCE_OPAQUE_STATUS_BARS,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
index bfa816e..25138fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
@@ -30,9 +30,12 @@
 import android.os.Bundle
 import android.os.SystemClock
 import android.os.UserHandle
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import androidx.test.InstrumentationRegistry
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapperTest.Companion.any
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -108,6 +111,28 @@
     }
 
     @Test
+    @DisableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
+    fun testCreateIcons_chipNotifIconFlagDisabled_statusBarChipIconIsNull() {
+        val entry =
+            notificationEntry(hasShortcut = true, hasMessageSenderIcon = true, hasLargeIcon = true)
+        entry?.let { iconManager.createIcons(it) }
+        testScope.runCurrent()
+
+        assertThat(entry?.icons?.statusBarChipIcon).isNull()
+    }
+
+    @Test
+    @EnableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
+    fun testCreateIcons_chipNotifIconFlagEnabled_statusBarChipIconIsNull() {
+        val entry =
+            notificationEntry(hasShortcut = true, hasMessageSenderIcon = true, hasLargeIcon = true)
+        entry?.let { iconManager.createIcons(it) }
+        testScope.runCurrent()
+
+        assertThat(entry?.icons?.statusBarChipIcon).isNotNull()
+    }
+
+    @Test
     fun testCreateIcons_importantConversation_shortcutIcon() {
         val entry =
             notificationEntry(hasShortcut = true, hasMessageSenderIcon = true, hasLargeIcon = true)
@@ -179,6 +204,7 @@
     }
 
     @Test
+    @EnableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
     fun testCreateIcons_sensitiveImportantConversation() {
         val entry =
             notificationEntry(hasShortcut = true, hasMessageSenderIcon = true, hasLargeIcon = false)
@@ -187,11 +213,13 @@
         entry?.let { iconManager.createIcons(it) }
         testScope.runCurrent()
         assertThat(entry?.icons?.statusBarIcon?.sourceIcon).isEqualTo(shortcutIc)
+        assertThat(entry?.icons?.statusBarChipIcon?.sourceIcon).isEqualTo(shortcutIc)
         assertThat(entry?.icons?.shelfIcon?.sourceIcon).isEqualTo(smallIc)
         assertThat(entry?.icons?.aodIcon?.sourceIcon).isEqualTo(smallIc)
     }
 
     @Test
+    @EnableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
     fun testUpdateIcons_sensitiveImportantConversation() {
         val entry =
             notificationEntry(hasShortcut = true, hasMessageSenderIcon = true, hasLargeIcon = false)
@@ -202,6 +230,7 @@
         entry?.let { iconManager.updateIcons(it) }
         testScope.runCurrent()
         assertThat(entry?.icons?.statusBarIcon?.sourceIcon).isEqualTo(shortcutIc)
+        assertThat(entry?.icons?.statusBarChipIcon?.sourceIcon).isEqualTo(shortcutIc)
         assertThat(entry?.icons?.shelfIcon?.sourceIcon).isEqualTo(smallIc)
         assertThat(entry?.icons?.aodIcon?.sourceIcon).isEqualTo(smallIc)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
index 6c2e2c6..dfe01bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
@@ -28,7 +28,7 @@
 import android.widget.LinearLayout
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
+import com.android.systemui.Flags.FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON
 import com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS
 import com.android.systemui.Flags.FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP
 import com.android.systemui.SysuiTestCase
@@ -39,6 +39,7 @@
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.plugins.activityStarter
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
 import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -160,6 +161,47 @@
         }
 
     @Test
+    @DisableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
+    fun interactorHasOngoingCallNotif_notifIconFlagOff_repoHasNoNotifIcon() =
+        testScope.runTest {
+            val icon = mock<StatusBarIconView>()
+            setNotifOnRepo(
+                activeNotificationModel(
+                    key = "ongoingNotif",
+                    callType = CallType.Ongoing,
+                    uid = CALL_UID,
+                    statusBarChipIcon = icon,
+                    whenTime = 567,
+                )
+            )
+
+            val repoState = ongoingCallRepository.ongoingCallState.value
+            assertThat(repoState).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((repoState as OngoingCallModel.InCall).notificationIconView).isNull()
+        }
+
+    @Test
+    @EnableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON)
+    fun interactorHasOngoingCallNotif_notifIconFlagOn_repoHasNotifIcon() =
+        testScope.runTest {
+            val icon = mock<StatusBarIconView>()
+
+            setNotifOnRepo(
+                activeNotificationModel(
+                    key = "ongoingNotif",
+                    callType = CallType.Ongoing,
+                    uid = CALL_UID,
+                    statusBarChipIcon = icon,
+                    whenTime = 567,
+                )
+            )
+
+            val repoState = ongoingCallRepository.ongoingCallState.value
+            assertThat(repoState).isInstanceOf(OngoingCallModel.InCall::class.java)
+            assertThat((repoState as OngoingCallModel.InCall).notificationIconView).isEqualTo(icon)
+        }
+
+    @Test
     fun notifRepoHasOngoingCallNotif_isOngoingCallNotif_windowControllerUpdated() {
         setCallNotifOnRepo()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
index cbb8fe8..4c6eaa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -33,7 +34,7 @@
 
     @Test
     fun hasOngoingCall_matchesSet() {
-        val inCallModel = OngoingCallModel.InCall(startTimeMs = 654, intent = null)
+        val inCallModel = inCallModel(startTimeMs = 654)
         underTest.setOngoingCallState(inCallModel)
 
         assertThat(underTest.ongoingCallState.value).isEqualTo(inCallModel)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
index 37f1f13..76bdc0d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
@@ -18,6 +18,7 @@
 
 import android.app.PendingIntent
 import android.graphics.drawable.Icon
+import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.statusbar.notification.shared.CallType
 import com.android.systemui.statusbar.notification.stack.BUCKET_UNKNOWN
@@ -36,6 +37,7 @@
     aodIcon: Icon? = null,
     shelfIcon: Icon? = null,
     statusBarIcon: Icon? = null,
+    statusBarChipIcon: StatusBarIconView? = null,
     uid: Int = 0,
     instanceId: Int? = null,
     isGroupSummary: Boolean = false,
@@ -57,6 +59,7 @@
         aodIcon = aodIcon,
         shelfIcon = shelfIcon,
         statusBarIcon = statusBarIcon,
+        statusBarChipIconView = statusBarChipIcon,
         uid = uid,
         packageName = packageName,
         contentIntent = contentIntent,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt
new file mode 100644
index 0000000..3963d7c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.ongoingcall.shared.model
+
+import android.app.PendingIntent
+import com.android.systemui.statusbar.StatusBarIconView
+
+/** Helper for building [OngoingCallModel.InCall] instances in tests. */
+fun inCallModel(
+    startTimeMs: Long,
+    notificationIcon: StatusBarIconView? = null,
+    intent: PendingIntent? = null
+) = OngoingCallModel.InCall(startTimeMs, notificationIcon, intent)