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

Commit e5bca37f authored by Ioana Alexandru's avatar Ioana Alexandru Committed by Android (Google) Code Review
Browse files

Merge "Notif redesign: Improve the way we display the work badge" into main

parents 3937f88d 63427582
Loading
Loading
Loading
Loading
+53 −11
Original line number Diff line number Diff line
@@ -22,12 +22,14 @@ import android.app.Flags
import android.content.Context
import android.content.pm.PackageManager.NameNotFoundException
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.UserHandle
import android.util.Log
import com.android.internal.R
import com.android.launcher3.icons.BaseIconFactory
import com.android.launcher3.icons.BaseIconFactory.IconOptions
import com.android.launcher3.util.UserIconInfo
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
@@ -48,7 +50,11 @@ interface AppIconProvider {
     */
    @Throws(NameNotFoundException::class)
    @WorkerThread
    fun getOrFetchAppIcon(packageName: String, context: Context): Drawable
    fun getOrFetchAppIcon(
        packageName: String,
        context: Context,
        withWorkProfileBadge: Boolean = false,
    ): Drawable

    /**
     * Mark all the entries in the cache that are NOT in [wantedPackages] to be cleared. If they're
@@ -81,21 +87,52 @@ constructor(private val sysuiContext: Context, dumpManager: DumpManager) :

    private val cache = NotifCollectionCache<Drawable>()

    override fun getOrFetchAppIcon(packageName: String, context: Context): Drawable {
        return cache.getOrFetch(packageName) { fetchAppIcon(packageName, context) }
    override fun getOrFetchAppIcon(
        packageName: String,
        context: Context,
        withWorkProfileBadge: Boolean,
    ): Drawable {
        // Add a suffix to distinguish the app installed on the work profile, since the icon will
        // be different.
        val key = packageName + if (withWorkProfileBadge) WORK_SUFFIX else ""

        return cache.getOrFetch(key) { fetchAppIcon(packageName, context, withWorkProfileBadge) }
    }

    @WorkerThread
    private fun fetchAppIcon(packageName: String, context: Context): BitmapDrawable {
        val icon = context.packageManager.getApplicationIcon(packageName)
        return BitmapDrawable(
            context.resources,
            iconFactory.createScaledBitmap(icon, BaseIconFactory.MODE_HARDWARE),
    private fun fetchAppIcon(
        packageName: String,
        context: Context,
        withWorkProfileBadge: Boolean,
    ): Drawable {
        val pm = context.packageManager
        val icon = pm.getApplicationInfo(packageName, 0).loadUnbadgedIcon(pm)

        val options =
            IconOptions().apply {
                setUser(userIconInfo(context, withWorkProfileBadge))
                setBitmapGenerationMode(BaseIconFactory.MODE_HARDWARE)
                // This color is not used since we're not showing the themed icons. We're just
                // setting it so that the icon factory doesn't try to extract colors from our bitmap
                // (since it won't work, given it's a hardware bitmap).
                setExtractedColor(Color.BLUE)
            }
        val badgedIcon = iconFactory.createBadgedIconBitmap(icon, options)
        return badgedIcon.newIcon(sysuiContext)
    }

    private fun userIconInfo(context: Context, withWorkProfileBadge: Boolean): UserIconInfo {
        val userId = context.userId
        return UserIconInfo(
            UserHandle.of(userId),
            if (withWorkProfileBadge) UserIconInfo.TYPE_WORK else UserIconInfo.TYPE_MAIN,
        )
    }

    override fun purgeCache(wantedPackages: Collection<String>) {
        cache.purge(wantedPackages)
        // We don't know from the packages if it's the work profile app or not, so let's just keep
        // both if they're present in the cache.
        cache.purge(wantedPackages.flatMap { listOf(it, "$it$WORK_SUFFIX") })
    }

    override fun dump(pwOrig: PrintWriter, args: Array<out String>) {
@@ -114,6 +151,7 @@ constructor(private val sysuiContext: Context, dumpManager: DumpManager) :

    companion object {
        const val TAG = "AppIconProviderImpl"
        const val WORK_SUFFIX = "|WORK"
    }
}

@@ -122,7 +160,11 @@ class NoOpIconProvider : AppIconProvider {
        const val TAG = "NoOpIconProvider"
    }

    override fun getOrFetchAppIcon(packageName: String, context: Context): Drawable {
    override fun getOrFetchAppIcon(
        packageName: String,
        context: Context,
        withWorkProfileBadge: Boolean,
    ): Drawable {
        Log.wtf(TAG, "NoOpIconProvider should not be used anywhere.")
        return ColorDrawable(Color.WHITE)
    }
+27 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.WorkerThread
import android.app.Flags
import android.content.Context
import android.content.pm.ApplicationInfo
import android.os.UserManager
import android.service.notification.StatusBarNotification
import android.util.Log
import com.android.systemui.Dumpable
@@ -46,6 +47,12 @@ interface NotificationIconStyleProvider {
    @WorkerThread
    fun shouldShowAppIcon(notification: StatusBarNotification, context: Context): Boolean

    /**
     * Whether the [notification] is coming from a work profile app, and therefore should display
     * the briefcase badge.
     */
    fun shouldShowWorkProfileBadge(notification: StatusBarNotification, context: Context): Boolean

    /**
     * Mark all the entries in the cache that are NOT in [wantedPackages] to be cleared. If they're
     * still not needed on the next call of this method (made after a timeout of 1s, in case they
@@ -55,7 +62,9 @@ interface NotificationIconStyleProvider {
}

@SysUISingleton
class NotificationIconStyleProviderImpl @Inject constructor(dumpManager: DumpManager) :
class NotificationIconStyleProviderImpl
@Inject
constructor(private val userManager: UserManager, dumpManager: DumpManager) :
    NotificationIconStyleProvider, Dumpable {
    init {
        dumpManager.registerNormalDumpable(TAG, this)
@@ -89,6 +98,15 @@ class NotificationIconStyleProviderImpl @Inject constructor(dumpManager: DumpMan
        }
    }

    override fun shouldShowWorkProfileBadge(
        notification: StatusBarNotification,
        context: Context,
    ): Boolean {
        val packageContext = notification.getPackageContext(context)
        // UserManager already caches this, so we don't need to.
        return userManager.isManagedProfile(packageContext.userId)
    }

    override fun purgeCache(wantedPackages: Collection<String>) {
        cache.purge(wantedPackages)
    }
@@ -114,6 +132,14 @@ class NoOpIconStyleProvider : NotificationIconStyleProvider {
        return true
    }

    override fun shouldShowWorkProfileBadge(
        notification: StatusBarNotification,
        context: Context,
    ): Boolean {
        Log.wtf(TAG, "NoOpIconStyleProvider should not be used anywhere.")
        return false
    }

    override fun purgeCache(wantedPackages: Collection<String>) {
        Log.wtf(TAG, "NoOpIconStyleProvider should not be used anywhere.")
    }
+9 −2
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ constructor(
                NotificationRowIconView(context, attrs).also { view ->
                    view.setIconProvider(createIconProvider(row, context))
                }

            else -> null
        }
    }
@@ -61,13 +62,19 @@ constructor(
        val sbn = row.entry.sbn
        return object : NotificationIconProvider {
            override fun shouldShowAppIcon(): Boolean {
                val shouldShowAppIcon = iconStyleProvider.shouldShowAppIcon(row.entry.sbn, context)
                val shouldShowAppIcon = iconStyleProvider.shouldShowAppIcon(sbn, context)
                row.setIsShowingAppIcon(shouldShowAppIcon)
                return shouldShowAppIcon
            }

            override fun getAppIcon(): Drawable {
                return appIconProvider.getOrFetchAppIcon(sbn.packageName, context)
                val withWorkProfileBadge =
                    iconStyleProvider.shouldShowWorkProfileBadge(sbn, context)
                return appIconProvider.getOrFetchAppIcon(
                    sbn.packageName,
                    context,
                    withWorkProfileBadge,
                )
            }
        }
    }
+4 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.app.NotificationManager
import android.content.Context
import android.content.pm.LauncherApps
import android.os.UserHandle
import android.os.UserManager
import android.provider.DeviceConfig
import androidx.core.os.bundleOf
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
@@ -109,6 +110,7 @@ class ExpandableNotificationRowBuilder(
    private val mKeyguardBypassController: KeyguardBypassController
    private val mGroupMembershipManager: GroupMembershipManager
    private val mGroupExpansionManager: GroupExpansionManager
    private val mUserManager: UserManager
    private val mHeadsUpManager: HeadsUpManager
    private val mIconManager: IconManager
    private val mContentBinder: NotificationRowContentBinder
@@ -143,6 +145,7 @@ class ExpandableNotificationRowBuilder(
        mSmartReplyController = Mockito.mock(SmartReplyController::class.java, STUB_ONLY)

        mGroupExpansionManager = GroupExpansionManagerImpl(mDumpManager, mGroupMembershipManager)
        mUserManager = Mockito.mock(UserManager::class.java, STUB_ONLY)
        mHeadsUpManager = Mockito.mock(HeadsUpManager::class.java, STUB_ONLY)
        mIconManager =
            IconManager(
@@ -289,7 +292,7 @@ class ExpandableNotificationRowBuilder(
            { Mockito.mock(NotificationViewFlipperFactory::class.java) },
            NotificationRowIconViewInflaterFactory(
                AppIconProviderImpl(context, mDumpManager),
                NotificationIconStyleProviderImpl(mDumpManager),
                NotificationIconStyleProviderImpl(mUserManager, mDumpManager),
            ),
        )
    }
+2 −1
Original line number Diff line number Diff line
@@ -16,8 +16,9 @@

package com.android.systemui.statusbar.notification.row.icon

import android.os.userManager
import com.android.systemui.dump.dumpManager
import com.android.systemui.kosmos.Kosmos

val Kosmos.notificationIconStyleProvider by
    Kosmos.Fixture { NotificationIconStyleProviderImpl(dumpManager) }
    Kosmos.Fixture { NotificationIconStyleProviderImpl(userManager, dumpManager) }