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

Commit 7d781c00 authored by Ioana Alexandru's avatar Ioana Alexandru
Browse files

Get person avatar icon on a bg thread

We're making a binder call to launcher, and it shouldn't block the main
thread.

Tracking this change and the other changes in the child bugs of b/315143361
under the same generic flag.

Fix: 320274812
Bug: 315143361
Test: posted a few high prio conversation notifs and checked that they
look good on aod, the shelf and status bar
Flag: ACONFIG com.android.systemui.notifications_background_icons DEVELOPMENT

Change-Id: Ie03cf3698c2d46c75012792a5628a5b1068b244b
parent c0fe25a5
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -105,10 +105,10 @@ flag {
}

flag {
    name: "notifications_background_media_icons"
    name: "notifications_background_icons"
    namespace: "systemui"
    description: "Updates icons for media notifications in the background."
    bug: "315143160"
    description: "Moves part of the notification icon updates to the background."
    bug: "315143361"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
+2 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
import com.android.systemui.toast.ToastModule;
import com.android.systemui.unfold.SysUIUnfoldStartableModule;
import com.android.systemui.unfold.UnfoldTransitionModule;
import com.android.systemui.util.kotlin.SysUICoroutinesModule;
import com.android.systemui.volume.dagger.VolumeModule;
import com.android.systemui.wallpapers.dagger.WallpaperModule;

@@ -117,6 +118,7 @@ import javax.inject.Named;
        ShadeModule.class,
        StartCentralSurfacesModule.class,
        SceneContainerFrameworkModule.class,
        SysUICoroutinesModule.class,
        SysUIUnfoldStartableModule.class,
        UnfoldTransitionModule.Startables.class,
        ToastModule.class,
+5 −5
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ public class MediaCoordinator implements Coordinator {
                return false;
            }

            if (!Flags.notificationsBackgroundMediaIcons()) {
            if (!Flags.notificationsBackgroundIcons()) {
                inflateOrUpdateIcons(entry);
            }

@@ -73,14 +73,14 @@ public class MediaCoordinator implements Coordinator {
        @Override
        public void onEntryInit(@NonNull NotificationEntry entry) {
            // We default to STATE_ICONS_UNINFLATED anyway, so there's no need to initialize it.
            if (!Flags.notificationsBackgroundMediaIcons()) {
            if (!Flags.notificationsBackgroundIcons()) {
                mIconsState.put(entry, STATE_ICONS_UNINFLATED);
            }
        }

        @Override
        public void onEntryAdded(@NonNull NotificationEntry entry) {
            if (Flags.notificationsBackgroundMediaIcons()) {
            if (Flags.notificationsBackgroundIcons()) {
                if (isMediaNotification(entry.getSbn())) {
                    inflateOrUpdateIcons(entry);
                }
@@ -94,7 +94,7 @@ public class MediaCoordinator implements Coordinator {
                mIconsState.put(entry, STATE_ICONS_UNINFLATED);
            }

            if (Flags.notificationsBackgroundMediaIcons()) {
            if (Flags.notificationsBackgroundIcons()) {
                if (isMediaNotification(entry.getSbn())) {
                    inflateOrUpdateIcons(entry);
                }
@@ -120,7 +120,7 @@ public class MediaCoordinator implements Coordinator {
                break;
            case STATE_ICONS_INFLATED:
                try {
                    mIconManager.updateIcons(entry);
                    mIconManager.updateIcons(entry, /* usingCache = */ false);
                } catch (InflationException e) {
                    reportInflationError(entry, e);
                    mIconsState.put(entry, STATE_ICONS_ERROR);
+1 −1
Original line number Diff line number Diff line
@@ -138,7 +138,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {

        if (entry.rowExists()) {
            mLogger.logUpdatingRow(entry, params);
            mIconManager.updateIcons(entry);
            mIconManager.updateIcons(entry, /* usingCache = */ false);
            ExpandableNotificationRow row = entry.getRow();
            row.reset();
            updateRow(entry, row);
+96 −22
Original line number Diff line number Diff line
@@ -28,14 +28,24 @@ import android.view.View
import android.widget.ImageView
import com.android.app.tracing.traceSection
import com.android.internal.statusbar.StatusBarIcon
import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.res.R
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.InflationException
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * Inflates and updates icons associated with notifications
@@ -53,9 +63,18 @@ class IconManager
constructor(
    private val notifCollection: CommonNotifCollection,
    private val launcherApps: LauncherApps,
    private val iconBuilder: IconBuilder
    private val iconBuilder: IconBuilder,
    @Application private val applicationCoroutineScope: CoroutineScope,
    @Background private val bgCoroutineContext: CoroutineContext,
    @Main private val mainCoroutineContext: CoroutineContext,
) : ConversationIconManager {
    private var unimportantConversationKeys: Set<String> = emptySet()
    /**
     * A map of running jobs for fetching the person avatar from launcher. The key is the
     * notification entry key.
     */
    private var launcherPeopleAvatarIconJobs: ConcurrentHashMap<String, Job> =
        ConcurrentHashMap<String, Job>()

    fun attach() {
        notifCollection.addCollectionListener(entryListener)
@@ -136,13 +155,23 @@ constructor(
     * @throws InflationException Exception if required icons are not valid or specified
     */
    @Throws(InflationException::class)
    fun updateIcons(entry: NotificationEntry) =
    fun updateIcons(entry: NotificationEntry, usingCache: Boolean = false) =
        traceSection("IconManager.updateIcons") {
            if (!entry.icons.areIconsAvailable) {
                return@traceSection
            }

            if (usingCache && !Flags.notificationsBackgroundIcons()) {
                Log.wtf(
                    TAG,
                    "Updating using the cache is not supported when the " +
                        "notifications_background_conversation_icons flag is off"
                )
            }
            if (!usingCache || !Flags.notificationsBackgroundIcons()) {
                entry.icons.smallIconDescriptor = null
                entry.icons.peopleAvatarDescriptor = null
            }

            val (normalIconDescriptor, sensitiveIconDescriptor) = getIconDescriptors(entry)
            val notificationContentDescription =
@@ -188,7 +217,7 @@ constructor(
    @Throws(InflationException::class)
    private fun getIconDescriptor(entry: NotificationEntry, redact: Boolean): StatusBarIcon {
        val n = entry.sbn.notification
        val showPeopleAvatar = isImportantConversation(entry) && !redact
        val showPeopleAvatar = !redact && isImportantConversation(entry)

        val peopleAvatarDescriptor = entry.icons.peopleAvatarDescriptor
        val smallIconDescriptor = entry.icons.smallIconDescriptor
@@ -208,26 +237,18 @@ constructor(
            })
                ?: throw InflationException("No icon in notification from " + entry.sbn.packageName)

        val ic =
            StatusBarIcon(
                entry.sbn.user,
                entry.sbn.packageName,
                icon,
                n.iconLevel,
                n.number,
                iconBuilder.getIconContentDescription(n)
            )
        val sbi = icon.toStatusBarIcon(entry)

        // Cache if important conversation.
        if (isImportantConversation(entry)) {
            if (showPeopleAvatar) {
                entry.icons.peopleAvatarDescriptor = ic
                entry.icons.peopleAvatarDescriptor = sbi
            } else {
                entry.icons.smallIconDescriptor = ic
                entry.icons.smallIconDescriptor = sbi
            }
        }

        return ic
        return sbi
    }

    @Throws(InflationException::class)
@@ -243,16 +264,69 @@ constructor(
        }
    }

    private fun Icon.toStatusBarIcon(entry: NotificationEntry): StatusBarIcon {
        val n = entry.sbn.notification
        return StatusBarIcon(
            entry.sbn.user,
            entry.sbn.packageName,
            /* icon = */ this,
            n.iconLevel,
            n.number,
            iconBuilder.getIconContentDescription(n)
        )
    }

    private suspend fun getLauncherShortcutIconForPeopleAvatar(entry: NotificationEntry) =
        withContext(bgCoroutineContext) {
            var icon: Icon? = null
            val shortcut = entry.ranking.conversationShortcutInfo
            if (shortcut != null) {
                try {
                    icon = launcherApps.getShortcutIcon(shortcut)
                } catch (e: Exception) {
                    Log.e(
                        TAG,
                        "Error calling LauncherApps#getShortcutIcon for notification $entry: $e"
                    )
                }
            }

            // Once we have the icon, updating it should happen on the main thread.
            if (icon != null) {
                withContext(mainCoroutineContext) {
                    val iconDescriptor = icon.toStatusBarIcon(entry)

                    // Cache the value
                    entry.icons.peopleAvatarDescriptor = iconDescriptor

                    // Update the icons using the cached value
                    updateIcons(entry = entry, usingCache = true)
                }
            }
        }

    @Throws(InflationException::class)
    private fun createPeopleAvatar(entry: NotificationEntry): Icon? {
    private fun createPeopleAvatar(entry: NotificationEntry): Icon {
        var ic: Icon? = null

        if (Flags.notificationsBackgroundIcons()) {
            // Ideally we want to get the icon from launcher, but this is a binder transaction that
            // may take longer so let's kick it off on a background thread and use a placeholder in
            // the meantime.
            // Cancel the previous job if necessary.
            launcherPeopleAvatarIconJobs[entry.key]?.cancel()
            launcherPeopleAvatarIconJobs[entry.key] =
                applicationCoroutineScope
                    .launch { getLauncherShortcutIconForPeopleAvatar(entry) }
                    .apply { invokeOnCompletion { launcherPeopleAvatarIconJobs.remove(entry.key) } }
        } else {
            val shortcut = entry.ranking.conversationShortcutInfo
            if (shortcut != null) {
                ic = launcherApps.getShortcutIcon(shortcut)
            }
        }

        // Fall back to extract from message
        // Try to extract from message
        if (ic == null) {
            val extras: Bundle = entry.sbn.notification.extras
            val messages =
Loading