|
|
|
|
@@ -19,6 +19,8 @@ package com.android.keyguard
|
|
|
|
|
import android.testing.AndroidTestingRunner
|
|
|
|
|
import android.testing.TestableLooper
|
|
|
|
|
import android.view.View
|
|
|
|
|
import androidx.constraintlayout.widget.ConstraintLayout
|
|
|
|
|
import androidx.constraintlayout.widget.ConstraintSet
|
|
|
|
|
import androidx.test.filters.SmallTest
|
|
|
|
|
import com.android.internal.util.LatencyTracker
|
|
|
|
|
import com.android.internal.widget.LockPatternUtils
|
|
|
|
|
@@ -32,6 +34,8 @@ import com.android.systemui.flags.Flags
|
|
|
|
|
import com.android.systemui.statusbar.policy.DevicePostureController
|
|
|
|
|
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
|
|
|
|
|
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED
|
|
|
|
|
import com.android.systemui.util.mockito.whenever
|
|
|
|
|
import com.google.common.truth.Truth.assertThat
|
|
|
|
|
import org.junit.Before
|
|
|
|
|
import org.junit.Test
|
|
|
|
|
import org.junit.runner.RunWith
|
|
|
|
|
@@ -51,7 +55,10 @@ import org.mockito.MockitoAnnotations
|
|
|
|
|
@RunWith(AndroidTestingRunner::class)
|
|
|
|
|
@TestableLooper.RunWithLooper
|
|
|
|
|
class KeyguardPinViewControllerTest : SysuiTestCase() {
|
|
|
|
|
@Mock private lateinit var keyguardPinView: KeyguardPINView
|
|
|
|
|
|
|
|
|
|
private lateinit var objectKeyguardPINView: KeyguardPINView
|
|
|
|
|
|
|
|
|
|
@Mock private lateinit var mockKeyguardPinView: KeyguardPINView
|
|
|
|
|
|
|
|
|
|
@Mock private lateinit var keyguardMessageArea: BouncerKeyguardMessageArea
|
|
|
|
|
|
|
|
|
|
@@ -83,64 +90,73 @@ class KeyguardPinViewControllerTest : SysuiTestCase() {
|
|
|
|
|
@Mock lateinit var deleteButton: NumPadButton
|
|
|
|
|
@Mock lateinit var enterButton: View
|
|
|
|
|
|
|
|
|
|
private lateinit var pinViewController: KeyguardPinViewController
|
|
|
|
|
|
|
|
|
|
@Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
|
|
|
|
|
|
|
|
|
|
@Before
|
|
|
|
|
fun setup() {
|
|
|
|
|
MockitoAnnotations.initMocks(this)
|
|
|
|
|
Mockito.`when`(keyguardPinView.requireViewById<View>(R.id.bouncer_message_area))
|
|
|
|
|
Mockito.`when`(mockKeyguardPinView.requireViewById<View>(R.id.bouncer_message_area))
|
|
|
|
|
.thenReturn(keyguardMessageArea)
|
|
|
|
|
Mockito.`when`(
|
|
|
|
|
keyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea::class.java))
|
|
|
|
|
)
|
|
|
|
|
.thenReturn(keyguardMessageAreaController)
|
|
|
|
|
`when`(keyguardPinView.passwordTextViewId).thenReturn(R.id.pinEntry)
|
|
|
|
|
`when`(keyguardPinView.findViewById<PasswordTextView>(R.id.pinEntry))
|
|
|
|
|
`when`(mockKeyguardPinView.passwordTextViewId).thenReturn(R.id.pinEntry)
|
|
|
|
|
`when`(mockKeyguardPinView.findViewById<PasswordTextView>(R.id.pinEntry))
|
|
|
|
|
.thenReturn(passwordTextView)
|
|
|
|
|
`when`(keyguardPinView.resources).thenReturn(context.resources)
|
|
|
|
|
`when`(keyguardPinView.findViewById<NumPadButton>(R.id.delete_button))
|
|
|
|
|
`when`(mockKeyguardPinView.resources).thenReturn(context.resources)
|
|
|
|
|
`when`(mockKeyguardPinView.findViewById<NumPadButton>(R.id.delete_button))
|
|
|
|
|
.thenReturn(deleteButton)
|
|
|
|
|
`when`(keyguardPinView.findViewById<View>(R.id.key_enter)).thenReturn(enterButton)
|
|
|
|
|
`when`(mockKeyguardPinView.findViewById<View>(R.id.key_enter)).thenReturn(enterButton)
|
|
|
|
|
// For posture tests:
|
|
|
|
|
`when`(keyguardPinView.buttons).thenReturn(arrayOf())
|
|
|
|
|
`when`(mockKeyguardPinView.buttons).thenReturn(arrayOf())
|
|
|
|
|
`when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
|
|
|
|
|
|
|
|
|
|
pinViewController =
|
|
|
|
|
KeyguardPinViewController(
|
|
|
|
|
keyguardPinView,
|
|
|
|
|
keyguardUpdateMonitor,
|
|
|
|
|
securityMode,
|
|
|
|
|
lockPatternUtils,
|
|
|
|
|
mKeyguardSecurityCallback,
|
|
|
|
|
keyguardMessageAreaControllerFactory,
|
|
|
|
|
mLatencyTracker,
|
|
|
|
|
liftToActivateListener,
|
|
|
|
|
mEmergencyButtonController,
|
|
|
|
|
falsingCollector,
|
|
|
|
|
postureController,
|
|
|
|
|
featureFlags
|
|
|
|
|
)
|
|
|
|
|
objectKeyguardPINView =
|
|
|
|
|
View.inflate(mContext, R.layout.keyguard_pin_view, null)
|
|
|
|
|
.findViewById(R.id.keyguard_pin_view) as KeyguardPINView
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun constructPinViewController(
|
|
|
|
|
mKeyguardPinView: KeyguardPINView
|
|
|
|
|
): KeyguardPinViewController {
|
|
|
|
|
return KeyguardPinViewController(
|
|
|
|
|
mKeyguardPinView,
|
|
|
|
|
keyguardUpdateMonitor,
|
|
|
|
|
securityMode,
|
|
|
|
|
lockPatternUtils,
|
|
|
|
|
mKeyguardSecurityCallback,
|
|
|
|
|
keyguardMessageAreaControllerFactory,
|
|
|
|
|
mLatencyTracker,
|
|
|
|
|
liftToActivateListener,
|
|
|
|
|
mEmergencyButtonController,
|
|
|
|
|
falsingCollector,
|
|
|
|
|
postureController,
|
|
|
|
|
featureFlags
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
fun onViewAttached_deviceHalfFolded_propagatedToPinView() {
|
|
|
|
|
`when`(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED)
|
|
|
|
|
fun onViewAttached_deviceHalfFolded_propagatedToPatternView() {
|
|
|
|
|
val pinViewController = constructPinViewController(objectKeyguardPINView)
|
|
|
|
|
overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f)
|
|
|
|
|
whenever(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED)
|
|
|
|
|
|
|
|
|
|
pinViewController.onViewAttached()
|
|
|
|
|
|
|
|
|
|
verify(keyguardPinView).onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED)
|
|
|
|
|
assertThat(getPinTopGuideline()).isEqualTo(getHalfOpenedBouncerHeightRatio())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
fun onDevicePostureChanged_deviceHalfFolded_propagatedToPinView() {
|
|
|
|
|
`when`(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED)
|
|
|
|
|
fun onDevicePostureChanged_deviceOpened_propagatedToPatternView() {
|
|
|
|
|
val pinViewController = constructPinViewController(objectKeyguardPINView)
|
|
|
|
|
overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f)
|
|
|
|
|
|
|
|
|
|
whenever(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED)
|
|
|
|
|
pinViewController.onViewAttached()
|
|
|
|
|
|
|
|
|
|
// Verify view begins in posture state DEVICE_POSTURE_HALF_OPENED
|
|
|
|
|
pinViewController.onViewAttached()
|
|
|
|
|
|
|
|
|
|
verify(keyguardPinView).onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED)
|
|
|
|
|
assertThat(getPinTopGuideline()).isEqualTo(getHalfOpenedBouncerHeightRatio())
|
|
|
|
|
|
|
|
|
|
// Simulate posture change to state DEVICE_POSTURE_OPENED with callback
|
|
|
|
|
verify(postureController).addCallback(postureCallbackCaptor.capture())
|
|
|
|
|
@@ -148,31 +164,57 @@ class KeyguardPinViewControllerTest : SysuiTestCase() {
|
|
|
|
|
postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED)
|
|
|
|
|
|
|
|
|
|
// Verify view is now in posture state DEVICE_POSTURE_OPENED
|
|
|
|
|
verify(keyguardPinView).onDevicePostureChanged(DEVICE_POSTURE_OPENED)
|
|
|
|
|
assertThat(getPinTopGuideline()).isNotEqualTo(getHalfOpenedBouncerHeightRatio())
|
|
|
|
|
|
|
|
|
|
// Simulate posture change to same state with callback
|
|
|
|
|
postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED)
|
|
|
|
|
|
|
|
|
|
// Verify view is still in posture state DEVICE_POSTURE_OPENED
|
|
|
|
|
assertThat(getPinTopGuideline()).isNotEqualTo(getHalfOpenedBouncerHeightRatio())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun getPinTopGuideline(): Float {
|
|
|
|
|
val cs = ConstraintSet()
|
|
|
|
|
val container = objectKeyguardPINView.findViewById(R.id.pin_container) as ConstraintLayout
|
|
|
|
|
cs.clone(container)
|
|
|
|
|
return cs.getConstraint(R.id.pin_pad_top_guideline).layout.guidePercent
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun getHalfOpenedBouncerHeightRatio(): Float {
|
|
|
|
|
return mContext.resources.getFloat(R.dimen.half_opened_bouncer_height_ratio)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
fun startAppearAnimation() {
|
|
|
|
|
val pinViewController = constructPinViewController(mockKeyguardPinView)
|
|
|
|
|
|
|
|
|
|
pinViewController.startAppearAnimation()
|
|
|
|
|
|
|
|
|
|
verify(keyguardMessageAreaController)
|
|
|
|
|
.setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
fun startAppearAnimation_withExistingMessage() {
|
|
|
|
|
val pinViewController = constructPinViewController(mockKeyguardPinView)
|
|
|
|
|
Mockito.`when`(keyguardMessageAreaController.message).thenReturn("Unlock to continue.")
|
|
|
|
|
|
|
|
|
|
pinViewController.startAppearAnimation()
|
|
|
|
|
|
|
|
|
|
verify(keyguardMessageAreaController, Mockito.never()).setMessage(anyString(), anyBoolean())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsLessThan5() {
|
|
|
|
|
val pinViewController = constructPinViewController(mockKeyguardPinView)
|
|
|
|
|
`when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true)
|
|
|
|
|
`when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
|
|
|
|
|
`when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true)
|
|
|
|
|
`when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(3)
|
|
|
|
|
`when`(passwordTextView.text).thenReturn("")
|
|
|
|
|
|
|
|
|
|
pinViewController.startAppearAnimation()
|
|
|
|
|
|
|
|
|
|
verify(deleteButton).visibility = View.INVISIBLE
|
|
|
|
|
verify(enterButton).visibility = View.INVISIBLE
|
|
|
|
|
verify(passwordTextView).setUsePinShapes(true)
|
|
|
|
|
@@ -181,12 +223,15 @@ class KeyguardPinViewControllerTest : SysuiTestCase() {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsMoreThan5() {
|
|
|
|
|
val pinViewController = constructPinViewController(mockKeyguardPinView)
|
|
|
|
|
`when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true)
|
|
|
|
|
`when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
|
|
|
|
|
`when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true)
|
|
|
|
|
`when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(6)
|
|
|
|
|
`when`(passwordTextView.text).thenReturn("")
|
|
|
|
|
|
|
|
|
|
pinViewController.startAppearAnimation()
|
|
|
|
|
|
|
|
|
|
verify(deleteButton).visibility = View.VISIBLE
|
|
|
|
|
verify(enterButton).visibility = View.VISIBLE
|
|
|
|
|
verify(passwordTextView).setUsePinShapes(true)
|
|
|
|
|
@@ -195,7 +240,10 @@ class KeyguardPinViewControllerTest : SysuiTestCase() {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
fun handleLockout_readsNumberOfErrorAttempts() {
|
|
|
|
|
val pinViewController = constructPinViewController(mockKeyguardPinView)
|
|
|
|
|
|
|
|
|
|
pinViewController.handleAttemptLockout(0)
|
|
|
|
|
|
|
|
|
|
verify(lockPatternUtils).getCurrentFailedPasswordAttempts(anyInt())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|