Loading packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +109 −96 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.hardware.biometrics.PromptVerticalListContentView import android.hardware.face.FaceSensorPropertiesInternal import android.hardware.fingerprint.FingerprintSensorProperties import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.os.UserHandle import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.HapticFeedbackConstants Loading Loading @@ -97,13 +98,14 @@ import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters private const val USER_ID = 4 private const val WORK_USER_ID = 100 private const val REQUEST_ID = 4L private const val CHALLENGE = 2L private const val DELAY = 1000L private const val OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO = "should.use.activiy.logo" private const val OP_PACKAGE_NAME_WITH_APP_LOGO = "biometric.testapp" private const val OP_PACKAGE_NAME_NO_ICON = "biometric.testapp.noicon" private const val OP_PACKAGE_NAME_NO_LOGO_INFO = "biometric.testapp.nologoinfo" private const val OP_PACKAGE_NAME_CAN_NOT_BE_FOUND = "can.not.be.found" private const val OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO = "should.use.activiy.logo" @OptIn(ExperimentalCoroutinesApi::class) @SmallTest Loading @@ -120,13 +122,15 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa private val defaultLogoIconFromAppInfo = context.getDrawable(R.drawable.ic_android) private val defaultLogoIconFromActivityInfo = context.getDrawable(R.drawable.ic_add) private val defaultLogoIconWithBadge = context.getDrawable(R.drawable.ic_alarm) private val logoResFromApp = R.drawable.ic_cake private val logoDrawableFromAppRes = context.getDrawable(logoResFromApp) private val logoBitmapFromApp = Bitmap.createBitmap(400, 400, Bitmap.Config.RGB_565) private val defaultLogoDescriptionFromAppInfo = "Test Android App" private val defaultLogoDescriptionFromActivityInfo = "Test Coke App" private val defaultLogoDescriptionWithBadge = "Work app" private val logoDescriptionFromApp = "Test Cake App" private val packageNameForLogoWithOverrides = "should.use.overridden.logo" private val authInteractionProperties = AuthInteractionProperties() /** Prompt panel size padding */ Loading Loading @@ -173,55 +177,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa @Before fun setup() { // Set up default logo info and app customized info whenever(kosmos.packageManager.getApplicationInfo(eq(OP_PACKAGE_NAME_NO_ICON), anyInt())) .thenReturn(applicationInfoNoIconOrDescription) whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_WITH_APP_LOGO), anyInt(), ) ) .thenReturn(applicationInfoWithIconAndDescription) whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO), anyInt(), ) ) .thenReturn(applicationInfoWithIconAndDescription) whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_CAN_NOT_BE_FOUND), anyInt(), ) ) .thenThrow(NameNotFoundException()) whenever(kosmos.packageManager.getActivityInfo(any(), anyInt())).thenReturn(activityInfo) whenever(kosmos.iconProvider.getIcon(activityInfo)) .thenReturn(defaultLogoIconFromActivityInfo) whenever(activityInfo.loadLabel(kosmos.packageManager)) .thenReturn(defaultLogoDescriptionFromActivityInfo) whenever(kosmos.packageManager.getApplicationIcon(applicationInfoWithIconAndDescription)) .thenReturn(defaultLogoIconFromAppInfo) whenever(kosmos.packageManager.getApplicationLabel(applicationInfoWithIconAndDescription)) .thenReturn(defaultLogoDescriptionFromAppInfo) whenever(kosmos.packageManager.getApplicationIcon(applicationInfoNoIconOrDescription)) .thenReturn(null) whenever(kosmos.packageManager.getApplicationLabel(applicationInfoNoIconOrDescription)) .thenReturn("") whenever(kosmos.packageManager.getUserBadgedIcon(any(), any())).then { it.getArgument(0) } whenever(kosmos.packageManager.getUserBadgedLabel(any(), any())).then { it.getArgument(0) } context.setMockPackageManager(kosmos.packageManager) overrideResource(logoResFromApp, logoDrawableFromAppRes) overrideResource( R.array.config_useActivityLogoForBiometricPrompt, arrayOf(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO), ) setupLogo() overrideResource(R.dimen.biometric_dialog_fingerprint_icon_width, mockFingerprintIconWidth) overrideResource( R.dimen.biometric_dialog_fingerprint_icon_height, Loading Loading @@ -264,6 +220,74 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa .build() } private fun setupLogo() { // Set up app customized logo overrideResource(logoResFromApp, logoDrawableFromAppRes) // Set up when activity info should be used overrideResource( R.array.config_useActivityLogoForBiometricPrompt, arrayOf(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO), ) whenever(kosmos.packageManager.getActivityInfo(any(), anyInt())).thenReturn(activityInfo) whenever(kosmos.iconProvider.getIcon(activityInfo)) .thenReturn(defaultLogoIconFromActivityInfo) whenever(activityInfo.loadLabel(kosmos.packageManager)) .thenReturn(defaultLogoDescriptionFromActivityInfo) // Set up when application info should be used for default logo whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_WITH_APP_LOGO), anyInt(), ) ) .thenReturn(applicationInfoWithIconAndDescription) whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO), anyInt(), ) ) .thenReturn(applicationInfoWithIconAndDescription) whenever(kosmos.packageManager.getApplicationIcon(applicationInfoWithIconAndDescription)) .thenReturn(defaultLogoIconFromAppInfo) whenever(kosmos.packageManager.getApplicationLabel(applicationInfoWithIconAndDescription)) .thenReturn(defaultLogoDescriptionFromAppInfo) // Set up when package name cannot but found whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_CAN_NOT_BE_FOUND), anyInt(), ) ) .thenThrow(NameNotFoundException()) // Set up when no default logo from application info whenever( kosmos.packageManager.getApplicationInfo(eq(OP_PACKAGE_NAME_NO_LOGO_INFO), anyInt()) ) .thenReturn(applicationInfoNoIconOrDescription) whenever(kosmos.packageManager.getApplicationIcon(applicationInfoNoIconOrDescription)) .thenReturn(null) whenever(kosmos.packageManager.getApplicationLabel(applicationInfoNoIconOrDescription)) .thenReturn("") // Set up work badge whenever(kosmos.packageManager.getUserBadgedIcon(any(), eq(UserHandle.of(USER_ID)))).then { it.getArgument(0) } whenever(kosmos.packageManager.getUserBadgedLabel(any(), eq(UserHandle.of(USER_ID)))).then { it.getArgument(0) } whenever(kosmos.packageManager.getUserBadgedIcon(any(), eq(UserHandle.of(WORK_USER_ID)))) .then { defaultLogoIconWithBadge } whenever(kosmos.packageManager.getUserBadgedLabel(any(), eq(UserHandle.of(WORK_USER_ID)))) .then { defaultLogoDescriptionWithBadge } context.setMockPackageManager(kosmos.packageManager) } @Test fun start_idle_and_show_authenticating() = runGenericTest(doNotStart = true) { Loading Loading @@ -1520,6 +1544,16 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isNull() assertThat(logoInfo!!.second).isEqualTo("") } @Test fun logo_defaultIsNull() = runGenericTest(packageName = OP_PACKAGE_NAME_NO_LOGO_INFO) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isNull() assertThat(logoInfo!!.second).isEqualTo("") } @Test Loading @@ -1527,32 +1561,39 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa runGenericTest(packageName = OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() // 1. PM.getApplicationInfo(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO) is set to return // applicationInfoWithIconAndDescription with "defaultLogoIconFromAppInfo", // 2. iconProvider.getIcon(activityInfo) is set to return // "defaultLogoIconFromActivityInfo" // For the apps with OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO, 2 should be called instead of 1 assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isEqualTo(defaultLogoIconFromActivityInfo) // 1. PM.getApplicationInfo(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO) is set to return // applicationInfoWithIconAndDescription with "defaultLogoDescriptionFromAppInfo", // 2. activityInfo.loadLabel() is set to return defaultLogoDescriptionFromActivityInfo // For the apps with OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO, 2 should be called instead of 1 assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionFromActivityInfo) } @Test fun logo_defaultIsNull() = runGenericTest(packageName = OP_PACKAGE_NAME_NO_ICON) { fun logo_defaultFromApplicationInfo() = runGenericTest { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isNull() assertThat(logoInfo!!.first).isEqualTo(defaultLogoIconFromAppInfo) assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionFromAppInfo) } @Test fun logo_default() = runGenericTest { fun logo_defaultWithWorkBadge() = runGenericTest(userId = WORK_USER_ID) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isEqualTo(defaultLogoIconFromAppInfo) assertThat(logoInfo!!.first).isEqualTo(defaultLogoIconWithBadge) assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionWithBadge) } @Test fun logo_resSetByApp() = fun logoRes_setByApp() = runGenericTest(logoRes = logoResFromApp) { val expectedBitmap = context.getDrawable(logoResFromApp).toBitmap() val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) Loading @@ -1561,43 +1602,12 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test fun logo_bitmapSetByApp() = fun logoBitmap_setByApp() = runGenericTest(logoBitmap = logoBitmapFromApp) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat((logoInfo!!.first as BitmapDrawable).bitmap).isEqualTo(logoBitmapFromApp) } @Test fun logoDescription_emptyIfPkgNameNotFound() = runGenericTest(packageName = OP_PACKAGE_NAME_CAN_NOT_BE_FOUND) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo!!.second).isEqualTo("") } @Test fun logoDescription_defaultFromActivityInfo() = runGenericTest(packageName = OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) // 1. PM.getApplicationInfo(packageNameForLogoWithOverrides) is set to return // applicationInfoWithIconAndDescription with defaultLogoDescription, // 2. activityInfo.loadLabel() is set to return defaultLogoDescriptionWithOverrides // For the apps with packageNameForLogoWithOverrides, 2 should be called instead of 1 assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionFromActivityInfo) } @Test fun logoDescription_defaultIsEmpty() = runGenericTest(packageName = OP_PACKAGE_NAME_NO_ICON) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo!!.second).isEqualTo("") } @Test fun logoDescription_default() = runGenericTest { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionFromAppInfo) } @Test fun logoDescription_setByApp() = runGenericTest(logoDescription = logoDescriptionFromApp) { Loading Loading @@ -1766,6 +1776,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa logoBitmap: Bitmap? = null, logoDescription: String? = null, packageName: String = OP_PACKAGE_NAME_WITH_APP_LOGO, userId: Int = USER_ID, block: suspend TestScope.() -> Unit, ) { val topActivity = ComponentName(packageName, "test app") Loading @@ -1785,6 +1796,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa logoBitmapFromApp = if (logoRes != 0) logoDrawableFromAppRes.toBitmap() else logoBitmap, logoDescriptionFromApp = logoDescription, packageName = packageName, userId = userId, ) kosmos.biometricStatusRepository.setFingerprintAcquiredStatus( Loading Loading @@ -2010,6 +2022,7 @@ private fun PromptSelectorInteractor.initializePrompt( logoBitmapFromApp: Bitmap? = null, logoDescriptionFromApp: String? = null, packageName: String = OP_PACKAGE_NAME_WITH_APP_LOGO, userId: Int = USER_ID, ) { val info = PromptInfo().apply { Loading @@ -2028,7 +2041,7 @@ private fun PromptSelectorInteractor.initializePrompt( setPrompt( info, USER_ID, userId, REQUEST_ID, BiometricModalities(fingerprintProperties = fingerprint, faceProperties = face), CHALLENGE, Loading packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +20 −27 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.util.Log import android.util.RotationUtils import android.view.HapticFeedbackConstants import android.view.MotionEvent import com.android.app.tracing.coroutines.launchTraced as launch import com.android.keyguard.AuthInteractionProperties import com.android.launcher3.icons.IconProvider import com.android.systemui.Flags.msdlFeedback Loading Loading @@ -71,7 +72,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import com.android.app.tracing.coroutines.launchTraced as launch /** ViewModel for BiometricPrompt. */ class PromptViewModel Loading Loading @@ -973,7 +973,7 @@ constructor( /** * The order of getting logo icon/description is: * 1. If the app sets customized icon/description, use the passed-in value * 2. If shouldShowLogoWithOverrides(), use activityInfo to get icon/description * 2. If shouldUseActivityLogo(), use activityInfo to get icon/description * 3. Otherwise, use applicationInfo to get icon/description */ private fun Context.getUserBadgedLogoInfo( Loading @@ -981,6 +981,7 @@ private fun Context.getUserBadgedLogoInfo( iconProvider: IconProvider, activityTaskManager: ActivityTaskManager, ): Pair<Drawable?, String> { // If the app sets customized icon/description, use the passed-in value directly var icon: Drawable? = if (prompt.logoBitmap != null) BitmapDrawable(resources, prompt.logoBitmap) else null var label = prompt.logoDescription ?: "" Loading @@ -993,36 +994,28 @@ private fun Context.getUserBadgedLogoInfo( if (componentName != null && shouldUseActivityLogo(componentName)) { val activityInfo = getActivityInfo(componentName) if (activityInfo != null) { if (icon == null) { icon = iconProvider.getIcon(activityInfo) } if (label.isEmpty()) { label = activityInfo.loadLabel(packageManager).toString() } icon = icon ?: iconProvider.getIcon(activityInfo) label = label.ifEmpty { activityInfo.loadLabel(packageManager).toString() } } } if (icon != null && label.isNotEmpty()) { return Pair(icon, label) } // Use applicationInfo for other cases if (icon == null || label.isEmpty()) { val appInfo = prompt.getApplicationInfo(this, componentName) if (appInfo == null) { Log.w(PromptViewModel.TAG, "Cannot find app logo for package $opPackageName") if (appInfo != null) { icon = icon ?: packageManager.getApplicationIcon(appInfo) label = label.ifEmpty { packageManager.getApplicationLabel(appInfo).toString() } } else { if (icon == null) { icon = packageManager.getApplicationIcon(appInfo) } if (label.isEmpty()) { label = packageManager .getUserBadgedLabel( packageManager.getApplicationLabel(appInfo), UserHandle.of(userId), ) .toString() Log.w(PromptViewModel.TAG, "Cannot find app logo for package $opPackageName") } } // Add user badge val userHandle = UserHandle.of(prompt.userInfo.userId) if (label.isNotEmpty()) { label = packageManager.getUserBadgedLabel(label, userHandle).toString() } icon = icon?.let { packageManager.getUserBadgedIcon(it, userHandle) } return Pair(icon, label) } Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +109 −96 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.hardware.biometrics.PromptVerticalListContentView import android.hardware.face.FaceSensorPropertiesInternal import android.hardware.fingerprint.FingerprintSensorProperties import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.os.UserHandle import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.HapticFeedbackConstants Loading Loading @@ -97,13 +98,14 @@ import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters private const val USER_ID = 4 private const val WORK_USER_ID = 100 private const val REQUEST_ID = 4L private const val CHALLENGE = 2L private const val DELAY = 1000L private const val OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO = "should.use.activiy.logo" private const val OP_PACKAGE_NAME_WITH_APP_LOGO = "biometric.testapp" private const val OP_PACKAGE_NAME_NO_ICON = "biometric.testapp.noicon" private const val OP_PACKAGE_NAME_NO_LOGO_INFO = "biometric.testapp.nologoinfo" private const val OP_PACKAGE_NAME_CAN_NOT_BE_FOUND = "can.not.be.found" private const val OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO = "should.use.activiy.logo" @OptIn(ExperimentalCoroutinesApi::class) @SmallTest Loading @@ -120,13 +122,15 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa private val defaultLogoIconFromAppInfo = context.getDrawable(R.drawable.ic_android) private val defaultLogoIconFromActivityInfo = context.getDrawable(R.drawable.ic_add) private val defaultLogoIconWithBadge = context.getDrawable(R.drawable.ic_alarm) private val logoResFromApp = R.drawable.ic_cake private val logoDrawableFromAppRes = context.getDrawable(logoResFromApp) private val logoBitmapFromApp = Bitmap.createBitmap(400, 400, Bitmap.Config.RGB_565) private val defaultLogoDescriptionFromAppInfo = "Test Android App" private val defaultLogoDescriptionFromActivityInfo = "Test Coke App" private val defaultLogoDescriptionWithBadge = "Work app" private val logoDescriptionFromApp = "Test Cake App" private val packageNameForLogoWithOverrides = "should.use.overridden.logo" private val authInteractionProperties = AuthInteractionProperties() /** Prompt panel size padding */ Loading Loading @@ -173,55 +177,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa @Before fun setup() { // Set up default logo info and app customized info whenever(kosmos.packageManager.getApplicationInfo(eq(OP_PACKAGE_NAME_NO_ICON), anyInt())) .thenReturn(applicationInfoNoIconOrDescription) whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_WITH_APP_LOGO), anyInt(), ) ) .thenReturn(applicationInfoWithIconAndDescription) whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO), anyInt(), ) ) .thenReturn(applicationInfoWithIconAndDescription) whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_CAN_NOT_BE_FOUND), anyInt(), ) ) .thenThrow(NameNotFoundException()) whenever(kosmos.packageManager.getActivityInfo(any(), anyInt())).thenReturn(activityInfo) whenever(kosmos.iconProvider.getIcon(activityInfo)) .thenReturn(defaultLogoIconFromActivityInfo) whenever(activityInfo.loadLabel(kosmos.packageManager)) .thenReturn(defaultLogoDescriptionFromActivityInfo) whenever(kosmos.packageManager.getApplicationIcon(applicationInfoWithIconAndDescription)) .thenReturn(defaultLogoIconFromAppInfo) whenever(kosmos.packageManager.getApplicationLabel(applicationInfoWithIconAndDescription)) .thenReturn(defaultLogoDescriptionFromAppInfo) whenever(kosmos.packageManager.getApplicationIcon(applicationInfoNoIconOrDescription)) .thenReturn(null) whenever(kosmos.packageManager.getApplicationLabel(applicationInfoNoIconOrDescription)) .thenReturn("") whenever(kosmos.packageManager.getUserBadgedIcon(any(), any())).then { it.getArgument(0) } whenever(kosmos.packageManager.getUserBadgedLabel(any(), any())).then { it.getArgument(0) } context.setMockPackageManager(kosmos.packageManager) overrideResource(logoResFromApp, logoDrawableFromAppRes) overrideResource( R.array.config_useActivityLogoForBiometricPrompt, arrayOf(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO), ) setupLogo() overrideResource(R.dimen.biometric_dialog_fingerprint_icon_width, mockFingerprintIconWidth) overrideResource( R.dimen.biometric_dialog_fingerprint_icon_height, Loading Loading @@ -264,6 +220,74 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa .build() } private fun setupLogo() { // Set up app customized logo overrideResource(logoResFromApp, logoDrawableFromAppRes) // Set up when activity info should be used overrideResource( R.array.config_useActivityLogoForBiometricPrompt, arrayOf(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO), ) whenever(kosmos.packageManager.getActivityInfo(any(), anyInt())).thenReturn(activityInfo) whenever(kosmos.iconProvider.getIcon(activityInfo)) .thenReturn(defaultLogoIconFromActivityInfo) whenever(activityInfo.loadLabel(kosmos.packageManager)) .thenReturn(defaultLogoDescriptionFromActivityInfo) // Set up when application info should be used for default logo whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_WITH_APP_LOGO), anyInt(), ) ) .thenReturn(applicationInfoWithIconAndDescription) whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO), anyInt(), ) ) .thenReturn(applicationInfoWithIconAndDescription) whenever(kosmos.packageManager.getApplicationIcon(applicationInfoWithIconAndDescription)) .thenReturn(defaultLogoIconFromAppInfo) whenever(kosmos.packageManager.getApplicationLabel(applicationInfoWithIconAndDescription)) .thenReturn(defaultLogoDescriptionFromAppInfo) // Set up when package name cannot but found whenever( kosmos.packageManager.getApplicationInfo( eq(OP_PACKAGE_NAME_CAN_NOT_BE_FOUND), anyInt(), ) ) .thenThrow(NameNotFoundException()) // Set up when no default logo from application info whenever( kosmos.packageManager.getApplicationInfo(eq(OP_PACKAGE_NAME_NO_LOGO_INFO), anyInt()) ) .thenReturn(applicationInfoNoIconOrDescription) whenever(kosmos.packageManager.getApplicationIcon(applicationInfoNoIconOrDescription)) .thenReturn(null) whenever(kosmos.packageManager.getApplicationLabel(applicationInfoNoIconOrDescription)) .thenReturn("") // Set up work badge whenever(kosmos.packageManager.getUserBadgedIcon(any(), eq(UserHandle.of(USER_ID)))).then { it.getArgument(0) } whenever(kosmos.packageManager.getUserBadgedLabel(any(), eq(UserHandle.of(USER_ID)))).then { it.getArgument(0) } whenever(kosmos.packageManager.getUserBadgedIcon(any(), eq(UserHandle.of(WORK_USER_ID)))) .then { defaultLogoIconWithBadge } whenever(kosmos.packageManager.getUserBadgedLabel(any(), eq(UserHandle.of(WORK_USER_ID)))) .then { defaultLogoDescriptionWithBadge } context.setMockPackageManager(kosmos.packageManager) } @Test fun start_idle_and_show_authenticating() = runGenericTest(doNotStart = true) { Loading Loading @@ -1520,6 +1544,16 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isNull() assertThat(logoInfo!!.second).isEqualTo("") } @Test fun logo_defaultIsNull() = runGenericTest(packageName = OP_PACKAGE_NAME_NO_LOGO_INFO) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isNull() assertThat(logoInfo!!.second).isEqualTo("") } @Test Loading @@ -1527,32 +1561,39 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa runGenericTest(packageName = OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() // 1. PM.getApplicationInfo(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO) is set to return // applicationInfoWithIconAndDescription with "defaultLogoIconFromAppInfo", // 2. iconProvider.getIcon(activityInfo) is set to return // "defaultLogoIconFromActivityInfo" // For the apps with OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO, 2 should be called instead of 1 assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isEqualTo(defaultLogoIconFromActivityInfo) // 1. PM.getApplicationInfo(OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO) is set to return // applicationInfoWithIconAndDescription with "defaultLogoDescriptionFromAppInfo", // 2. activityInfo.loadLabel() is set to return defaultLogoDescriptionFromActivityInfo // For the apps with OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO, 2 should be called instead of 1 assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionFromActivityInfo) } @Test fun logo_defaultIsNull() = runGenericTest(packageName = OP_PACKAGE_NAME_NO_ICON) { fun logo_defaultFromApplicationInfo() = runGenericTest { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isNull() assertThat(logoInfo!!.first).isEqualTo(defaultLogoIconFromAppInfo) assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionFromAppInfo) } @Test fun logo_default() = runGenericTest { fun logo_defaultWithWorkBadge() = runGenericTest(userId = WORK_USER_ID) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isEqualTo(defaultLogoIconFromAppInfo) assertThat(logoInfo!!.first).isEqualTo(defaultLogoIconWithBadge) assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionWithBadge) } @Test fun logo_resSetByApp() = fun logoRes_setByApp() = runGenericTest(logoRes = logoResFromApp) { val expectedBitmap = context.getDrawable(logoResFromApp).toBitmap() val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) Loading @@ -1561,43 +1602,12 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test fun logo_bitmapSetByApp() = fun logoBitmap_setByApp() = runGenericTest(logoBitmap = logoBitmapFromApp) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat((logoInfo!!.first as BitmapDrawable).bitmap).isEqualTo(logoBitmapFromApp) } @Test fun logoDescription_emptyIfPkgNameNotFound() = runGenericTest(packageName = OP_PACKAGE_NAME_CAN_NOT_BE_FOUND) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo!!.second).isEqualTo("") } @Test fun logoDescription_defaultFromActivityInfo() = runGenericTest(packageName = OP_PACKAGE_NAME_WITH_ACTIVITY_LOGO) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) // 1. PM.getApplicationInfo(packageNameForLogoWithOverrides) is set to return // applicationInfoWithIconAndDescription with defaultLogoDescription, // 2. activityInfo.loadLabel() is set to return defaultLogoDescriptionWithOverrides // For the apps with packageNameForLogoWithOverrides, 2 should be called instead of 1 assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionFromActivityInfo) } @Test fun logoDescription_defaultIsEmpty() = runGenericTest(packageName = OP_PACKAGE_NAME_NO_ICON) { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo!!.second).isEqualTo("") } @Test fun logoDescription_default() = runGenericTest { val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionFromAppInfo) } @Test fun logoDescription_setByApp() = runGenericTest(logoDescription = logoDescriptionFromApp) { Loading Loading @@ -1766,6 +1776,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa logoBitmap: Bitmap? = null, logoDescription: String? = null, packageName: String = OP_PACKAGE_NAME_WITH_APP_LOGO, userId: Int = USER_ID, block: suspend TestScope.() -> Unit, ) { val topActivity = ComponentName(packageName, "test app") Loading @@ -1785,6 +1796,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa logoBitmapFromApp = if (logoRes != 0) logoDrawableFromAppRes.toBitmap() else logoBitmap, logoDescriptionFromApp = logoDescription, packageName = packageName, userId = userId, ) kosmos.biometricStatusRepository.setFingerprintAcquiredStatus( Loading Loading @@ -2010,6 +2022,7 @@ private fun PromptSelectorInteractor.initializePrompt( logoBitmapFromApp: Bitmap? = null, logoDescriptionFromApp: String? = null, packageName: String = OP_PACKAGE_NAME_WITH_APP_LOGO, userId: Int = USER_ID, ) { val info = PromptInfo().apply { Loading @@ -2028,7 +2041,7 @@ private fun PromptSelectorInteractor.initializePrompt( setPrompt( info, USER_ID, userId, REQUEST_ID, BiometricModalities(fingerprintProperties = fingerprint, faceProperties = face), CHALLENGE, Loading
packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +20 −27 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.util.Log import android.util.RotationUtils import android.view.HapticFeedbackConstants import android.view.MotionEvent import com.android.app.tracing.coroutines.launchTraced as launch import com.android.keyguard.AuthInteractionProperties import com.android.launcher3.icons.IconProvider import com.android.systemui.Flags.msdlFeedback Loading Loading @@ -71,7 +72,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import com.android.app.tracing.coroutines.launchTraced as launch /** ViewModel for BiometricPrompt. */ class PromptViewModel Loading Loading @@ -973,7 +973,7 @@ constructor( /** * The order of getting logo icon/description is: * 1. If the app sets customized icon/description, use the passed-in value * 2. If shouldShowLogoWithOverrides(), use activityInfo to get icon/description * 2. If shouldUseActivityLogo(), use activityInfo to get icon/description * 3. Otherwise, use applicationInfo to get icon/description */ private fun Context.getUserBadgedLogoInfo( Loading @@ -981,6 +981,7 @@ private fun Context.getUserBadgedLogoInfo( iconProvider: IconProvider, activityTaskManager: ActivityTaskManager, ): Pair<Drawable?, String> { // If the app sets customized icon/description, use the passed-in value directly var icon: Drawable? = if (prompt.logoBitmap != null) BitmapDrawable(resources, prompt.logoBitmap) else null var label = prompt.logoDescription ?: "" Loading @@ -993,36 +994,28 @@ private fun Context.getUserBadgedLogoInfo( if (componentName != null && shouldUseActivityLogo(componentName)) { val activityInfo = getActivityInfo(componentName) if (activityInfo != null) { if (icon == null) { icon = iconProvider.getIcon(activityInfo) } if (label.isEmpty()) { label = activityInfo.loadLabel(packageManager).toString() } icon = icon ?: iconProvider.getIcon(activityInfo) label = label.ifEmpty { activityInfo.loadLabel(packageManager).toString() } } } if (icon != null && label.isNotEmpty()) { return Pair(icon, label) } // Use applicationInfo for other cases if (icon == null || label.isEmpty()) { val appInfo = prompt.getApplicationInfo(this, componentName) if (appInfo == null) { Log.w(PromptViewModel.TAG, "Cannot find app logo for package $opPackageName") if (appInfo != null) { icon = icon ?: packageManager.getApplicationIcon(appInfo) label = label.ifEmpty { packageManager.getApplicationLabel(appInfo).toString() } } else { if (icon == null) { icon = packageManager.getApplicationIcon(appInfo) } if (label.isEmpty()) { label = packageManager .getUserBadgedLabel( packageManager.getApplicationLabel(appInfo), UserHandle.of(userId), ) .toString() Log.w(PromptViewModel.TAG, "Cannot find app logo for package $opPackageName") } } // Add user badge val userHandle = UserHandle.of(prompt.userInfo.userId) if (label.isNotEmpty()) { label = packageManager.getUserBadgedLabel(label, userHandle).toString() } icon = icon?.let { packageManager.getUserBadgedIcon(it, userHandle) } return Pair(icon, label) } Loading