1/* 2 * Copyright (C) 2017 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 17package com.android.systemui.statusbar.phone; 18 19import static com.google.common.truth.Truth.assertThat; 20 21import static org.mockito.ArgumentMatchers.anyFloat; 22import static org.mockito.ArgumentMatchers.anyInt; 23import static org.mockito.ArgumentMatchers.eq; 24import static org.mockito.Mockito.never; 25import static org.mockito.Mockito.reset; 26import static org.mockito.Mockito.verify; 27import static org.mockito.Mockito.verifyNoMoreInteractions; 28import static org.mockito.Mockito.verifyZeroInteractions; 29import static org.mockito.Mockito.when; 30 31import android.graphics.Color; 32import android.support.test.filters.SmallTest; 33import android.testing.AndroidTestingRunner; 34import android.testing.TestableLooper; 35import android.view.ViewGroup; 36import android.view.ViewTreeObserver; 37import android.widget.FrameLayout; 38 39import com.android.internal.widget.LockPatternUtils; 40import com.android.keyguard.KeyguardHostView; 41import com.android.keyguard.KeyguardSecurityModel; 42import com.android.keyguard.ViewMediatorCallback; 43import com.android.systemui.DejankUtils; 44import com.android.systemui.SysuiTestCase; 45import com.android.systemui.classifier.FalsingManager; 46import com.android.systemui.keyguard.DismissCallbackRegistry; 47 48import org.junit.Assert; 49import org.junit.Before; 50import org.junit.Test; 51import org.junit.runner.RunWith; 52import org.mockito.Mock; 53import org.mockito.MockitoAnnotations; 54 55@SmallTest 56@RunWith(AndroidTestingRunner.class) 57@TestableLooper.RunWithLooper(setAsMainLooper = true) 58public class KeyguardBouncerTest extends SysuiTestCase { 59 60 @Mock 61 private FalsingManager mFalsingManager; 62 @Mock 63 private ViewMediatorCallback mViewMediatorCallback; 64 @Mock 65 private LockPatternUtils mLockPatternUtils; 66 @Mock 67 private DismissCallbackRegistry mDismissCallbackRegistry; 68 @Mock 69 private KeyguardHostView mKeyguardHostView; 70 @Mock 71 private ViewTreeObserver mViewTreeObserver; 72 @Mock 73 private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback; 74 75 private KeyguardBouncer mBouncer; 76 77 @Before 78 public void setup() { 79 MockitoAnnotations.initMocks(this); 80 DejankUtils.setImmediate(true); 81 final ViewGroup container = new FrameLayout(getContext()); 82 when(mKeyguardHostView.getViewTreeObserver()).thenReturn(mViewTreeObserver); 83 when(mKeyguardHostView.getHeight()).thenReturn(500); 84 mBouncer = new KeyguardBouncer(getContext(), mViewMediatorCallback, 85 mLockPatternUtils, container, mDismissCallbackRegistry, mFalsingManager, 86 mExpansionCallback) { 87 @Override 88 protected void inflateView() { 89 super.inflateView(); 90 mKeyguardView = mKeyguardHostView; 91 } 92 }; 93 } 94 95 @Test 96 public void testInflateView_doesntCrash() { 97 mBouncer.inflateView(); 98 } 99 100 @Test 101 public void testShow_notifiesFalsingManager() { 102 mBouncer.show(true); 103 verify(mFalsingManager).onBouncerShown(); 104 105 mBouncer.show(true, false); 106 verifyNoMoreInteractions(mFalsingManager); 107 } 108 109 /** 110 * Regression test: Invisible bouncer when occluded. 111 */ 112 @Test 113 public void testShow_bouncerIsVisible() { 114 // Expand notification panel as if we were in the keyguard. 115 mBouncer.ensureView(); 116 mBouncer.setExpansion(1); 117 118 reset(mKeyguardHostView); 119 when(mKeyguardHostView.getHeight()).thenReturn(500); 120 121 mBouncer.show(true); 122 verify(mKeyguardHostView).setAlpha(eq(1f)); 123 verify(mKeyguardHostView).setTranslationY(eq(0f)); 124 } 125 126 @Test 127 public void testShow_notifiesVisibility() { 128 mBouncer.show(true); 129 verify(mViewMediatorCallback).onBouncerVisiblityChanged(eq(true)); 130 131 // Not called again when visible 132 reset(mViewMediatorCallback); 133 mBouncer.show(true); 134 verifyNoMoreInteractions(mViewMediatorCallback); 135 } 136 137 @Test 138 public void testShow_triesToDismissKeyguard() { 139 mBouncer.show(true); 140 verify(mKeyguardHostView).dismiss(anyInt()); 141 } 142 143 @Test 144 public void testShow_resetsSecuritySelection() { 145 mBouncer.show(false); 146 verify(mKeyguardHostView, never()).showPrimarySecurityScreen(); 147 148 mBouncer.hide(false); 149 mBouncer.show(true); 150 verify(mKeyguardHostView).showPrimarySecurityScreen(); 151 } 152 153 @Test 154 public void testShow_animatesKeyguardView() { 155 mBouncer.show(true); 156 verify(mKeyguardHostView).startAppearAnimation(); 157 } 158 159 @Test 160 public void testShow_showsErrorMessage() { 161 final String errorMessage = "an error message"; 162 when(mViewMediatorCallback.consumeCustomMessage()).thenReturn(errorMessage); 163 mBouncer.show(true); 164 verify(mKeyguardHostView).showErrorMessage(eq(errorMessage)); 165 } 166 167 @Test 168 public void testSetExpansion_notifiesFalsingManager() { 169 mBouncer.ensureView(); 170 mBouncer.setExpansion(0.5f); 171 172 mBouncer.setExpansion(1); 173 verify(mFalsingManager).onBouncerHidden(); 174 verify(mExpansionCallback).onFullyHidden(); 175 176 mBouncer.setExpansion(0); 177 verify(mFalsingManager).onBouncerShown(); 178 verify(mExpansionCallback).onFullyShown(); 179 } 180 181 @Test 182 public void testSetExpansion_notifiesKeyguardView() { 183 mBouncer.ensureView(); 184 mBouncer.setExpansion(0.1f); 185 186 mBouncer.setExpansion(0); 187 verify(mKeyguardHostView).onResume(); 188 } 189 190 @Test 191 public void testHide_notifiesFalsingManager() { 192 mBouncer.hide(false); 193 verify(mFalsingManager).onBouncerHidden(); 194 } 195 196 @Test 197 public void testHide_notifiesVisibility() { 198 mBouncer.hide(false); 199 verify(mViewMediatorCallback).onBouncerVisiblityChanged(eq(false)); 200 } 201 202 @Test 203 public void testHide_notifiesDismissCallbackIfVisible() { 204 mBouncer.hide(false); 205 verifyZeroInteractions(mDismissCallbackRegistry); 206 mBouncer.show(false); 207 mBouncer.hide(false); 208 verify(mDismissCallbackRegistry).notifyDismissCancelled(); 209 } 210 211 @Test 212 public void testHide_notShowingAnymore() { 213 mBouncer.ensureView(); 214 mBouncer.show(false /* resetSecuritySelection */); 215 mBouncer.hide(false /* destroyViews */); 216 Assert.assertFalse("Not showing", mBouncer.isShowing()); 217 } 218 219 @Test 220 public void testShowPromptReason_propagates() { 221 mBouncer.ensureView(); 222 mBouncer.showPromptReason(1); 223 verify(mKeyguardHostView).showPromptReason(eq(1)); 224 } 225 226 @Test 227 public void testShowMessage_propagates() { 228 final String message = "a message"; 229 mBouncer.ensureView(); 230 mBouncer.showMessage(message, Color.GREEN); 231 verify(mKeyguardHostView).showMessage(eq(message), eq(Color.GREEN)); 232 } 233 234 @Test 235 public void testShowOnDismissAction_showsBouncer() { 236 final KeyguardHostView.OnDismissAction dismissAction = () -> false; 237 final Runnable cancelAction = () -> {}; 238 mBouncer.showWithDismissAction(dismissAction, cancelAction); 239 verify(mKeyguardHostView).setOnDismissAction(dismissAction, cancelAction); 240 Assert.assertTrue("Should be showing", mBouncer.isShowing()); 241 } 242 243 @Test 244 public void testStartPreHideAnimation_notifiesView() { 245 final boolean[] ran = {false}; 246 final Runnable r = () -> ran[0] = true; 247 mBouncer.startPreHideAnimation(r); 248 Assert.assertTrue("Callback should have been invoked", ran[0]); 249 250 ran[0] = false; 251 mBouncer.ensureView(); 252 mBouncer.startPreHideAnimation(r); 253 verify(mKeyguardHostView).startDisappearAnimation(r); 254 Assert.assertFalse("Callback should have been deferred", ran[0]); 255 } 256 257 @Test 258 public void testIsShowing_animated() { 259 Assert.assertFalse("Show wasn't invoked yet", mBouncer.isShowing()); 260 mBouncer.show(true /* reset */); 261 Assert.assertTrue("Should be showing", mBouncer.isShowing()); 262 } 263 264 @Test 265 public void testIsShowing_forSwipeUp() { 266 mBouncer.setExpansion(1f); 267 mBouncer.show(true /* reset */, false /* animated */); 268 Assert.assertFalse("Should only be showing after collapsing notification panel", 269 mBouncer.isShowing()); 270 mBouncer.setExpansion(0f); 271 Assert.assertTrue("Should be showing", mBouncer.isShowing()); 272 } 273 274 @Test 275 public void testSetExpansion() { 276 mBouncer.ensureView(); 277 mBouncer.setExpansion(0.5f); 278 verify(mKeyguardHostView).setAlpha(anyFloat()); 279 verify(mKeyguardHostView).setTranslationY(anyFloat()); 280 } 281 282 @Test 283 public void testNeedsFullscreenBouncer_asksKeyguardView() { 284 mBouncer.ensureView(); 285 mBouncer.needsFullscreenBouncer(); 286 verify(mKeyguardHostView).getSecurityMode(); 287 verify(mKeyguardHostView, never()).getCurrentSecurityMode(); 288 } 289 290 @Test 291 public void testIsFullscreenBouncer_asksKeyguardView() { 292 mBouncer.ensureView(); 293 mBouncer.isFullscreenBouncer(); 294 verify(mKeyguardHostView).getCurrentSecurityMode(); 295 verify(mKeyguardHostView, never()).getSecurityMode(); 296 } 297 298 @Test 299 public void testIsHiding_preHideOrHide() { 300 Assert.assertFalse("Should not be hiding on initial state", mBouncer.isAnimatingAway()); 301 mBouncer.startPreHideAnimation(null /* runnable */); 302 Assert.assertTrue("Should be hiding during pre-hide", mBouncer.isAnimatingAway()); 303 mBouncer.hide(false /* destroyView */); 304 Assert.assertFalse("Should be hidden after hide()", mBouncer.isAnimatingAway()); 305 } 306 307 @Test 308 public void testIsHiding_skipsTranslation() { 309 mBouncer.show(false /* reset */); 310 reset(mKeyguardHostView); 311 mBouncer.startPreHideAnimation(null /* runnable */); 312 mBouncer.setExpansion(0.5f); 313 verify(mKeyguardHostView, never()).setTranslationY(anyFloat()); 314 verify(mKeyguardHostView, never()).setAlpha(anyFloat()); 315 } 316 317 @Test 318 public void testIsSecure() { 319 Assert.assertTrue("Bouncer is secure before inflating views", mBouncer.isSecure()); 320 321 mBouncer.ensureView(); 322 for (KeyguardSecurityModel.SecurityMode mode : KeyguardSecurityModel.SecurityMode.values()){ 323 reset(mKeyguardHostView); 324 when(mKeyguardHostView.getSecurityMode()).thenReturn(mode); 325 Assert.assertEquals("Security doesn't match for mode: " + mode, 326 mBouncer.isSecure(), mode != KeyguardSecurityModel.SecurityMode.None); 327 } 328 } 329 330 @Test 331 public void testIsShowingScrimmed() { 332 mBouncer.show(false /* resetSecuritySelection */, true /* animate */); 333 assertThat(mBouncer.isShowingScrimmed()).isTrue(); 334 mBouncer.show(false /* resetSecuritySelection */, false /* animate */); 335 assertThat(mBouncer.isShowingScrimmed()).isFalse(); 336 } 337 338 @Test 339 public void testWillDismissWithAction() { 340 mBouncer.ensureView(); 341 Assert.assertFalse("Action not set yet", mBouncer.willDismissWithAction()); 342 when(mKeyguardHostView.hasDismissActions()).thenReturn(true); 343 Assert.assertTrue("Action should exist", mBouncer.willDismissWithAction()); 344 } 345} 346