• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server;
18 
19 import static android.service.quickaccesswallet.Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP;
20 import static android.service.quickaccesswallet.Flags.FLAG_LAUNCH_WALLET_VIA_SYSUI_CALLBACKS;
21 import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap;
22 import static android.service.quickaccesswallet.Flags.launchWalletViaSysuiCallbacks;
23 
24 import static com.android.server.GestureLauncherService.DOUBLE_TAP_POWER_DISABLED_MODE;
25 import static com.android.server.GestureLauncherService.DOUBLE_TAP_POWER_LAUNCH_CAMERA_MODE;
26 import static com.android.server.GestureLauncherService.DOUBLE_TAP_POWER_MULTI_TARGET_MODE;
27 import static com.android.server.GestureLauncherService.LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER;
28 import static com.android.server.GestureLauncherService.LAUNCH_WALLET_ON_DOUBLE_TAP_POWER;
29 import static com.android.server.GestureLauncherService.POWER_DOUBLE_TAP_MAX_TIME_MS;
30 
31 import static org.junit.Assert.assertEquals;
32 import static org.junit.Assert.assertFalse;
33 import static org.junit.Assert.assertTrue;
34 import static org.mockito.ArgumentMatchers.any;
35 import static org.mockito.ArgumentMatchers.anyInt;
36 import static org.mockito.ArgumentMatchers.eq;
37 import static org.mockito.Mockito.doAnswer;
38 import static org.mockito.Mockito.never;
39 import static org.mockito.Mockito.times;
40 import static org.mockito.Mockito.verify;
41 import static org.mockito.Mockito.when;
42 
43 import android.app.PendingIntent;
44 import android.app.StatusBarManager;
45 import android.content.BroadcastReceiver;
46 import android.content.Context;
47 import android.content.Intent;
48 import android.content.IntentFilter;
49 import android.content.res.Resources;
50 import android.os.Looper;
51 import android.os.UserHandle;
52 import android.platform.test.annotations.Presubmit;
53 import android.platform.test.annotations.RequiresFlagsDisabled;
54 import android.platform.test.annotations.RequiresFlagsEnabled;
55 import android.platform.test.flag.junit.CheckFlagsRule;
56 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
57 import android.provider.Settings;
58 import android.service.quickaccesswallet.QuickAccessWalletClient;
59 import android.telecom.TelecomManager;
60 import android.test.mock.MockContentResolver;
61 import android.testing.TestableLooper;
62 import android.util.MutableBoolean;
63 import android.view.KeyEvent;
64 
65 import androidx.test.InstrumentationRegistry;
66 import androidx.test.filters.SmallTest;
67 import androidx.test.runner.AndroidJUnit4;
68 
69 import com.android.internal.logging.MetricsLogger;
70 import com.android.internal.logging.UiEventLogger;
71 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
72 import com.android.internal.util.test.FakeSettingsProvider;
73 import com.android.server.statusbar.StatusBarManagerInternal;
74 
75 import org.junit.Before;
76 import org.junit.BeforeClass;
77 import org.junit.Rule;
78 import org.junit.Test;
79 import org.junit.runner.RunWith;
80 import org.mockito.ArgumentCaptor;
81 import org.mockito.Mock;
82 import org.mockito.MockitoAnnotations;
83 
84 import java.util.List;
85 import java.util.concurrent.CountDownLatch;
86 import java.util.concurrent.TimeUnit;
87 
88 /**
89  * Unit tests for {@link GestureLauncherService}.
90  * runtest frameworks-services -c com.android.server.GestureLauncherServiceTest
91  */
92 @Presubmit
93 @SmallTest
94 @RunWith(AndroidJUnit4.class)
95 @TestableLooper.RunWithLooper(setAsMainLooper = true)
96 public class GestureLauncherServiceTest {
97 
98     private static final int FAKE_USER_ID = 1337;
99     private static final int FAKE_SOURCE = 1982;
100     private static final long INITIAL_EVENT_TIME_MILLIS = 20000L;
101     private static final long IGNORED_DOWN_TIME = 1234L;
102     private static final int IGNORED_ACTION = 13;
103     private static final int IGNORED_CODE = 1999;
104     private static final int IGNORED_REPEAT = 42;
105     private static final int IGNORED_META_STATE = 0;
106     private static final int IGNORED_DEVICE_ID = 0;
107     private static final int IGNORED_SCANCODE = 0;
108 
109     private @Mock Context mContext;
110     private @Mock Resources mResources;
111     private @Mock StatusBarManagerInternal mStatusBarManagerInternal;
112     private @Mock TelecomManager mTelecomManager;
113     private @Mock MetricsLogger mMetricsLogger;
114     @Mock private UiEventLogger mUiEventLogger;
115     @Mock private QuickAccessWalletClient mQuickAccessWalletClient;
116     private MockContentResolver mContentResolver;
117     private GestureLauncherService mGestureLauncherService;
118 
119     private Context mInstrumentationContext =
120             InstrumentationRegistry.getInstrumentation().getContext();
121 
122     private static final String LAUNCH_TEST_WALLET_ACTION = "LAUNCH_TEST_WALLET_ACTION";
123     private static final String LAUNCH_FALLBACK_ACTION = "LAUNCH_FALLBACK_ACTION";
124     private PendingIntent mGesturePendingIntent =
125             PendingIntent.getBroadcast(
126                     mInstrumentationContext,
127                     0,
128                     new Intent(LAUNCH_TEST_WALLET_ACTION),
129                     PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);
130 
131     private PendingIntent mFallbackPendingIntent =
132             PendingIntent.getBroadcast(
133                     mInstrumentationContext,
134                     0,
135                     new Intent(LAUNCH_FALLBACK_ACTION),
136                     PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);
137 
138     @Rule
139     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
140 
141     @BeforeClass
oneTimeInitialization()142     public static void oneTimeInitialization() {
143         if (Looper.myLooper() == null) {
144             Looper.prepare();
145         }
146     }
147 
148     @Before
setup()149     public void setup() {
150         MockitoAnnotations.initMocks(this);
151 
152         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
153         LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
154 
155         final Context originalContext = InstrumentationRegistry.getContext();
156         when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
157         when(mContext.getResources()).thenReturn(mResources);
158         mContentResolver = new MockContentResolver(mContext);
159         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
160         when(mContext.getContentResolver()).thenReturn(mContentResolver);
161         when(mContext.getSystemService(Context.TELECOM_SERVICE)).thenReturn(mTelecomManager);
162         when(mTelecomManager.createLaunchEmergencyDialerIntent(null)).thenReturn(new Intent());
163         when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
164 
165         mGestureLauncherService =
166                 new GestureLauncherService(
167                         mContext, mMetricsLogger, mQuickAccessWalletClient, mUiEventLogger);
168 
169         Settings.Secure.clearProviderForTest();
170     }
171 
registerWalletLaunchedReceiver(String action)172     private WalletLaunchedReceiver registerWalletLaunchedReceiver(String action) {
173         IntentFilter filter = new IntentFilter(action);
174         WalletLaunchedReceiver receiver = new WalletLaunchedReceiver();
175         mInstrumentationContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
176         return receiver;
177     }
178 
179     /**
180      * A simple {@link BroadcastReceiver} implementation that counts down a {@link CountDownLatch}
181      * when a matching message is received
182      */
183     private static final class WalletLaunchedReceiver extends BroadcastReceiver {
184         private static final int TIMEOUT_SECONDS = 3;
185 
186         private final CountDownLatch mLatch;
187 
WalletLaunchedReceiver()188         WalletLaunchedReceiver() {
189             mLatch = new CountDownLatch(1);
190         }
191 
192         @Override
onReceive(Context context, Intent intent)193         public void onReceive(Context context, Intent intent) {
194             mLatch.countDown();
195             context.unregisterReceiver(this);
196         }
197 
waitUntilShown()198         Boolean waitUntilShown() {
199             try {
200                 return mLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
201             } catch (InterruptedException e) {
202                 return false;
203             }
204         }
205     }
206 
207     @Test
testIsCameraDoubleTapPowerEnabled_configFalse()208     public void testIsCameraDoubleTapPowerEnabled_configFalse() {
209         withCameraDoubleTapPowerEnableConfigValue(false);
210         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
211     }
212 
213     @Test
testIsCameraDoubleTapPowerEnabled_configTrue()214     public void testIsCameraDoubleTapPowerEnabled_configTrue() {
215         withCameraDoubleTapPowerEnableConfigValue(true);
216         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
217     }
218 
219     @Test
220     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configFalseSettingDisabled()221     public void testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configFalseSettingDisabled() {
222         withDoubleTapPowerModeConfigValue(
223                 DOUBLE_TAP_POWER_DISABLED_MODE);
224         withMultiTargetDoubleTapPowerGestureEnableSettingValue(false);
225         withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
226 
227         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
228                 mContext, FAKE_USER_ID));
229     }
230 
231     @Test
232     @RequiresFlagsDisabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_flagDisabled_configFalseSettingDisabled()233     public void testIsCameraDoubleTapPowerSettingEnabled_flagDisabled_configFalseSettingDisabled() {
234         withCameraDoubleTapPowerEnableConfigValue(false);
235         withCameraDoubleTapPowerDisableSettingValue(1);
236 
237         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
238                 mContext, FAKE_USER_ID));
239     }
240 
241     @Test
242     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configFalseSettingEnabled()243     public void testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configFalseSettingEnabled() {
244         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_DISABLED_MODE);
245         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
246         withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
247 
248         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
249                 mContext, FAKE_USER_ID));
250     }
251 
252     @Test
253     @RequiresFlagsDisabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_flagDisabled_configFalseSettingEnabled()254     public void testIsCameraDoubleTapPowerSettingEnabled_flagDisabled_configFalseSettingEnabled() {
255         withCameraDoubleTapPowerEnableConfigValue(false);
256         withCameraDoubleTapPowerDisableSettingValue(0);
257 
258         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
259                 mContext, FAKE_USER_ID));
260     }
261 
262     @Test
263     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configTrueSettingDisabled()264     public void testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configTrueSettingDisabled() {
265         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
266         withMultiTargetDoubleTapPowerGestureEnableSettingValue(false);
267         withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
268 
269         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
270                 mContext, FAKE_USER_ID));
271     }
272 
273     @Test
274     @RequiresFlagsDisabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_flagDisabled_configTrueSettingDisabled()275     public void testIsCameraDoubleTapPowerSettingEnabled_flagDisabled_configTrueSettingDisabled() {
276         withCameraDoubleTapPowerEnableConfigValue(true);
277         withCameraDoubleTapPowerDisableSettingValue(1);
278 
279         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
280                 mContext, FAKE_USER_ID));
281     }
282 
283     @Test
284     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configTrueSettingEnabled()285     public void testIsCameraDoubleTapPowerSettingEnabled_flagEnabled_configTrueSettingEnabled() {
286         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
287         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
288         withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
289 
290         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
291                 mContext, FAKE_USER_ID));
292     }
293 
294     @Test
295     @RequiresFlagsDisabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_flagDisabled_configTrueSettingEnabled()296     public void testIsCameraDoubleTapPowerSettingEnabled_flagDisabled_configTrueSettingEnabled() {
297         withCameraDoubleTapPowerEnableConfigValue(true);
298         withCameraDoubleTapPowerDisableSettingValue(0);
299 
300         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
301                 mContext, FAKE_USER_ID));
302     }
303 
304     @Test
305     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_launchCameraMode_settingEnabled()306     public void testIsCameraDoubleTapPowerSettingEnabled_launchCameraMode_settingEnabled() {
307         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_LAUNCH_CAMERA_MODE);
308         withCameraDoubleTapPowerDisableSettingValue(0);
309 
310         assertTrue(
311                 mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
312                         mContext, FAKE_USER_ID));
313     }
314 
315     @Test
316     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_launchCameraMode_settingDisabled()317     public void testIsCameraDoubleTapPowerSettingEnabled_launchCameraMode_settingDisabled() {
318         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_LAUNCH_CAMERA_MODE);
319         withCameraDoubleTapPowerDisableSettingValue(1);
320 
321         assertFalse(
322                 mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
323                         mContext, FAKE_USER_ID));
324     }
325 
326     @Test
327     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_actionWallet()328     public void testIsCameraDoubleTapPowerSettingEnabled_actionWallet() {
329         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
330         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
331         withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
332 
333         assertFalse(
334                 mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
335                         mContext, FAKE_USER_ID));
336     }
337 
338     @Test
339     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_defaultActionCamera()340     public void testIsCameraDoubleTapPowerSettingEnabled_defaultActionCamera() {
341         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
342         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
343         withDefaultDoubleTapPowerGestureActionConfig(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
344 
345         assertTrue(
346                 mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
347                         mContext, FAKE_USER_ID));
348     }
349 
350     @Test
351     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsCameraDoubleTapPowerSettingEnabled_defaultActionNotCamera()352     public void testIsCameraDoubleTapPowerSettingEnabled_defaultActionNotCamera() {
353         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
354         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
355         withDefaultDoubleTapPowerGestureActionConfig(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
356 
357         assertFalse(
358                 mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
359                         mContext, FAKE_USER_ID));
360     }
361 
362     @Test
363     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsWalletDoubleTapPowerSettingEnabled()364     public void testIsWalletDoubleTapPowerSettingEnabled() {
365         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
366         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
367         withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
368 
369         assertTrue(
370                 mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
371                         mContext, FAKE_USER_ID));
372     }
373 
374     @Test
375     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsWalletDoubleTapPowerSettingEnabled_configDisabled()376     public void testIsWalletDoubleTapPowerSettingEnabled_configDisabled() {
377         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_DISABLED_MODE);
378         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
379         withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
380 
381         assertFalse(
382                 mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
383                         mContext, FAKE_USER_ID));
384     }
385 
386     @Test
387     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsWalletDoubleTapPowerSettingEnabled_settingDisabled()388     public void testIsWalletDoubleTapPowerSettingEnabled_settingDisabled() {
389         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
390         withMultiTargetDoubleTapPowerGestureEnableSettingValue(false);
391         withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
392 
393         assertFalse(
394                 mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
395                         mContext, FAKE_USER_ID));
396     }
397 
398     @Test
399     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsWalletDoubleTapPowerSettingEnabled_actionCamera()400     public void testIsWalletDoubleTapPowerSettingEnabled_actionCamera() {
401         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
402         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
403         withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
404 
405         assertFalse(
406                 mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
407                         mContext, FAKE_USER_ID));
408     }
409 
410     @Test
411     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsWalletDoubleTapPowerSettingEnabled_defaultActionWallet()412     public void testIsWalletDoubleTapPowerSettingEnabled_defaultActionWallet() {
413         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
414         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
415         withDefaultDoubleTapPowerGestureActionConfig(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
416 
417         assertTrue(
418                 mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
419                         mContext, FAKE_USER_ID));
420     }
421 
422     @Test
423     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testIsWalletDoubleTapPowerSettingEnabled_defaultActionNotWallet()424     public void testIsWalletDoubleTapPowerSettingEnabled_defaultActionNotWallet() {
425         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
426         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
427         withDefaultDoubleTapPowerGestureActionConfig(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
428 
429         assertFalse(
430                 mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled(
431                         mContext, FAKE_USER_ID));
432     }
433 
434     @Test
testIsEmergencyGestureSettingEnabled_settingDisabled()435     public void testIsEmergencyGestureSettingEnabled_settingDisabled() {
436         withEmergencyGestureEnabledConfigValue(true);
437         withEmergencyGestureEnabledSettingValue(false);
438         assertFalse(mGestureLauncherService.isEmergencyGestureSettingEnabled(
439                 mContext, FAKE_USER_ID));
440     }
441 
442     @Test
testIsEmergencyGestureSettingEnabled_settingEnabled()443     public void testIsEmergencyGestureSettingEnabled_settingEnabled() {
444         withEmergencyGestureEnabledConfigValue(true);
445         withEmergencyGestureEnabledSettingValue(true);
446         assertTrue(mGestureLauncherService.isEmergencyGestureSettingEnabled(
447                 mContext, FAKE_USER_ID));
448     }
449 
450     @Test
testIsEmergencyGestureSettingEnabled_supportDisabled()451     public void testIsEmergencyGestureSettingEnabled_supportDisabled() {
452         withEmergencyGestureEnabledConfigValue(false);
453         withEmergencyGestureEnabledSettingValue(true);
454         assertFalse(mGestureLauncherService.isEmergencyGestureSettingEnabled(
455                 mContext, FAKE_USER_ID));
456     }
457 
458     @Test
testGetEmergencyGesturePowerButtonCooldownPeriodMs_enabled()459     public void testGetEmergencyGesturePowerButtonCooldownPeriodMs_enabled() {
460         withEmergencyGesturePowerButtonCooldownPeriodMsValue(4000);
461         assertEquals(4000,
462                 mGestureLauncherService.getEmergencyGesturePowerButtonCooldownPeriodMs(mContext,
463                         FAKE_USER_ID));
464     }
465 
466     @Test
testGetEmergencyGesturePowerButtonCooldownPeriodMs_disabled()467     public void testGetEmergencyGesturePowerButtonCooldownPeriodMs_disabled() {
468         withEmergencyGesturePowerButtonCooldownPeriodMsValue(0);
469         assertEquals(0,
470                 mGestureLauncherService.getEmergencyGesturePowerButtonCooldownPeriodMs(mContext,
471                         FAKE_USER_ID));
472     }
473 
474     @Test
testGetEmergencyGesturePowerButtonCooldownPeriodMs_cappedAtMaximum()475     public void testGetEmergencyGesturePowerButtonCooldownPeriodMs_cappedAtMaximum() {
476         withEmergencyGesturePowerButtonCooldownPeriodMsValue(10000);
477         assertEquals(GestureLauncherService.EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX,
478                 mGestureLauncherService.getEmergencyGesturePowerButtonCooldownPeriodMs(mContext,
479                         FAKE_USER_ID));
480     }
481 
482     @Test
testHandleCameraLaunchGesture_userSetupComplete()483     public void testHandleCameraLaunchGesture_userSetupComplete() {
484         withUserSetupCompleteValue(true);
485 
486         boolean useWakeLock = false;
487         assertTrue(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
488         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(FAKE_SOURCE);
489     }
490 
491     @Test
testHandleEmergencyGesture_userSetupComplete()492     public void testHandleEmergencyGesture_userSetupComplete() {
493         withUserSetupCompleteValue(true);
494 
495         assertTrue(mGestureLauncherService.handleEmergencyGesture());
496     }
497 
498     @Test
testHandleCameraLaunchGesture_userSetupNotComplete()499     public void testHandleCameraLaunchGesture_userSetupNotComplete() {
500         withUserSetupCompleteValue(false);
501 
502         boolean useWakeLock = false;
503         assertFalse(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
504     }
505 
506     @Test
testHandleEmergencyGesture_userSetupNotComplete()507     public void testHandleEmergencyGesture_userSetupNotComplete() {
508         withUserSetupCompleteValue(false);
509 
510         assertFalse(mGestureLauncherService.handleEmergencyGesture());
511     }
512 
513     @Test
testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive()514     public void testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive() {
515         enableCameraGesture();
516 
517         long eventTime = INITIAL_EVENT_TIME_MILLIS + POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
518         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
519                 IGNORED_REPEAT);
520         boolean interactive = true;
521         MutableBoolean outLaunched = new MutableBoolean(true);
522         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
523                 outLaunched);
524         assertFalse(intercepted);
525         assertFalse(outLaunched.value);
526         verify(mMetricsLogger).histogram("power_consecutive_short_tap_count", 1);
527         verify(mMetricsLogger).histogram("power_double_tap_interval", (int) eventTime);
528     }
529 
530     @Test
testInterceptPowerKeyDown_firstPowerDown_emergencyGestureNotLaunched()531     public void testInterceptPowerKeyDown_firstPowerDown_emergencyGestureNotLaunched() {
532         withEmergencyGestureEnabledSettingValue(true);
533         mGestureLauncherService.updateEmergencyGestureEnabled();
534 
535         long eventTime = INITIAL_EVENT_TIME_MILLIS
536                 + GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS - 1;
537         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
538                 IGNORED_REPEAT);
539         boolean interactive = true;
540         MutableBoolean outLaunched = new MutableBoolean(true);
541         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
542                 outLaunched);
543 
544         assertFalse(intercepted);
545         assertFalse(outLaunched.value);
546         verify(mMetricsLogger).histogram("power_double_tap_interval", (int) eventTime);
547     }
548 
549     @Test
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive()550     public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive() {
551         disableDoubleTapPowerGesture();
552 
553         long eventTime = INITIAL_EVENT_TIME_MILLIS;
554         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
555                 IGNORED_REPEAT);
556         boolean interactive = true;
557         MutableBoolean outLaunched = new MutableBoolean(true);
558         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
559                 outLaunched);
560         assertFalse(intercepted);
561         assertFalse(outLaunched.value);
562 
563         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
564         eventTime += interval;
565         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
566                 IGNORED_REPEAT);
567         outLaunched.value = true;
568         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
569                 outLaunched);
570         assertFalse(intercepted);
571         assertFalse(outLaunched.value);
572 
573         verify(mMetricsLogger, never())
574                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
575         verify(mUiEventLogger, never()).log(any());
576 
577         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
578         verify(mMetricsLogger, times(2)).histogram(
579                 eq("power_double_tap_interval"), intervalCaptor.capture());
580         List<Integer> intervals = intervalCaptor.getAllValues();
581         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
582         assertEquals((int) interval, intervals.get(1).intValue());
583 
584         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
585         verify(mMetricsLogger, times(2)).histogram(
586                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
587         List<Integer> tapCounts = tapCountCaptor.getAllValues();
588         assertEquals(1, tapCounts.get(0).intValue());
589         assertEquals(2, tapCounts.get(1).intValue());
590     }
591 
592     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffInteractive()593     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffInteractive() {
594         disableDoubleTapPowerGesture();
595 
596         long eventTime = INITIAL_EVENT_TIME_MILLIS;
597         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
598                 IGNORED_REPEAT);
599         boolean interactive = true;
600         MutableBoolean outLaunched = new MutableBoolean(true);
601         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
602                 outLaunched);
603         assertFalse(intercepted);
604         assertFalse(outLaunched.value);
605 
606         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS;
607         eventTime += interval;
608         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
609                 IGNORED_REPEAT);
610         outLaunched.value = true;
611         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
612                 outLaunched);
613         assertFalse(intercepted);
614         assertFalse(outLaunched.value);
615 
616         verify(mMetricsLogger, never())
617                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
618         verify(mUiEventLogger, never()).log(any());
619 
620         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
621         verify(mMetricsLogger, times(2)).histogram(
622                 eq("power_double_tap_interval"), intervalCaptor.capture());
623         List<Integer> intervals = intervalCaptor.getAllValues();
624         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
625         assertEquals((int) interval, intervals.get(1).intValue());
626 
627         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
628         verify(mMetricsLogger, times(2)).histogram(
629                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
630         List<Integer> tapCounts = tapCountCaptor.getAllValues();
631         assertEquals(1, tapCounts.get(0).intValue());
632         // The interval is too long to launch the camera, but short enough to count as a
633         // sequential tap.
634         assertEquals(2, tapCounts.get(1).intValue());
635     }
636 
637     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffInteractive()638     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffInteractive() {
639         disableDoubleTapPowerGesture();
640 
641         long eventTime = INITIAL_EVENT_TIME_MILLIS;
642         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
643                 IGNORED_REPEAT);
644         boolean interactive = true;
645         MutableBoolean outLaunched = new MutableBoolean(true);
646         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
647                 outLaunched);
648         assertFalse(intercepted);
649         assertFalse(outLaunched.value);
650 
651         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
652         eventTime += interval;
653         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
654                 IGNORED_REPEAT);
655         outLaunched.value = true;
656         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
657                 outLaunched);
658         assertFalse(intercepted);
659         assertFalse(outLaunched.value);
660 
661         verify(mMetricsLogger, never())
662                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
663         verify(mUiEventLogger, never()).log(any());
664 
665         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
666         verify(mMetricsLogger, times(2)).histogram(
667                 eq("power_double_tap_interval"), intervalCaptor.capture());
668         List<Integer> intervals = intervalCaptor.getAllValues();
669         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
670         assertEquals((int) interval, intervals.get(1).intValue());
671 
672         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
673         verify(mMetricsLogger, times(2)).histogram(
674                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
675         List<Integer> tapCounts = tapCountCaptor.getAllValues();
676         assertEquals(1, tapCounts.get(0).intValue());
677         assertEquals(1, tapCounts.get(1).intValue());
678     }
679 
680     @Test
681     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupComplete()682     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupComplete() {
683         enableCameraGesture();
684 
685         long eventTime = INITIAL_EVENT_TIME_MILLIS;
686         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
687                 IGNORED_REPEAT);
688         boolean interactive = true;
689         MutableBoolean outLaunched = new MutableBoolean(true);
690         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
691                 outLaunched);
692         assertFalse(intercepted);
693         assertFalse(outLaunched.value);
694 
695         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
696         eventTime += interval;
697         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
698                 IGNORED_REPEAT);
699         outLaunched.value = false;
700         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
701                 outLaunched);
702         assertTrue(intercepted);
703         assertTrue(outLaunched.value);
704 
705         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
706                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
707         verify(mMetricsLogger)
708                 .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
709         verify(mUiEventLogger, times(1))
710                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
711 
712         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
713         verify(mMetricsLogger, times(2)).histogram(
714                 eq("power_double_tap_interval"), intervalCaptor.capture());
715         List<Integer> intervals = intervalCaptor.getAllValues();
716         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
717         assertEquals((int) interval, intervals.get(1).intValue());
718 
719         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
720         verify(mMetricsLogger, times(2)).histogram(
721                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
722         List<Integer> tapCounts = tapCountCaptor.getAllValues();
723         assertEquals(1, tapCounts.get(0).intValue());
724         assertEquals(2, tapCounts.get(1).intValue());
725     }
726 
727     @Test
728     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
729     public void
testInterceptPowerKeyDown_fiveInboundPresses_walletAndEmergencyEnabled_bothLaunch()730             testInterceptPowerKeyDown_fiveInboundPresses_walletAndEmergencyEnabled_bothLaunch() {
731         WalletLaunchedReceiver receiver = registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION);
732         setUpGetGestureTargetActivityPendingIntent(mGesturePendingIntent);
733         enableEmergencyGesture();
734         enableWalletGesture();
735 
736         // First event
737         long eventTime = INITIAL_EVENT_TIME_MILLIS;
738         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false);
739 
740         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
741         eventTime += interval;
742         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, true);
743 
744         if (launchWalletViaSysuiCallbacks()) {
745             verify(mStatusBarManagerInternal).onWalletLaunchGestureDetected();
746         } else {
747             assertTrue(receiver.waitUntilShown());
748         }
749 
750         // Presses 3 and 4 should not trigger any gesture
751         for (int i = 0; i < 2; i++) {
752             eventTime += interval;
753             sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, false);
754         }
755 
756         // Fifth button press should trigger the emergency flow
757         eventTime += interval;
758         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, true);
759 
760         verify(mUiEventLogger, times(1))
761                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
762         verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
763     }
764 
765     @Test
766     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testInterceptPowerKeyDown_intervalInBoundsWalletPowerGesture()767     public void testInterceptPowerKeyDown_intervalInBoundsWalletPowerGesture() {
768         WalletLaunchedReceiver receiver = registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION);
769         setUpGetGestureTargetActivityPendingIntent(mGesturePendingIntent);
770         enableWalletGesture();
771         enableEmergencyGesture();
772 
773         long eventTime = INITIAL_EVENT_TIME_MILLIS;
774         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false);
775         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
776         eventTime += interval;
777         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, true);
778 
779         if (launchWalletViaSysuiCallbacks()) {
780             verify(mStatusBarManagerInternal).onWalletLaunchGestureDetected();
781         } else {
782             assertTrue(receiver.waitUntilShown());
783         }
784     }
785 
786     @Test
787     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
788     @RequiresFlagsDisabled(FLAG_LAUNCH_WALLET_VIA_SYSUI_CALLBACKS)
testInterceptPowerKeyDown_walletGestureOn_quickAccessWalletServiceUnavailable()789     public void testInterceptPowerKeyDown_walletGestureOn_quickAccessWalletServiceUnavailable() {
790         when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
791         WalletLaunchedReceiver receiver = registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION);
792         setUpGetGestureTargetActivityPendingIntent(mGesturePendingIntent);
793         enableWalletGesture();
794 
795         // First event
796         long eventTime = INITIAL_EVENT_TIME_MILLIS;
797         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false);
798 
799         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
800         eventTime += interval;
801         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, false);
802 
803         assertFalse(receiver.waitUntilShown());
804     }
805 
806     @Test
testInterceptPowerKeyDown_walletGestureOn_userSetupIncomplete()807     public void testInterceptPowerKeyDown_walletGestureOn_userSetupIncomplete() {
808         WalletLaunchedReceiver receiver = registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION);
809         setUpGetGestureTargetActivityPendingIntent(mGesturePendingIntent);
810         enableWalletGesture();
811         withUserSetupCompleteValue(false);
812 
813         // First event
814         long eventTime = INITIAL_EVENT_TIME_MILLIS;
815         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false);
816 
817         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
818         eventTime += interval;
819         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false);
820 
821         if (launchWalletViaSysuiCallbacks()) {
822             verify(mStatusBarManagerInternal, never()).onWalletLaunchGestureDetected();
823         } else {
824             assertFalse(receiver.waitUntilShown());
825         }
826     }
827 
828     @Test
829     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
830     @RequiresFlagsDisabled(FLAG_LAUNCH_WALLET_VIA_SYSUI_CALLBACKS)
testInterceptPowerKeyDown_walletPowerGesture_nullPendingIntent()831     public void testInterceptPowerKeyDown_walletPowerGesture_nullPendingIntent() {
832         WalletLaunchedReceiver gestureReceiver =
833                 registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION);
834         setUpGetGestureTargetActivityPendingIntent(null);
835         WalletLaunchedReceiver fallbackReceiver =
836                 registerWalletLaunchedReceiver(LAUNCH_FALLBACK_ACTION);
837         setUpWalletFallbackPendingIntent(mFallbackPendingIntent);
838         enableWalletGesture();
839         enableEmergencyGesture();
840 
841         // First event
842         long eventTime = INITIAL_EVENT_TIME_MILLIS;
843         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false);
844 
845         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
846         eventTime += interval;
847         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, true);
848 
849         assertFalse(gestureReceiver.waitUntilShown());
850         assertTrue(fallbackReceiver.waitUntilShown());
851     }
852 
853     @Test
854     @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
testInterceptPowerKeyDown_walletPowerGesture_intervalOutOfBounds()855     public void testInterceptPowerKeyDown_walletPowerGesture_intervalOutOfBounds() {
856         WalletLaunchedReceiver gestureReceiver =
857                 registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION);
858         setUpGetGestureTargetActivityPendingIntent(null);
859         WalletLaunchedReceiver fallbackReceiver =
860                 registerWalletLaunchedReceiver(LAUNCH_FALLBACK_ACTION);
861         setUpWalletFallbackPendingIntent(mFallbackPendingIntent);
862         enableWalletGesture();
863         enableEmergencyGesture();
864 
865         // First event
866         long eventTime = INITIAL_EVENT_TIME_MILLIS;
867         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false);
868 
869         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS;
870         eventTime += interval;
871         sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false);
872 
873         if (launchWalletViaSysuiCallbacks()) {
874             verify(mStatusBarManagerInternal, never()).onWalletLaunchGestureDetected();
875         } else {
876             assertFalse(gestureReceiver.waitUntilShown());
877             assertFalse(fallbackReceiver.waitUntilShown());
878         }
879     }
880 
881     @Test
882     public void
testInterceptPowerKeyDown_fiveInboundPresses_cameraAndEmergencyEnabled_bothLaunch()883             testInterceptPowerKeyDown_fiveInboundPresses_cameraAndEmergencyEnabled_bothLaunch() {
884         enableCameraGesture();
885         enableEmergencyGesture();
886 
887         // First button press does nothing
888         long eventTime = INITIAL_EVENT_TIME_MILLIS;
889         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
890                 IGNORED_REPEAT);
891         boolean interactive = true;
892         MutableBoolean outLaunched = new MutableBoolean(true);
893         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
894                 outLaunched);
895         assertFalse(intercepted);
896         assertFalse(outLaunched.value);
897 
898         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
899 
900         // 2nd button triggers camera
901         eventTime += interval;
902         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
903                 IGNORED_REPEAT);
904         outLaunched.value = false;
905         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
906                 outLaunched);
907         assertTrue(intercepted);
908         assertTrue(outLaunched.value);
909 
910         // Camera checks
911         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
912                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
913         verify(mMetricsLogger)
914                 .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
915         verify(mUiEventLogger, times(1))
916                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
917 
918         final ArgumentCaptor<Integer> cameraIntervalCaptor = ArgumentCaptor.forClass(Integer.class);
919         verify(mMetricsLogger, times(2)).histogram(
920                 eq("power_double_tap_interval"), cameraIntervalCaptor.capture());
921         List<Integer> cameraIntervals = cameraIntervalCaptor.getAllValues();
922         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, cameraIntervals.get(0).intValue());
923         assertEquals((int) interval, cameraIntervals.get(1).intValue());
924 
925         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
926         verify(mMetricsLogger, times(2)).histogram(
927                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
928         List<Integer> tapCounts = tapCountCaptor.getAllValues();
929         assertEquals(1, tapCounts.get(0).intValue());
930         assertEquals(2, tapCounts.get(1).intValue());
931 
932         // Continue the button presses for the emergency gesture.
933 
934         // Presses 3 and 4 should not trigger any gesture
935         for (int i = 0; i < 2; i++) {
936             eventTime += interval;
937             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
938                     IGNORED_REPEAT);
939             outLaunched.value = false;
940             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
941                     outLaunched);
942             assertTrue(intercepted);
943             assertFalse(outLaunched.value);
944         }
945 
946         // Fifth button press should trigger the emergency flow
947         eventTime += interval;
948         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
949                 IGNORED_REPEAT);
950         outLaunched.value = false;
951         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
952                 outLaunched);
953         assertTrue(intercepted);
954         assertTrue(outLaunched.value);
955 
956         verify(mUiEventLogger, times(1))
957                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
958         verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
959 
960         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
961         verify(mMetricsLogger, times(5)).histogram(
962                 eq("power_double_tap_interval"), intervalCaptor.capture());
963         List<Integer> intervals = intervalCaptor.getAllValues();
964         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
965         assertEquals((int) interval, intervals.get(1).intValue());
966     }
967 
968     @Test
969     public void
testInterceptPowerKeyDown_fiveInboundPresses_emergencyGestureEnabled_launchesFlow()970             testInterceptPowerKeyDown_fiveInboundPresses_emergencyGestureEnabled_launchesFlow() {
971         withEmergencyGestureEnabledConfigValue(true);
972         withEmergencyGestureEnabledSettingValue(true);
973         mGestureLauncherService.updateEmergencyGestureEnabled();
974         withUserSetupCompleteValue(true);
975 
976         // First button press does nothing
977         long eventTime = INITIAL_EVENT_TIME_MILLIS;
978         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
979                 IGNORED_REPEAT);
980         boolean interactive = true;
981         MutableBoolean outLaunched = new MutableBoolean(true);
982         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
983                 outLaunched);
984         assertFalse(intercepted);
985         assertFalse(outLaunched.value);
986 
987         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
988         // 3 more button presses which should not trigger any gesture (camera gesture disabled)
989         for (int i = 0; i < 3; i++) {
990             eventTime += interval;
991             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
992                     IGNORED_REPEAT);
993             outLaunched.value = false;
994             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
995                     outLaunched);
996             assertTrue(intercepted);
997             assertFalse(outLaunched.value);
998         }
999 
1000         // Fifth button press should trigger the emergency flow
1001         eventTime += interval;
1002         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1003                 IGNORED_REPEAT);
1004         outLaunched.value = false;
1005         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1006                 outLaunched);
1007         assertTrue(outLaunched.value);
1008         assertTrue(intercepted);
1009 
1010         verify(mUiEventLogger, times(1))
1011                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
1012         verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
1013 
1014         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1015         verify(mMetricsLogger, times(5)).histogram(
1016                 eq("power_double_tap_interval"), intervalCaptor.capture());
1017         List<Integer> intervals = intervalCaptor.getAllValues();
1018         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1019         assertEquals((int) interval, intervals.get(1).intValue());
1020     }
1021 
1022     @Test
1023     public void
testInterceptPowerKeyDown_tenInboundPresses_emergencyGestureEnabled_keyIntercepted()1024             testInterceptPowerKeyDown_tenInboundPresses_emergencyGestureEnabled_keyIntercepted() {
1025         withEmergencyGestureEnabledConfigValue(true);
1026         withEmergencyGestureEnabledSettingValue(true);
1027         mGestureLauncherService.updateEmergencyGestureEnabled();
1028         withUserSetupCompleteValue(true);
1029 
1030         // First button press does nothing
1031         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1032         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1033                 IGNORED_REPEAT);
1034         boolean interactive = true;
1035         MutableBoolean outLaunched = new MutableBoolean(true);
1036         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1037                 outLaunched);
1038         assertFalse(intercepted);
1039         assertFalse(outLaunched.value);
1040 
1041         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1042         // 3 more button presses which should not trigger any gesture, but intercepts action.
1043         for (int i = 0; i < 3; i++) {
1044             eventTime += interval;
1045             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1046                     IGNORED_REPEAT);
1047             outLaunched.value = false;
1048             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1049                     outLaunched);
1050             assertTrue(intercepted);
1051             assertFalse(outLaunched.value);
1052         }
1053 
1054         // Fifth button press should trigger the emergency flow
1055         eventTime += interval;
1056         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1057                 IGNORED_REPEAT);
1058         outLaunched.value = false;
1059         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1060                 outLaunched);
1061         assertTrue(outLaunched.value);
1062         assertTrue(intercepted);
1063 
1064         // 5 more button presses which should not trigger any gesture, but intercepts action.
1065         for (int i = 0; i < 5; i++) {
1066             eventTime += interval;
1067             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1068                     IGNORED_REPEAT);
1069             outLaunched.value = false;
1070             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1071                     outLaunched);
1072             assertTrue(intercepted);
1073             assertFalse(outLaunched.value);
1074         }
1075     }
1076 
1077     @Test
testInterceptPowerKeyDown_triggerEmergency_singleTaps_cooldownTriggered()1078     public void testInterceptPowerKeyDown_triggerEmergency_singleTaps_cooldownTriggered() {
1079         // Enable power button cooldown
1080         withEmergencyGesturePowerButtonCooldownPeriodMsValue(3000);
1081         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
1082 
1083         // Trigger emergency by tapping button 5 times
1084         long eventTime = triggerEmergencyGesture();
1085 
1086         // Add enough interval to reset consecutive tap count
1087         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
1088         eventTime += interval;
1089 
1090         // Subsequent single tap is intercepted, but should not trigger any gesture
1091         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1092                 IGNORED_REPEAT);
1093         boolean interactive = true;
1094         MutableBoolean outLaunched = new MutableBoolean(true);
1095         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1096                 outLaunched);
1097         assertTrue(intercepted);
1098         assertFalse(outLaunched.value);
1099 
1100         // Add enough interval to reset consecutive tap count
1101         interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
1102         eventTime += interval;
1103 
1104         // Another single tap should be the same (intercepted but should not trigger gesture)
1105         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1106                 IGNORED_REPEAT);
1107         interactive = true;
1108         outLaunched = new MutableBoolean(true);
1109         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1110                 outLaunched);
1111         assertTrue(intercepted);
1112         assertFalse(outLaunched.value);
1113     }
1114 
1115     @Test
1116     public void
testInterceptPowerKeyDown_triggerEmergency_cameraGestureEnabled_doubleTap_cooldownTriggered()1117     testInterceptPowerKeyDown_triggerEmergency_cameraGestureEnabled_doubleTap_cooldownTriggered() {
1118         // Enable camera double tap gesture
1119         enableCameraGesture();
1120 
1121         // Enable power button cooldown
1122         withEmergencyGesturePowerButtonCooldownPeriodMsValue(3000);
1123         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
1124 
1125         // Trigger emergency by tapping button 5 times
1126         long eventTime = triggerEmergencyGesture();
1127 
1128         // Add enough interval to reset consecutive tap count
1129         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
1130         eventTime += interval;
1131 
1132         // Subsequent double tap is intercepted, but should not trigger any gesture
1133         for (int i = 0; i < 2; i++) {
1134             KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION,
1135                     IGNORED_CODE, IGNORED_REPEAT);
1136             boolean interactive = true;
1137             MutableBoolean outLaunched = new MutableBoolean(true);
1138             boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent,
1139                     interactive, outLaunched);
1140             assertTrue(intercepted);
1141             assertFalse(outLaunched.value);
1142             interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1143             eventTime += interval;
1144         }
1145     }
1146 
1147     @Test
testInterceptPowerKeyDown_triggerEmergency_fiveTaps_cooldownTriggered()1148     public void testInterceptPowerKeyDown_triggerEmergency_fiveTaps_cooldownTriggered() {
1149         // Enable power button cooldown
1150         withEmergencyGesturePowerButtonCooldownPeriodMsValue(3000);
1151         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
1152 
1153         // Trigger emergency by tapping button 5 times
1154         long eventTime = triggerEmergencyGesture();
1155 
1156         // Add enough interval to reset consecutive tap count
1157         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
1158         eventTime += interval;
1159 
1160         // Subsequent 5 taps are intercepted, but should not trigger any gesture
1161         for (int i = 0; i < 5; i++) {
1162             KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION,
1163                     IGNORED_CODE, IGNORED_REPEAT);
1164             boolean interactive = true;
1165             MutableBoolean outLaunched = new MutableBoolean(true);
1166             boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent,
1167                     interactive, outLaunched);
1168             assertTrue(intercepted);
1169             assertFalse(outLaunched.value);
1170             interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1171             eventTime += interval;
1172         }
1173     }
1174 
1175     @Test
testInterceptPowerKeyDown_triggerEmergency_fiveFastTaps_gestureIgnored()1176     public void testInterceptPowerKeyDown_triggerEmergency_fiveFastTaps_gestureIgnored() {
1177         when(mResources.getInteger(
1178                 com.android.internal.R.integer.config_defaultMinEmergencyGestureTapDurationMillis))
1179                 .thenReturn(200);
1180         // Trigger emergency by tapping button 5 times
1181         long eventTime = triggerEmergencyGesture(/* tapIntervalMs= */ 1);
1182 
1183         // Add 1 more millisecond and send the event again.
1184         eventTime += 1;
1185 
1186         // Subsequent long press is intercepted, but should not trigger any gesture
1187         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1188                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
1189                 KeyEvent.FLAG_LONG_PRESS);
1190         MutableBoolean outLaunched = new MutableBoolean(true);
1191         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(
1192                 keyEvent,
1193                 /* interactive= */ true,
1194                 outLaunched);
1195         assertFalse(intercepted);
1196         assertFalse(outLaunched.value);
1197     }
1198 
1199     @Test
testInterceptPowerKeyDown_triggerEmergency_longPress_cooldownTriggered()1200     public void testInterceptPowerKeyDown_triggerEmergency_longPress_cooldownTriggered() {
1201         // Enable power button cooldown
1202         withEmergencyGesturePowerButtonCooldownPeriodMsValue(3000);
1203         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
1204 
1205         // Trigger emergency by tapping button 5 times
1206         long eventTime = triggerEmergencyGesture();
1207 
1208         // Add enough interval to reset consecutive tap count
1209         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
1210         eventTime += interval;
1211 
1212         // Subsequent long press is intercepted, but should not trigger any gesture
1213         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1214                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
1215                 KeyEvent.FLAG_LONG_PRESS);
1216 
1217         boolean interactive = true;
1218         MutableBoolean outLaunched = new MutableBoolean(true);
1219         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1220                 outLaunched);
1221         assertTrue(intercepted);
1222         assertFalse(outLaunched.value);
1223     }
1224 
1225     @Test
testInterceptPowerKeyDown_triggerEmergency_cooldownDisabled_cooldownNotTriggered()1226     public void testInterceptPowerKeyDown_triggerEmergency_cooldownDisabled_cooldownNotTriggered() {
1227         // Disable power button cooldown by setting cooldown period to 0
1228         withEmergencyGesturePowerButtonCooldownPeriodMsValue(0);
1229         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
1230 
1231         // Trigger emergency by tapping button 5 times
1232         long eventTime = triggerEmergencyGesture();
1233 
1234         // Add enough interval to reset consecutive tap count
1235         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
1236         eventTime += interval;
1237 
1238         // Subsequent single tap is NOT intercepted
1239         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1240                 IGNORED_REPEAT);
1241         boolean interactive = true;
1242         MutableBoolean outLaunched = new MutableBoolean(true);
1243         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1244                 outLaunched);
1245         assertFalse(intercepted);
1246         assertFalse(outLaunched.value);
1247 
1248         // Add enough interval to reset consecutive tap count
1249         interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
1250         eventTime += interval;
1251 
1252         // Long press also NOT intercepted
1253         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1254                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
1255                 KeyEvent.FLAG_LONG_PRESS);
1256         interactive = true;
1257         outLaunched = new MutableBoolean(true);
1258         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1259                 outLaunched);
1260         assertFalse(intercepted);
1261         assertFalse(outLaunched.value);
1262     }
1263 
1264     @Test
1265     public void
testInterceptPowerKeyDown_triggerEmergency_outsideCooldownPeriod_cooldownNotTriggered()1266     testInterceptPowerKeyDown_triggerEmergency_outsideCooldownPeriod_cooldownNotTriggered() {
1267         // Enable power button cooldown
1268         withEmergencyGesturePowerButtonCooldownPeriodMsValue(5000);
1269         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
1270 
1271         // Trigger emergency by tapping button 5 times
1272         long eventTime = triggerEmergencyGesture();
1273 
1274         // Add enough interval to be outside of cooldown period
1275         long interval = 5001;
1276         eventTime += interval;
1277 
1278         // Subsequent single tap is NOT intercepted
1279         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1280                 IGNORED_REPEAT);
1281         boolean interactive = true;
1282         MutableBoolean outLaunched = new MutableBoolean(true);
1283         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1284                 outLaunched);
1285         assertFalse(intercepted);
1286         assertFalse(outLaunched.value);
1287 
1288         // Add enough interval to reset consecutive tap count
1289         interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
1290         eventTime += interval;
1291 
1292         // Long press also NOT intercepted
1293         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1294                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
1295                 KeyEvent.FLAG_LONG_PRESS);
1296         interactive = true;
1297         outLaunched = new MutableBoolean(true);
1298         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1299                 outLaunched);
1300         assertFalse(intercepted);
1301         assertFalse(outLaunched.value);
1302     }
1303 
1304     @Test
testInterceptPowerKeyDown_longpress()1305     public void testInterceptPowerKeyDown_longpress() {
1306         enableCameraGesture();
1307 
1308         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1309         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1310                 IGNORED_REPEAT);
1311         boolean interactive = true;
1312         MutableBoolean outLaunched = new MutableBoolean(true);
1313         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1314                 outLaunched);
1315         assertFalse(intercepted);
1316         assertFalse(outLaunched.value);
1317 
1318         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1319         eventTime += interval;
1320         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1321                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
1322                 KeyEvent.FLAG_LONG_PRESS);
1323         outLaunched.value = false;
1324         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1325                 outLaunched);
1326         assertFalse(intercepted);
1327         assertFalse(outLaunched.value);
1328 
1329         verify(mMetricsLogger, never())
1330                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1331         verify(mUiEventLogger, never()).log(any());
1332 
1333         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1334         verify(mMetricsLogger, times(1)).histogram(
1335                 eq("power_double_tap_interval"), intervalCaptor.capture());
1336         List<Integer> intervals = intervalCaptor.getAllValues();
1337         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1338 
1339         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1340         verify(mMetricsLogger, times(1)).histogram(
1341                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1342         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1343         assertEquals(1, tapCounts.get(0).intValue());
1344     }
1345 
1346     @Test
1347     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete()1348     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete() {
1349         enableCameraGesture();
1350         withUserSetupCompleteValue(false);
1351 
1352         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1353         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1354                 IGNORED_REPEAT);
1355         boolean interactive = true;
1356         MutableBoolean outLaunched = new MutableBoolean(true);
1357         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1358                 outLaunched);
1359         assertFalse(intercepted);
1360         assertFalse(outLaunched.value);
1361 
1362         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1363         eventTime += interval;
1364         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1365                 IGNORED_REPEAT);
1366         outLaunched.value = true;
1367         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1368                 outLaunched);
1369         assertFalse(intercepted);
1370         assertFalse(outLaunched.value);
1371 
1372         verify(mMetricsLogger, never())
1373                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1374         verify(mUiEventLogger, never()).log(any());
1375 
1376         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1377         verify(mMetricsLogger, times(2)).histogram(
1378                 eq("power_double_tap_interval"), intervalCaptor.capture());
1379         List<Integer> intervals = intervalCaptor.getAllValues();
1380         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1381         assertEquals((int) interval, intervals.get(1).intValue());
1382 
1383         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1384         verify(mMetricsLogger, times(2)).histogram(
1385                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1386         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1387         assertEquals(1, tapCounts.get(0).intValue());
1388         // The interval is too long to launch the camera, but short enough to count as a
1389         // sequential tap.
1390         assertEquals(2, tapCounts.get(1).intValue());
1391     }
1392 
1393     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnInteractive()1394     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnInteractive() {
1395         enableCameraGesture();
1396 
1397         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1398         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1399                 IGNORED_REPEAT);
1400         boolean interactive = true;
1401         MutableBoolean outLaunched = new MutableBoolean(true);
1402         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1403                 outLaunched);
1404         assertFalse(intercepted);
1405         assertFalse(outLaunched.value);
1406 
1407         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS;
1408         eventTime += interval;
1409         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1410                 IGNORED_REPEAT);
1411         outLaunched.value = true;
1412         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1413                 outLaunched);
1414         assertFalse(intercepted);
1415         assertFalse(outLaunched.value);
1416 
1417         verify(mMetricsLogger, never())
1418                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1419         verify(mUiEventLogger, never()).log(any());
1420 
1421         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1422         verify(mMetricsLogger, times(2)).histogram(
1423                 eq("power_double_tap_interval"), intervalCaptor.capture());
1424         List<Integer> intervals = intervalCaptor.getAllValues();
1425         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1426         assertEquals((int) interval, intervals.get(1).intValue());
1427 
1428         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1429         verify(mMetricsLogger, times(2)).histogram(
1430                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1431         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1432         assertEquals(1, tapCounts.get(0).intValue());
1433         // The interval is too long to launch the camera, but short enough to count as a
1434         // sequential tap.
1435         assertEquals(2, tapCounts.get(1).intValue());
1436     }
1437 
1438     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnInteractive()1439     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnInteractive() {
1440         enableCameraGesture();
1441 
1442         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1443         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1444                 IGNORED_REPEAT);
1445         boolean interactive = true;
1446         MutableBoolean outLaunched = new MutableBoolean(true);
1447         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1448                 outLaunched);
1449         assertFalse(intercepted);
1450         assertFalse(outLaunched.value);
1451 
1452         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
1453         eventTime += interval;
1454         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1455                 IGNORED_REPEAT);
1456         outLaunched.value = true;
1457         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1458                 outLaunched);
1459         assertFalse(intercepted);
1460         assertFalse(outLaunched.value);
1461 
1462         verify(mMetricsLogger, never())
1463                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1464         verify(mUiEventLogger, never()).log(any());
1465 
1466         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1467         verify(mMetricsLogger, times(2)).histogram(
1468                 eq("power_double_tap_interval"), intervalCaptor.capture());
1469         List<Integer> intervals = intervalCaptor.getAllValues();
1470         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1471         assertEquals((int) interval, intervals.get(1).intValue());
1472 
1473         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1474         verify(mMetricsLogger, times(2)).histogram(
1475                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1476         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1477         assertEquals(1, tapCounts.get(0).intValue());
1478         assertEquals(1, tapCounts.get(1).intValue());
1479     }
1480 
1481     @Test
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffNotInteractive()1482     public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffNotInteractive() {
1483         disableDoubleTapPowerGesture();
1484 
1485         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1486         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1487                 IGNORED_REPEAT);
1488         boolean interactive = false;
1489         MutableBoolean outLaunched = new MutableBoolean(true);
1490         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1491                 outLaunched);
1492         assertFalse(intercepted);
1493         assertFalse(outLaunched.value);
1494 
1495         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1496         eventTime += interval;
1497         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1498                 IGNORED_REPEAT);
1499         outLaunched.value = true;
1500         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1501                 outLaunched);
1502         assertFalse(intercepted);
1503         assertFalse(outLaunched.value);
1504 
1505         verify(mMetricsLogger, never())
1506                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1507         verify(mUiEventLogger, never()).log(any());
1508 
1509         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1510         verify(mMetricsLogger, times(2)).histogram(
1511                 eq("power_double_tap_interval"), intervalCaptor.capture());
1512         List<Integer> intervals = intervalCaptor.getAllValues();
1513         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1514         assertEquals((int) interval, intervals.get(1).intValue());
1515 
1516         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1517         verify(mMetricsLogger, times(2)).histogram(
1518                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1519         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1520         assertEquals(1, tapCounts.get(0).intValue());
1521         assertEquals(2, tapCounts.get(1).intValue());
1522     }
1523 
1524     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffNotInteractive()1525     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffNotInteractive() {
1526         disableDoubleTapPowerGesture();
1527 
1528         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1529         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1530                 IGNORED_REPEAT);
1531         boolean interactive = false;
1532         MutableBoolean outLaunched = new MutableBoolean(true);
1533         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1534                 outLaunched);
1535         assertFalse(intercepted);
1536         assertFalse(outLaunched.value);
1537 
1538         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS;
1539         eventTime += interval;
1540         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1541                 IGNORED_REPEAT);
1542         outLaunched.value = true;
1543         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1544                 outLaunched);
1545         assertFalse(intercepted);
1546         assertFalse(outLaunched.value);
1547         verify(mMetricsLogger, never())
1548                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1549         verify(mUiEventLogger, never()).log(any());
1550 
1551         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1552         verify(mMetricsLogger, times(2)).histogram(
1553                 eq("power_double_tap_interval"), intervalCaptor.capture());
1554         List<Integer> intervals = intervalCaptor.getAllValues();
1555         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1556         assertEquals((int) interval, intervals.get(1).intValue());
1557 
1558         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1559         verify(mMetricsLogger, times(2)).histogram(
1560                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1561         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1562         assertEquals(1, tapCounts.get(0).intValue());
1563         // The interval is too long to launch the camera, but short enough to count as a
1564         // sequential tap.
1565         assertEquals(2, tapCounts.get(1).intValue());
1566     }
1567 
1568     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffNotInteractive()1569     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffNotInteractive() {
1570         disableDoubleTapPowerGesture();
1571 
1572         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1573         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1574                 IGNORED_REPEAT);
1575         boolean interactive = false;
1576         MutableBoolean outLaunched = new MutableBoolean(true);
1577         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1578                 outLaunched);
1579         assertFalse(intercepted);
1580         assertFalse(outLaunched.value);
1581 
1582         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
1583         eventTime += interval;
1584         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1585                 IGNORED_REPEAT);
1586         outLaunched.value = true;
1587         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1588                 outLaunched);
1589         assertFalse(intercepted);
1590         assertFalse(outLaunched.value);
1591         verify(mMetricsLogger, never())
1592                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1593         verify(mUiEventLogger, never()).log(any());
1594 
1595         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1596         verify(mMetricsLogger, times(2)).histogram(
1597                 eq("power_double_tap_interval"), intervalCaptor.capture());
1598         List<Integer> intervals = intervalCaptor.getAllValues();
1599         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1600         assertEquals((int) interval, intervals.get(1).intValue());
1601 
1602         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1603         verify(mMetricsLogger, times(2)).histogram(
1604                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1605         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1606         assertEquals(1, tapCounts.get(0).intValue());
1607         assertEquals(1, tapCounts.get(1).intValue());
1608     }
1609 
1610     @Test
1611     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupComplete()1612     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupComplete() {
1613         enableCameraGesture();
1614 
1615         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1616         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1617                 IGNORED_REPEAT);
1618         boolean interactive = false;
1619         MutableBoolean outLaunched = new MutableBoolean(true);
1620         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1621                 outLaunched);
1622         assertFalse(intercepted);
1623         assertFalse(outLaunched.value);
1624 
1625         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1626         eventTime += interval;
1627         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1628                 IGNORED_REPEAT);
1629         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1630                 outLaunched);
1631         assertFalse(intercepted);
1632         assertTrue(outLaunched.value);
1633 
1634         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
1635                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
1636         verify(mMetricsLogger)
1637                 .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
1638         verify(mUiEventLogger, times(1))
1639                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
1640 
1641         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1642         verify(mMetricsLogger, times(2)).histogram(
1643                 eq("power_double_tap_interval"), intervalCaptor.capture());
1644         List<Integer> intervals = intervalCaptor.getAllValues();
1645         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1646         assertEquals((int) interval, intervals.get(1).intValue());
1647 
1648         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1649         verify(mMetricsLogger, times(2)).histogram(
1650                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1651         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1652         assertEquals(1, tapCounts.get(0).intValue());
1653         assertEquals(2, tapCounts.get(1).intValue());
1654     }
1655 
1656     @Test
1657     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupIncomplete()1658     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupIncomplete() {
1659         enableCameraGesture();
1660         withUserSetupCompleteValue(false);
1661 
1662         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1663         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1664                 IGNORED_REPEAT);
1665         boolean interactive = false;
1666         MutableBoolean outLaunched = new MutableBoolean(true);
1667         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1668                 outLaunched);
1669         assertFalse(intercepted);
1670         assertFalse(outLaunched.value);
1671 
1672         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1673         eventTime += interval;
1674         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1675                 IGNORED_REPEAT);
1676         outLaunched.value = true;
1677         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1678                 outLaunched);
1679         assertFalse(intercepted);
1680         assertFalse(outLaunched.value);
1681 
1682         verify(mMetricsLogger, never())
1683                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1684         verify(mUiEventLogger, never()).log(any());
1685 
1686         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1687         verify(mMetricsLogger, times(2)).histogram(
1688                 eq("power_double_tap_interval"), intervalCaptor.capture());
1689         List<Integer> intervals = intervalCaptor.getAllValues();
1690         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1691         assertEquals((int) interval, intervals.get(1).intValue());
1692 
1693         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1694         verify(mMetricsLogger, times(2)).histogram(
1695                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1696         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1697         assertEquals(1, tapCounts.get(0).intValue());
1698         assertEquals(2, tapCounts.get(1).intValue());
1699     }
1700 
1701     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnNotInteractive()1702     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnNotInteractive() {
1703         enableCameraGesture();
1704 
1705         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1706         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1707                 IGNORED_REPEAT);
1708         boolean interactive = false;
1709         MutableBoolean outLaunched = new MutableBoolean(true);
1710         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1711                 outLaunched);
1712         assertFalse(intercepted);
1713         assertFalse(outLaunched.value);
1714 
1715         final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS;
1716         eventTime += interval;
1717         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1718                 IGNORED_REPEAT);
1719         outLaunched.value = true;
1720         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1721                 outLaunched);
1722         assertFalse(intercepted);
1723         assertFalse(outLaunched.value);
1724 
1725         verify(mMetricsLogger, never())
1726                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1727         verify(mUiEventLogger, never()).log(any());
1728 
1729         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1730         verify(mMetricsLogger, times(2)).histogram(
1731                 eq("power_double_tap_interval"), intervalCaptor.capture());
1732         List<Integer> intervals = intervalCaptor.getAllValues();
1733         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1734         assertEquals((int) interval, intervals.get(1).intValue());
1735 
1736         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1737         verify(mMetricsLogger, times(2)).histogram(
1738                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1739         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1740         assertEquals(1, tapCounts.get(0).intValue());
1741         // The interval is too long to launch the camera, but short enough to count as a
1742         // sequential tap.
1743         assertEquals(2, tapCounts.get(1).intValue());
1744     }
1745 
1746     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnNotInteractive()1747     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnNotInteractive() {
1748         enableCameraGesture();
1749 
1750         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1751         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1752                 IGNORED_REPEAT);
1753         boolean interactive = false;
1754         MutableBoolean outLaunched = new MutableBoolean(true);
1755         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1756                 outLaunched);
1757         assertFalse(intercepted);
1758         assertFalse(outLaunched.value);
1759 
1760         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
1761         eventTime += interval;
1762         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1763                 IGNORED_REPEAT);
1764         outLaunched.value = true;
1765         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1766                 outLaunched);
1767         assertFalse(intercepted);
1768         assertFalse(outLaunched.value);
1769 
1770         verify(mMetricsLogger, never())
1771                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1772         verify(mUiEventLogger, never()).log(any());
1773 
1774         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1775         verify(mMetricsLogger, times(2)).histogram(
1776                 eq("power_double_tap_interval"), intervalCaptor.capture());
1777         List<Integer> intervals = intervalCaptor.getAllValues();
1778         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1779         assertEquals((int) interval, intervals.get(1).intValue());
1780 
1781         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1782         verify(mMetricsLogger, times(2)).histogram(
1783                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1784         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1785         assertEquals(1, tapCounts.get(0).intValue());
1786         assertEquals(1, tapCounts.get(1).intValue());
1787     }
1788 
1789     /**
1790      * Helper method to trigger emergency gesture by pressing button for 5 times.
1791      *
1792      * @return last event time.
1793      */
triggerEmergencyGesture()1794     private long triggerEmergencyGesture() {
1795         return triggerEmergencyGesture(POWER_DOUBLE_TAP_MAX_TIME_MS - 1);
1796     }
1797 
1798     /**
1799      * Helper method to trigger emergency gesture by pressing button for 5 times with
1800      * specified interval between each tap
1801      *
1802      * @return last event time.
1803      */
triggerEmergencyGesture(long tapIntervalMs)1804     private long triggerEmergencyGesture(long tapIntervalMs) {
1805         // Enable emergency power gesture
1806         withEmergencyGestureEnabledConfigValue(true);
1807         withEmergencyGestureEnabledSettingValue(true);
1808         mGestureLauncherService.updateEmergencyGestureEnabled();
1809         withUserSetupCompleteValue(true);
1810 
1811         // 4 button presses
1812         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1813         boolean interactive = true;
1814         KeyEvent keyEvent;
1815         MutableBoolean outLaunched = new MutableBoolean(false);
1816         for (int i = 0; i < 4; i++) {
1817             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1818                     IGNORED_REPEAT);
1819             mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive, outLaunched);
1820             eventTime += tapIntervalMs;
1821         }
1822 
1823         // 5th button press should trigger the emergency flow
1824         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1825                 IGNORED_REPEAT);
1826         outLaunched.value = false;
1827         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1828                 outLaunched);
1829         long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
1830                 mContext.getContentResolver(),
1831                 Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
1832                 200);
1833         assertTrue(intercepted);
1834         if (tapIntervalMs * 4 > emergencyGestureTapDetectionMinTimeMs) {
1835             assertTrue(outLaunched.value);
1836             verify(mUiEventLogger, times(1))
1837                     .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
1838             verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
1839         } else {
1840             assertFalse(outLaunched.value);
1841             verify(mUiEventLogger, never())
1842                     .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
1843             verify(mStatusBarManagerInternal, never()).onEmergencyActionLaunchGestureDetected();
1844         }
1845         return eventTime;
1846     }
1847 
withCameraDoubleTapPowerEnableConfigValue(boolean enableConfigValue)1848     private void withCameraDoubleTapPowerEnableConfigValue(boolean enableConfigValue) {
1849         when(mResources.getBoolean(
1850                 com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled))
1851                 .thenReturn(enableConfigValue);
1852     }
1853 
withDoubleTapPowerModeConfigValue( int modeConfigValue)1854     private void withDoubleTapPowerModeConfigValue(
1855             int modeConfigValue) {
1856         when(mResources.getInteger(com.android.internal.R.integer.config_doubleTapPowerGestureMode))
1857                 .thenReturn(modeConfigValue);
1858     }
1859 
withMultiTargetDoubleTapPowerGestureEnableSettingValue(boolean enable)1860     private void withMultiTargetDoubleTapPowerGestureEnableSettingValue(boolean enable) {
1861         Settings.Secure.putIntForUser(
1862                 mContentResolver,
1863                 Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED,
1864                 enable ? 1 : 0,
1865                 UserHandle.USER_CURRENT);
1866     }
1867 
withDoubleTapPowerGestureActionSettingValue(int action)1868     private void withDoubleTapPowerGestureActionSettingValue(int action) {
1869         Settings.Secure.putIntForUser(
1870                 mContentResolver,
1871                 Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
1872                 action,
1873                 UserHandle.USER_CURRENT);
1874     }
1875 
withDefaultDoubleTapPowerGestureActionConfig(int action)1876     private void withDefaultDoubleTapPowerGestureActionConfig(int action) {
1877         when(mResources.getInteger(
1878                 com.android.internal.R.integer.config_doubleTapPowerGestureMultiTargetDefaultAction
1879         )).thenReturn(action);
1880     }
1881 
withEmergencyGestureEnabledConfigValue(boolean enableConfigValue)1882     private void withEmergencyGestureEnabledConfigValue(boolean enableConfigValue) {
1883         when(mResources.getBoolean(
1884                 com.android.internal.R.bool.config_emergencyGestureEnabled))
1885                 .thenReturn(enableConfigValue);
1886     }
1887 
withCameraDoubleTapPowerDisableSettingValue(int disableSettingValue)1888     private void withCameraDoubleTapPowerDisableSettingValue(int disableSettingValue) {
1889         Settings.Secure.putIntForUser(
1890                 mContentResolver,
1891                 Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
1892                 disableSettingValue,
1893                 UserHandle.USER_CURRENT);
1894     }
1895 
withEmergencyGestureEnabledSettingValue(boolean enable)1896     private void withEmergencyGestureEnabledSettingValue(boolean enable) {
1897         Settings.Secure.putIntForUser(
1898                 mContentResolver,
1899                 Settings.Secure.EMERGENCY_GESTURE_ENABLED,
1900                 enable ? 1 : 0,
1901                 UserHandle.USER_CURRENT);
1902     }
1903 
withEmergencyGesturePowerButtonCooldownPeriodMsValue(int period)1904     private void withEmergencyGesturePowerButtonCooldownPeriodMsValue(int period) {
1905         Settings.Global.putInt(
1906                 mContentResolver,
1907                 Settings.Global.EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS,
1908                 period);
1909     }
1910 
withUserSetupCompleteValue(boolean userSetupComplete)1911     private void withUserSetupCompleteValue(boolean userSetupComplete) {
1912         int userSetupCompleteValue = userSetupComplete ? 1 : 0;
1913         Settings.Secure.putIntForUser(
1914                 mContentResolver,
1915                 Settings.Secure.USER_SETUP_COMPLETE,
1916                 userSetupCompleteValue,
1917                 UserHandle.USER_CURRENT);
1918     }
1919 
setUpGetGestureTargetActivityPendingIntent(PendingIntent pendingIntent)1920     private void setUpGetGestureTargetActivityPendingIntent(PendingIntent pendingIntent) {
1921         doAnswer(
1922                 invocation -> {
1923                     QuickAccessWalletClient.GesturePendingIntentCallback callback =
1924                             (QuickAccessWalletClient.GesturePendingIntentCallback)
1925                                     invocation.getArguments()[1];
1926                     callback.onGesturePendingIntentRetrieved(pendingIntent);
1927                     return null;
1928                 })
1929                 .when(mQuickAccessWalletClient)
1930                 .getGestureTargetActivityPendingIntent(any(), any());
1931     }
1932 
setUpWalletFallbackPendingIntent(PendingIntent pendingIntent)1933     private void setUpWalletFallbackPendingIntent(PendingIntent pendingIntent) {
1934         doAnswer(
1935                 invocation -> {
1936                     QuickAccessWalletClient.WalletPendingIntentCallback callback =
1937                             (QuickAccessWalletClient.WalletPendingIntentCallback)
1938                                     invocation.getArguments()[1];
1939                     callback.onWalletPendingIntentRetrieved(pendingIntent);
1940                     return null;
1941                 })
1942                 .when(mQuickAccessWalletClient)
1943                 .getWalletPendingIntent(any(), any());
1944     }
1945 
enableWalletGesture()1946     private void enableWalletGesture() {
1947         withDoubleTapPowerGestureActionSettingValue(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER);
1948         withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
1949         withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
1950 
1951         mGestureLauncherService.updateWalletDoubleTapPowerEnabled();
1952         withUserSetupCompleteValue(true);
1953     }
1954 
enableEmergencyGesture()1955     private void enableEmergencyGesture() {
1956         withEmergencyGestureEnabledConfigValue(true);
1957         withEmergencyGestureEnabledSettingValue(true);
1958         mGestureLauncherService.updateEmergencyGestureEnabled();
1959         withUserSetupCompleteValue(true);
1960     }
1961 
enableCameraGesture()1962     private void enableCameraGesture() {
1963         if (launchWalletOptionOnPowerDoubleTap()) {
1964             withDoubleTapPowerModeConfigValue(
1965                     DOUBLE_TAP_POWER_MULTI_TARGET_MODE);
1966             withMultiTargetDoubleTapPowerGestureEnableSettingValue(true);
1967             withDoubleTapPowerGestureActionSettingValue(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER);
1968         } else {
1969             withCameraDoubleTapPowerEnableConfigValue(true);
1970             withCameraDoubleTapPowerDisableSettingValue(0);
1971         }
1972         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1973         withUserSetupCompleteValue(true);
1974     }
1975 
disableDoubleTapPowerGesture()1976     private void disableDoubleTapPowerGesture() {
1977         if (launchWalletOptionOnPowerDoubleTap()) {
1978             withDoubleTapPowerModeConfigValue(DOUBLE_TAP_POWER_DISABLED_MODE);
1979             withMultiTargetDoubleTapPowerGestureEnableSettingValue(false);
1980         } else {
1981             withCameraDoubleTapPowerEnableConfigValue(false);
1982             withCameraDoubleTapPowerDisableSettingValue(1);
1983         }
1984         mGestureLauncherService.updateWalletDoubleTapPowerEnabled();
1985         withUserSetupCompleteValue(true);
1986     }
1987 
sendPowerKeyDownToGestureLauncherServiceAndAssertValues( long eventTime, boolean expectedIntercept, boolean expectedOutLaunchedValue)1988     private void sendPowerKeyDownToGestureLauncherServiceAndAssertValues(
1989             long eventTime, boolean expectedIntercept, boolean expectedOutLaunchedValue) {
1990         KeyEvent keyEvent =
1991                 new KeyEvent(
1992                         IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT);
1993         boolean interactive = true;
1994         MutableBoolean outLaunched = new MutableBoolean(true);
1995         boolean intercepted =
1996                 mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive, outLaunched);
1997         assertEquals(intercepted, expectedIntercept);
1998         assertEquals(outLaunched.value, expectedOutLaunchedValue);
1999     }
2000 }
2001