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.systemui.classifier; 18 19 import static org.mockito.ArgumentMatchers.any; 20 import static org.mockito.ArgumentMatchers.argThat; 21 import static org.mockito.Mockito.inOrder; 22 import static org.mockito.Mockito.never; 23 import static org.mockito.Mockito.reset; 24 import static org.mockito.Mockito.times; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.testing.AndroidTestingRunner; 29 import android.view.MotionEvent; 30 31 import androidx.test.filters.SmallTest; 32 33 import com.android.keyguard.KeyguardUpdateMonitor; 34 import com.android.systemui.SysuiTestCase; 35 import com.android.systemui.dock.DockManager; 36 import com.android.systemui.dock.DockManagerFake; 37 import com.android.systemui.plugins.statusbar.StatusBarStateController; 38 import com.android.systemui.shade.ShadeExpansionStateManager; 39 import com.android.systemui.statusbar.StatusBarState; 40 import com.android.systemui.statusbar.SysuiStatusBarStateController; 41 import com.android.systemui.statusbar.policy.BatteryController; 42 import com.android.systemui.statusbar.policy.KeyguardStateController; 43 import com.android.systemui.util.concurrency.FakeExecutor; 44 import com.android.systemui.util.sensors.ProximitySensor; 45 import com.android.systemui.util.sensors.ThresholdSensor; 46 import com.android.systemui.util.time.FakeSystemClock; 47 48 import org.junit.Before; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 import org.mockito.ArgumentCaptor; 52 import org.mockito.InOrder; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 56 @SmallTest 57 @RunWith(AndroidTestingRunner.class) 58 public class FalsingCollectorImplTest extends SysuiTestCase { 59 60 private FalsingCollectorImpl mFalsingCollector; 61 @Mock 62 private FalsingDataProvider mFalsingDataProvider; 63 private final FalsingManagerFake mFalsingManager = new FalsingManagerFake(); 64 @Mock 65 private KeyguardUpdateMonitor mKeyguardUpdateMonitor; 66 @Mock 67 private HistoryTracker mHistoryTracker; 68 @Mock 69 private ProximitySensor mProximitySensor; 70 @Mock 71 private SysuiStatusBarStateController mStatusBarStateController; 72 @Mock 73 private KeyguardStateController mKeyguardStateController; 74 @Mock 75 private ShadeExpansionStateManager mShadeExpansionStateManager; 76 @Mock 77 private BatteryController mBatteryController; 78 private final DockManagerFake mDockManager = new DockManagerFake(); 79 private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); 80 private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock); 81 82 @Before setUp()83 public void setUp() { 84 MockitoAnnotations.initMocks(this); 85 86 when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); 87 when(mKeyguardStateController.isShowing()).thenReturn(true); 88 89 mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager, 90 mKeyguardUpdateMonitor, mHistoryTracker, mProximitySensor, 91 mStatusBarStateController, mKeyguardStateController, mShadeExpansionStateManager, 92 mBatteryController, 93 mDockManager, mFakeExecutor, mFakeSystemClock); 94 } 95 96 @Test testRegisterSensor()97 public void testRegisterSensor() { 98 mFalsingCollector.onScreenTurningOn(); 99 verify(mProximitySensor).register(any(ThresholdSensor.Listener.class)); 100 } 101 102 @Test testNoProximityWhenWirelessCharging()103 public void testNoProximityWhenWirelessCharging() { 104 ArgumentCaptor<BatteryController.BatteryStateChangeCallback> batteryCallbackCaptor = 105 ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class); 106 verify(mBatteryController).addCallback(batteryCallbackCaptor.capture()); 107 batteryCallbackCaptor.getValue().onWirelessChargingChanged(true); 108 verify(mProximitySensor).pause(); 109 } 110 111 @Test testProximityWhenOffWirelessCharging()112 public void testProximityWhenOffWirelessCharging() { 113 ArgumentCaptor<BatteryController.BatteryStateChangeCallback> batteryCallbackCaptor = 114 ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class); 115 verify(mBatteryController).addCallback(batteryCallbackCaptor.capture()); 116 batteryCallbackCaptor.getValue().onWirelessChargingChanged(false); 117 verify(mProximitySensor).resume(); 118 } 119 120 @Test testNoProximityWhenDocked()121 public void testNoProximityWhenDocked() { 122 mDockManager.setDockEvent(DockManager.STATE_DOCKED); 123 verify(mProximitySensor).pause(); 124 } 125 126 @Test testProximityWhenUndocked()127 public void testProximityWhenUndocked() { 128 mDockManager.setDockEvent(DockManager.STATE_NONE); 129 verify(mProximitySensor).resume(); 130 } 131 132 @Test testUnregisterSensor()133 public void testUnregisterSensor() { 134 mFalsingCollector.onScreenTurningOn(); 135 reset(mProximitySensor); 136 mFalsingCollector.onScreenOff(); 137 verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class)); 138 } 139 140 @Test testUnregisterSensor_QS()141 public void testUnregisterSensor_QS() { 142 mFalsingCollector.onScreenTurningOn(); 143 reset(mProximitySensor); 144 mFalsingCollector.onQsExpansionChanged(true); 145 verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class)); 146 mFalsingCollector.onQsExpansionChanged(false); 147 verify(mProximitySensor).register(any(ThresholdSensor.Listener.class)); 148 } 149 150 @Test testUnregisterSensor_Bouncer()151 public void testUnregisterSensor_Bouncer() { 152 mFalsingCollector.onScreenTurningOn(); 153 reset(mProximitySensor); 154 mFalsingCollector.onBouncerShown(); 155 verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class)); 156 mFalsingCollector.onBouncerHidden(); 157 verify(mProximitySensor).register(any(ThresholdSensor.Listener.class)); 158 } 159 160 @Test testUnregisterSensor_StateTransition()161 public void testUnregisterSensor_StateTransition() { 162 ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor = 163 ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); 164 verify(mStatusBarStateController).addCallback(stateListenerArgumentCaptor.capture()); 165 166 mFalsingCollector.onScreenTurningOn(); 167 reset(mProximitySensor); 168 stateListenerArgumentCaptor.getValue().onStateChanged(StatusBarState.SHADE); 169 verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class)); 170 } 171 172 @Test testPassThroughGesture()173 public void testPassThroughGesture() { 174 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); 175 MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); 176 177 // Nothing passed initially 178 mFalsingCollector.onTouchEvent(down); 179 verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); 180 181 // Up event flushes the down event. 182 mFalsingCollector.onTouchEvent(up); 183 InOrder orderedCalls = inOrder(mFalsingDataProvider); 184 // We can't simply use "eq" or similar because the collector makes a copy of "down". 185 orderedCalls.verify(mFalsingDataProvider).onMotionEvent( 186 argThat(argument -> argument.getActionMasked() == MotionEvent.ACTION_DOWN)); 187 orderedCalls.verify(mFalsingDataProvider).onMotionEvent(up); 188 } 189 190 @Test testAvoidGesture()191 public void testAvoidGesture() { 192 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); 193 MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); 194 195 // Nothing passed initially 196 mFalsingCollector.onTouchEvent(down); 197 verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); 198 199 mFalsingCollector.avoidGesture(); 200 // Up event would flush, but we were told to avoid. 201 mFalsingCollector.onTouchEvent(up); 202 verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); 203 } 204 205 @Test testIgnoreActionOutside()206 public void testIgnoreActionOutside() { 207 MotionEvent outside = MotionEvent.obtain(0, 0, MotionEvent.ACTION_OUTSIDE, 0, 0, 0); 208 MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); 209 210 // Nothing passed initially. The outside event will be completely ignored. 211 mFalsingCollector.onTouchEvent(outside); 212 verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); 213 214 // Up event flushes, and the outside event isn't passed through. 215 mFalsingCollector.onTouchEvent(up); 216 verify(mFalsingDataProvider).onMotionEvent(up); 217 } 218 219 @Test testAvoidUnlocked()220 public void testAvoidUnlocked() { 221 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); 222 MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); 223 224 when(mKeyguardStateController.isShowing()).thenReturn(false); 225 226 // Nothing passed initially 227 mFalsingCollector.onTouchEvent(down); 228 verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); 229 230 // Up event would normally flush the up event, but doesn't. 231 mFalsingCollector.onTouchEvent(up); 232 verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); 233 } 234 235 @Test testGestureWhenDozing()236 public void testGestureWhenDozing() { 237 // We check the FalsingManager for taps during the transition to AoD (dozing=true, 238 // pulsing=false), so the FalsingCollector needs to continue to analyze events that occur 239 // while the device is dozing. 240 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); 241 MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); 242 243 when(mStatusBarStateController.isDozing()).thenReturn(true); 244 245 // Nothing passed initially 246 mFalsingCollector.onTouchEvent(down); 247 verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); 248 249 // Up event flushes 250 mFalsingCollector.onTouchEvent(up); 251 verify(mFalsingDataProvider, times(2)).onMotionEvent(any(MotionEvent.class)); 252 } 253 254 @Test testGestureWhenPulsing()255 public void testGestureWhenPulsing() { 256 MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); 257 MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); 258 259 when(mStatusBarStateController.isDozing()).thenReturn(true); 260 when(mStatusBarStateController.isPulsing()).thenReturn(true); 261 262 // Nothing passed initially 263 mFalsingCollector.onTouchEvent(down); 264 verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); 265 266 // Up event would flushes 267 mFalsingCollector.onTouchEvent(up); 268 verify(mFalsingDataProvider, times(2)).onMotionEvent(any(MotionEvent.class)); 269 } 270 271 @Test testOnA11yAction()272 public void testOnA11yAction() { 273 mFalsingCollector.onA11yAction(); 274 verify(mFalsingDataProvider).onA11yAction(); 275 } 276 } 277