1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.bouncer.data.factory 18 19 import androidx.test.ext.junit.runners.AndroidJUnit4 20 import androidx.test.filters.SmallTest 21 import com.android.keyguard.KeyguardSecurityModel 22 import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN 23 import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password 24 import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Pattern 25 import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT 26 import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT 27 import com.android.systemui.SysuiTestCase 28 import com.android.systemui.bouncer.shared.model.BouncerMessageModel 29 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository 30 import com.android.systemui.util.mockito.whenever 31 import com.google.common.truth.StringSubject 32 import com.google.common.truth.Truth.assertThat 33 import kotlinx.coroutines.test.TestScope 34 import kotlinx.coroutines.test.runTest 35 import org.junit.Before 36 import org.junit.Test 37 import org.junit.runner.RunWith 38 import org.mockito.Mock 39 import org.mockito.MockitoAnnotations 40 41 @SmallTest 42 @RunWith(AndroidJUnit4::class) 43 class BouncerMessageFactoryTest : SysuiTestCase() { 44 private lateinit var underTest: BouncerMessageFactory 45 46 @Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository 47 48 @Mock private lateinit var securityModel: KeyguardSecurityModel 49 50 private lateinit var testScope: TestScope 51 52 @Before 53 fun setUp() { 54 MockitoAnnotations.initMocks(this) 55 testScope = TestScope() 56 biometricSettingsRepository = FakeBiometricSettingsRepository() 57 underTest = BouncerMessageFactory(biometricSettingsRepository, securityModel) 58 } 59 60 @Test 61 fun bouncerMessages_choosesTheRightMessage_basedOnSecurityModeAndFpAuthIsAllowed() = 62 testScope.runTest { 63 primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = false) 64 .isEqualTo("Enter PIN") 65 primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = true) 66 .isEqualTo("Unlock with PIN or fingerprint") 67 68 primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = false) 69 .isEqualTo("Enter password") 70 primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = true) 71 .isEqualTo("Unlock with password or fingerprint") 72 73 primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = false) 74 .isEqualTo("Draw pattern") 75 primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = true) 76 .isEqualTo("Unlock with pattern or fingerprint") 77 } 78 79 @Test 80 fun bouncerMessages_overridesSecondaryMessageValue() = 81 testScope.runTest { 82 val bouncerMessageModel = 83 bouncerMessageModel( 84 PIN, 85 true, 86 PROMPT_REASON_DEFAULT, 87 secondaryMessageOverride = "face acquisition message" 88 )!! 89 assertThat(context.resources.getString(bouncerMessageModel.message!!.messageResId!!)) 90 .isEqualTo("Unlock with PIN or fingerprint") 91 assertThat(bouncerMessageModel.secondaryMessage!!.message!!) 92 .isEqualTo("face acquisition message") 93 } 94 95 @Test 96 fun bouncerMessages_setsPrimaryAndSecondaryMessage_basedOnSecurityModeAndFpAuthIsAllowed() = 97 testScope.runTest { 98 primaryMessage( 99 PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, 100 mode = PIN, 101 fpAuthAllowed = true 102 ) 103 .isEqualTo("Wrong PIN. Try again.") 104 secondaryMessage( 105 PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, 106 mode = PIN, 107 fpAuthAllowed = true 108 ) 109 .isEqualTo("Or unlock with fingerprint") 110 111 primaryMessage( 112 PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, 113 mode = Password, 114 fpAuthAllowed = true 115 ) 116 .isEqualTo("Wrong password. Try again.") 117 secondaryMessage( 118 PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, 119 mode = Password, 120 fpAuthAllowed = true 121 ) 122 .isEqualTo("Or unlock with fingerprint") 123 124 primaryMessage( 125 PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, 126 mode = Pattern, 127 fpAuthAllowed = true 128 ) 129 .isEqualTo("Wrong pattern. Try again.") 130 secondaryMessage( 131 PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT, 132 mode = Pattern, 133 fpAuthAllowed = true 134 ) 135 .isEqualTo("Or unlock with fingerprint") 136 } 137 138 private fun primaryMessage( 139 reason: Int, 140 mode: KeyguardSecurityModel.SecurityMode, 141 fpAuthAllowed: Boolean 142 ): StringSubject { 143 return assertThat( 144 context.resources.getString( 145 bouncerMessageModel(mode, fpAuthAllowed, reason)!!.message!!.messageResId!! 146 ) 147 )!! 148 } 149 150 private fun secondaryMessage( 151 reason: Int, 152 mode: KeyguardSecurityModel.SecurityMode, 153 fpAuthAllowed: Boolean 154 ): StringSubject { 155 return assertThat( 156 context.resources.getString( 157 bouncerMessageModel(mode, fpAuthAllowed, reason)!!.secondaryMessage!!.messageResId!! 158 ) 159 )!! 160 } 161 162 private fun bouncerMessageModel( 163 mode: KeyguardSecurityModel.SecurityMode, 164 fpAuthAllowed: Boolean, 165 reason: Int, 166 secondaryMessageOverride: String? = null, 167 ): BouncerMessageModel? { 168 whenever(securityModel.getSecurityMode(0)).thenReturn(mode) 169 biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(fpAuthAllowed) 170 171 return underTest.createFromPromptReason( 172 reason, 173 0, 174 secondaryMsgOverride = secondaryMessageOverride 175 ) 176 } 177 } 178