1 /* 2 * Copyright (C) 2020 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.keyguard 18 19 import android.testing.TestableLooper 20 import android.view.View 21 import androidx.constraintlayout.widget.ConstraintLayout 22 import androidx.constraintlayout.widget.ConstraintSet 23 import androidx.test.ext.junit.runners.AndroidJUnit4 24 import androidx.test.filters.SmallTest 25 import com.android.internal.util.LatencyTracker 26 import com.android.internal.widget.LockPatternUtils 27 import com.android.systemui.Flags as AConfigFlags 28 import com.android.systemui.SysuiTestCase 29 import com.android.systemui.classifier.FalsingCollector 30 import com.android.systemui.classifier.FalsingCollectorFake 31 import com.android.systemui.flags.FakeFeatureFlags 32 import com.android.systemui.flags.Flags 33 import com.android.systemui.res.R 34 import com.android.systemui.statusbar.policy.DevicePostureController 35 import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED 36 import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED 37 import com.android.systemui.user.domain.interactor.SelectedUserInteractor 38 import com.android.systemui.util.mockito.any 39 import com.android.systemui.util.mockito.whenever 40 import com.google.common.truth.Truth.assertThat 41 import org.junit.Before 42 import org.junit.Test 43 import org.junit.runner.RunWith 44 import org.mockito.ArgumentCaptor 45 import org.mockito.ArgumentMatchers.anyBoolean 46 import org.mockito.ArgumentMatchers.anyInt 47 import org.mockito.ArgumentMatchers.anyString 48 import org.mockito.Captor 49 import org.mockito.Mock 50 import org.mockito.Mockito.never 51 import org.mockito.Mockito.reset 52 import org.mockito.Mockito.verify 53 import org.mockito.Mockito.`when` 54 import org.mockito.MockitoAnnotations 55 56 @SmallTest 57 @RunWith(AndroidJUnit4::class) 58 @TestableLooper.RunWithLooper 59 class KeyguardPatternViewControllerTest : SysuiTestCase() { 60 private lateinit var mKeyguardPatternView: KeyguardPatternView 61 62 @Mock private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor 63 64 @Mock private lateinit var mSecurityMode: KeyguardSecurityModel.SecurityMode 65 66 @Mock private lateinit var mLockPatternUtils: LockPatternUtils 67 68 @Mock private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback 69 70 @Mock private lateinit var mLatencyTracker: LatencyTracker 71 private var mFalsingCollector: FalsingCollector = FalsingCollectorFake() 72 73 @Mock private lateinit var mEmergencyButtonController: EmergencyButtonController 74 75 @Mock 76 private lateinit var mKeyguardMessageAreaControllerFactory: 77 KeyguardMessageAreaController.Factory 78 79 @Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor 80 81 @Mock 82 private lateinit var mKeyguardMessageAreaController: 83 KeyguardMessageAreaController<BouncerKeyguardMessageArea> 84 85 @Mock private lateinit var mPostureController: DevicePostureController 86 87 private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController 88 private lateinit var fakeFeatureFlags: FakeFeatureFlags 89 90 @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback> 91 92 @Before setupnull93 fun setup() { 94 MockitoAnnotations.initMocks(this) 95 whenever(mKeyguardMessageAreaControllerFactory.create(any())) 96 .thenReturn(mKeyguardMessageAreaController) 97 fakeFeatureFlags = FakeFeatureFlags() 98 fakeFeatureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false) 99 mKeyguardPatternView = 100 View.inflate(mContext, R.layout.keyguard_pattern_view, null) as KeyguardPatternView 101 mKeyguardPatternView.setIsLockScreenLandscapeEnabled(false) 102 mKeyguardPatternViewController = 103 KeyguardPatternViewController( 104 mKeyguardPatternView, 105 mKeyguardUpdateMonitor, 106 mSecurityMode, 107 mLockPatternUtils, 108 mKeyguardSecurityCallback, 109 mLatencyTracker, 110 mFalsingCollector, 111 mEmergencyButtonController, 112 mKeyguardMessageAreaControllerFactory, 113 mPostureController, 114 fakeFeatureFlags, 115 mSelectedUserInteractor 116 ) 117 mKeyguardPatternView.onAttachedToWindow() 118 } 119 120 @Test onViewAttached_deviceHalfFolded_propagatedToPatternViewnull121 fun onViewAttached_deviceHalfFolded_propagatedToPatternView() { 122 overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f) 123 whenever(mPostureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED) 124 125 mKeyguardPatternViewController.onViewAttached() 126 127 assertThat(getPatternTopGuideline()).isEqualTo(getHalfOpenedBouncerHeightRatio()) 128 } 129 130 @Test onDevicePostureChanged_deviceOpened_propagatedToPatternViewnull131 fun onDevicePostureChanged_deviceOpened_propagatedToPatternView() { 132 overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f) 133 whenever(mPostureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED) 134 135 mKeyguardPatternViewController.onViewAttached() 136 137 // Verify view begins in posture state DEVICE_POSTURE_HALF_OPENED 138 assertThat(getPatternTopGuideline()).isEqualTo(getHalfOpenedBouncerHeightRatio()) 139 140 // Simulate posture change to state DEVICE_POSTURE_OPENED with callback 141 verify(mPostureController).addCallback(postureCallbackCaptor.capture()) 142 val postureCallback: DevicePostureController.Callback = postureCallbackCaptor.value 143 postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED) 144 145 // Simulate posture change to same state with callback 146 assertThat(getPatternTopGuideline()).isNotEqualTo(getHalfOpenedBouncerHeightRatio()) 147 148 postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED) 149 150 // Verify view is still in posture state DEVICE_POSTURE_OPENED 151 assertThat(getPatternTopGuideline()).isNotEqualTo(getHalfOpenedBouncerHeightRatio()) 152 } 153 getPatternTopGuidelinenull154 private fun getPatternTopGuideline(): Float { 155 val cs = ConstraintSet() 156 val container = 157 mKeyguardPatternView.requireViewById(R.id.pattern_container) as ConstraintLayout 158 cs.clone(container) 159 return cs.getConstraint(R.id.pattern_top_guideline).layout.guidePercent 160 } 161 getHalfOpenedBouncerHeightRationull162 private fun getHalfOpenedBouncerHeightRatio(): Float { 163 return mContext.resources.getFloat(R.dimen.half_opened_bouncer_height_ratio) 164 } 165 166 @Test withFeatureFlagOn_oldMessage_isHiddennull167 fun withFeatureFlagOn_oldMessage_isHidden() { 168 mSetFlagsRule.enableFlags(AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES) 169 170 mKeyguardPatternViewController.onViewAttached() 171 172 verify<KeyguardMessageAreaController<*>>(mKeyguardMessageAreaController).disable() 173 } 174 175 @Test onPause_resetsTextnull176 fun onPause_resetsText() { 177 mKeyguardPatternViewController.init() 178 mKeyguardPatternViewController.onPause() 179 verify(mKeyguardMessageAreaController).setMessage(R.string.keyguard_enter_your_pattern) 180 } 181 182 @Test testOnViewAttachednull183 fun testOnViewAttached() { 184 reset(mKeyguardMessageAreaController) 185 reset(mLockPatternUtils) 186 mKeyguardPatternViewController.onViewAttached() 187 verify(mKeyguardMessageAreaController) 188 .setMessage(context.resources.getString(R.string.keyguard_enter_your_pattern), false) 189 verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt()) 190 } 191 192 @Test testOnViewAttached_withExistingMessagenull193 fun testOnViewAttached_withExistingMessage() { 194 reset(mKeyguardMessageAreaController) 195 `when`(mKeyguardMessageAreaController.message).thenReturn("Unlock to continue.") 196 mKeyguardPatternViewController.onViewAttached() 197 verify(mKeyguardMessageAreaController, never()).setMessage(anyString(), anyBoolean()) 198 } 199 } 200