• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.server.wm;
18 
19 import static android.app.AppOpsManager.MODE_ALLOWED;
20 import static android.app.AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW;
21 import static android.server.wm.UiDeviceUtils.pressUnlockButton;
22 import static android.server.wm.UiDeviceUtils.pressWakeupButton;
23 import static android.server.wm.WindowManagerState.STATE_RESUMED;
24 import static android.server.wm.overlay.Components.OverlayActivity.EXTRA_TOKEN;
25 
26 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
27 
28 import static com.google.common.truth.Truth.assertThat;
29 
30 import static junit.framework.Assert.assertEquals;
31 import static junit.framework.Assert.assertTrue;
32 import static junit.framework.Assert.fail;
33 
34 import android.app.Activity;
35 import android.app.ActivityManager;
36 import android.app.ActivityOptions;
37 import android.app.Instrumentation;
38 import android.app.NotificationManager;
39 import android.content.ComponentName;
40 import android.content.ContentResolver;
41 import android.content.Context;
42 import android.content.Intent;
43 import android.content.res.Resources;
44 import android.graphics.Rect;
45 import android.hardware.input.InputManager;
46 import android.os.Bundle;
47 import android.os.ConditionVariable;
48 import android.os.Handler;
49 import android.os.IBinder;
50 import android.os.Looper;
51 import android.os.SystemClock;
52 import android.platform.test.annotations.Presubmit;
53 import android.provider.Settings;
54 import android.server.wm.overlay.Components;
55 import android.server.wm.overlay.R;
56 import android.server.wm.shared.BlockingResultReceiver;
57 import android.server.wm.shared.IUntrustedTouchTestService;
58 import android.util.ArrayMap;
59 import android.util.ArraySet;
60 import android.view.Display;
61 import android.view.Gravity;
62 import android.view.MotionEvent;
63 import android.view.View;
64 import android.view.WindowManager;
65 import android.view.WindowManager.LayoutParams;
66 import android.widget.Toast;
67 
68 import androidx.annotation.AnimRes;
69 import androidx.annotation.Nullable;
70 import androidx.test.rule.ActivityTestRule;
71 
72 import com.android.compatibility.common.util.AppOpsUtils;
73 import com.android.compatibility.common.util.SystemUtil;
74 
75 import org.junit.After;
76 import org.junit.Before;
77 import org.junit.Rule;
78 import org.junit.Test;
79 import org.junit.rules.TestName;
80 
81 import java.util.Map;
82 import java.util.Set;
83 import java.util.concurrent.atomic.AtomicInteger;
84 
85 @Presubmit
86 public class WindowUntrustedTouchTest {
87     private static final String TAG = "WindowUntrustedTouchTest";
88 
89     /**
90      * Opacity (or alpha) is represented as a half-precision floating point number (16b) in surface
91      * flinger and the conversion from the single-precision float provided to window manager happens
92      * in Layer::setAlpha() by android::half::ftoh(). So, many small non-zero values provided to
93      * window manager end up becoming zero due to loss of precision (this is fine as long as the
94      * zeros are also used to render the pixels on the screen). So, the minimum opacity possible is
95      * actually the minimum positive value representable in half-precision float, which is
96      * 0_00001_0000000000, whose equivalent in float is 0_01110001_00000000000000000000000.
97      *
98      * Note that from float -> half conversion code we don't produce any subnormal half-precision
99      * floats during conversion.
100      */
101     public static final float MIN_POSITIVE_OPACITY =
102             Float.intBitsToFloat(0b00111000100000000000000000000000);
103 
104     private static final float MAXIMUM_OBSCURING_OPACITY = .8f;
105     private static final long TIMEOUT_MS = 3000L;
106     private static final long MAX_ANIMATION_DURATION_MS = 3000L;
107     private static final long ANIMATION_DURATION_TOLERANCE_MS = 500L;
108 
109     private static final int OVERLAY_COLOR = 0xFFFF0000;
110     private static final int ACTIVITY_COLOR = 0xFFFFFFFF;
111 
112     private static final int FEATURE_MODE_DISABLED = 0;
113     private static final int FEATURE_MODE_PERMISSIVE = 1;
114     private static final int FEATURE_MODE_BLOCK = 2;
115 
116     private static final String APP_SELF =
117             WindowUntrustedTouchTest.class.getPackage().getName() + ".cts";
118     private static final String APP_A =
119             android.server.wm.second.Components.class.getPackage().getName();
120     private static final String APP_B =
121             android.server.wm.third.Components.class.getPackage().getName();
122     private static final String WINDOW_1 = "W1";
123     private static final String WINDOW_2 = "W2";
124 
125     private static final String[] APPS = {APP_A, APP_B};
126 
127     private static final String SETTING_MAXIMUM_OBSCURING_OPACITY =
128             "maximum_obscuring_opacity_for_touch";
129 
130     private final WindowManagerStateHelper mWmState = new WindowManagerStateHelper();
131     private final Map<String, FutureConnection<IUntrustedTouchTestService>> mConnections =
132             new ArrayMap<>();
133     private Instrumentation mInstrumentation;
134     private Context mContext;
135     private Resources mResources;
136     private ContentResolver mContentResolver;
137     private TouchHelper mTouchHelper;
138     private Handler mMainHandler;
139     private InputManager mInputManager;
140     private WindowManager mWindowManager;
141     private ActivityManager mActivityManager;
142     private NotificationManager mNotificationManager;
143     private TestActivity mActivity;
144     private View mContainer;
145     private Toast mToast;
146     private float mPreviousTouchOpacity;
147     private int mPreviousMode;
148     private int mPreviousSawAppOp;
149     private final Set<String> mSawWindowsAdded = new ArraySet<>();
150     private final AtomicInteger mTouchesReceived = new AtomicInteger(0);
151 
152     @Rule
153     public TestName testNameRule = new TestName();
154 
155     @Rule
156     public ActivityTestRule<TestActivity> activityRule = new ActivityTestRule<>(TestActivity.class);
157 
158     @Before
setUp()159     public void setUp() throws Exception {
160         mActivity = activityRule.getActivity();
161         mContainer = mActivity.view;
162         mContainer.setOnTouchListener(this::onTouchEvent);
163         mInstrumentation = getInstrumentation();
164         mContext = mInstrumentation.getContext();
165         mResources = mContext.getResources();
166         mContentResolver = mContext.getContentResolver();
167         mTouchHelper = new TouchHelper(mInstrumentation, mWmState);
168         mMainHandler = new Handler(Looper.getMainLooper());
169         mInputManager = mContext.getSystemService(InputManager.class);
170         mWindowManager = mContext.getSystemService(WindowManager.class);
171         mActivityManager = mContext.getSystemService(ActivityManager.class);
172         mNotificationManager = mContext.getSystemService(NotificationManager.class);
173 
174         mPreviousSawAppOp = AppOpsUtils.getOpMode(APP_SELF, OPSTR_SYSTEM_ALERT_WINDOW);
175         AppOpsUtils.setOpMode(APP_SELF, OPSTR_SYSTEM_ALERT_WINDOW, MODE_ALLOWED);
176         mPreviousTouchOpacity = setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
177         mPreviousMode = setBlockUntrustedTouchesMode(FEATURE_MODE_BLOCK);
178         SystemUtil.runWithShellPermissionIdentity(
179                 () -> mNotificationManager.setToastRateLimitingEnabled(false));
180 
181         pressWakeupButton();
182         pressUnlockButton();
183     }
184 
185     @After
tearDown()186     public void tearDown() throws Throwable {
187         mWmState.waitForAppTransitionIdleOnDisplay(Display.DEFAULT_DISPLAY);
188         mTouchesReceived.set(0);
189         removeOverlays();
190         for (FutureConnection<IUntrustedTouchTestService> connection : mConnections.values()) {
191             mContext.unbindService(connection);
192         }
193         mConnections.clear();
194         for (String app : APPS) {
195             stopPackage(app);
196         }
197         SystemUtil.runWithShellPermissionIdentity(
198                 () -> mNotificationManager.setToastRateLimitingEnabled(true));
199         setBlockUntrustedTouchesMode(mPreviousMode);
200         setMaximumObscuringOpacityForTouch(mPreviousTouchOpacity);
201         AppOpsUtils.setOpMode(APP_SELF, OPSTR_SYSTEM_ALERT_WINDOW, mPreviousSawAppOp);
202     }
203 
204     @Test
testWhenFeatureInDisabledModeAndActivityWindowAbove_allowsTouch()205     public void testWhenFeatureInDisabledModeAndActivityWindowAbove_allowsTouch()
206             throws Throwable {
207         setBlockUntrustedTouchesMode(FEATURE_MODE_DISABLED);
208         addActivityOverlay(APP_A, /* opacity */ .9f);
209 
210         mTouchHelper.tapOnViewCenter(mContainer);
211 
212         assertTouchReceived();
213     }
214 
215     @Test
testWhenFeatureInPermissiveModeAndActivityWindowAbove_allowsTouch()216     public void testWhenFeatureInPermissiveModeAndActivityWindowAbove_allowsTouch()
217             throws Throwable {
218         setBlockUntrustedTouchesMode(FEATURE_MODE_PERMISSIVE);
219         addActivityOverlay(APP_A, /* opacity */ .9f);
220 
221         mTouchHelper.tapOnViewCenter(mContainer);
222 
223         assertTouchReceived();
224     }
225 
226     @Test
testWhenFeatureInBlockModeAndActivityWindowAbove_blocksTouch()227     public void testWhenFeatureInBlockModeAndActivityWindowAbove_blocksTouch()
228             throws Throwable {
229         setBlockUntrustedTouchesMode(FEATURE_MODE_BLOCK);
230         addActivityOverlay(APP_A, /* opacity */ .9f);
231 
232         mTouchHelper.tapOnViewCenter(mContainer);
233 
234         assertTouchNotReceived();
235     }
236 
237     @Test
testMaximumObscuringOpacity()238     public void testMaximumObscuringOpacity() throws Throwable {
239         // Setting the previous value since we override this on setUp()
240         setMaximumObscuringOpacityForTouch(mPreviousTouchOpacity);
241 
242         assertEquals(0.8f, mInputManager.getMaximumObscuringOpacityForTouch());
243     }
244 
245     @Test
testAfterSettingThreshold_returnsThresholdSet()246     public void testAfterSettingThreshold_returnsThresholdSet()
247             throws Throwable {
248         float threshold = .123f;
249         setMaximumObscuringOpacityForTouch(threshold);
250 
251         assertEquals(threshold, mInputManager.getMaximumObscuringOpacityForTouch());
252     }
253 
254     @Test
testAfterSettingFeatureMode_returnsModeSet()255     public void testAfterSettingFeatureMode_returnsModeSet()
256             throws Throwable {
257         // Make sure the previous mode is different
258         setBlockUntrustedTouchesMode(FEATURE_MODE_BLOCK);
259         assertEquals(FEATURE_MODE_BLOCK, mInputManager.getBlockUntrustedTouchesMode(mContext));
260         setBlockUntrustedTouchesMode(FEATURE_MODE_PERMISSIVE);
261 
262         assertEquals(FEATURE_MODE_PERMISSIVE, mInputManager.getBlockUntrustedTouchesMode(mContext));
263     }
264 
265     @Test(expected = IllegalArgumentException.class)
testAfterSettingThresholdLessThan0_throws()266     public void testAfterSettingThresholdLessThan0_throws() throws Throwable {
267         setMaximumObscuringOpacityForTouch(-.5f);
268     }
269 
270     @Test(expected = IllegalArgumentException.class)
testAfterSettingThresholdGreaterThan1_throws()271     public void testAfterSettingThresholdGreaterThan1_throws() throws Throwable {
272         setMaximumObscuringOpacityForTouch(1.5f);
273     }
274 
275     /** This is testing what happens if setting is overridden manually */
276     @Test
testAfterSettingThresholdGreaterThan1ViaSettings_previousThresholdIsUsed()277     public void testAfterSettingThresholdGreaterThan1ViaSettings_previousThresholdIsUsed()
278             throws Throwable {
279         setMaximumObscuringOpacityForTouch(.8f);
280         assertEquals(.8f, mInputManager.getMaximumObscuringOpacityForTouch());
281         SystemUtil.runWithShellPermissionIdentity(() -> {
282             Settings.Global.putFloat(mContentResolver, SETTING_MAXIMUM_OBSCURING_OPACITY, 1.5f);
283         });
284         addSawOverlay(APP_A, WINDOW_1, 9.f);
285 
286         mTouchHelper.tapOnViewCenter(mContainer);
287 
288         // Blocks because it's using previous maximum of .8
289         assertTouchNotReceived();
290     }
291 
292     /** This is testing what happens if setting is overridden manually */
293     @Test
testAfterSettingThresholdLessThan0ViaSettings_previousThresholdIsUsed()294     public void testAfterSettingThresholdLessThan0ViaSettings_previousThresholdIsUsed()
295             throws Throwable {
296         setMaximumObscuringOpacityForTouch(.8f);
297         assertEquals(.8f, mInputManager.getMaximumObscuringOpacityForTouch());
298         SystemUtil.runWithShellPermissionIdentity(() -> {
299             Settings.Global.putFloat(mContentResolver, SETTING_MAXIMUM_OBSCURING_OPACITY, -.5f);
300         });
301         addSawOverlay(APP_A, WINDOW_1, .7f);
302 
303         mTouchHelper.tapOnViewCenter(mContainer);
304 
305         // Allows because it's using previous maximum of .8
306         assertTouchReceived();
307     }
308 
309     /** SAWs */
310 
311     @Test
testWhenOneSawWindowAboveThreshold_blocksTouch()312     public void testWhenOneSawWindowAboveThreshold_blocksTouch() throws Throwable {
313         addSawOverlay(APP_A, WINDOW_1, .9f);
314 
315         mTouchHelper.tapOnViewCenter(mContainer);
316 
317         assertTouchNotReceived();
318     }
319 
320     @Test
testWhenOneSawWindowBelowThreshold_allowsTouch()321     public void testWhenOneSawWindowBelowThreshold_allowsTouch() throws Throwable {
322         addSawOverlay(APP_A, WINDOW_1, .7f);
323 
324         mTouchHelper.tapOnViewCenter(mContainer);
325 
326         assertTouchReceived();
327     }
328 
329     @Test
testWhenOneSawWindowWithZeroOpacity_allowsTouch()330     public void testWhenOneSawWindowWithZeroOpacity_allowsTouch() throws Throwable {
331         addSawOverlay(APP_A, WINDOW_1, 0f);
332 
333         mTouchHelper.tapOnViewCenter(mContainer);
334 
335         assertTouchReceived();
336     }
337 
338     @Test
testWhenOneSawWindowAtThreshold_allowsTouch()339     public void testWhenOneSawWindowAtThreshold_allowsTouch() throws Throwable {
340         addSawOverlay(APP_A, WINDOW_1, MAXIMUM_OBSCURING_OPACITY);
341 
342         mTouchHelper.tapOnViewCenter(mContainer);
343 
344         assertTouchReceived();
345     }
346 
347     @Test
testWhenTwoSawWindowsFromSameAppTogetherBelowThreshold_allowsTouch()348     public void testWhenTwoSawWindowsFromSameAppTogetherBelowThreshold_allowsTouch()
349             throws Throwable {
350         // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
351         addSawOverlay(APP_A, WINDOW_1, .5f);
352         addSawOverlay(APP_A, WINDOW_2, .5f);
353 
354         mTouchHelper.tapOnViewCenter(mContainer);
355 
356         assertTouchReceived();
357     }
358 
359     @Test
testWhenTwoSawWindowsFromSameAppTogetherAboveThreshold_blocksTouch()360     public void testWhenTwoSawWindowsFromSameAppTogetherAboveThreshold_blocksTouch()
361             throws Throwable {
362         // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
363         addSawOverlay(APP_A, WINDOW_1, .7f);
364         addSawOverlay(APP_A, WINDOW_2, .7f);
365 
366         mTouchHelper.tapOnViewCenter(mContainer);
367 
368         assertTouchNotReceived();
369     }
370 
371     @Test
testWhenTwoSawWindowsFromDifferentAppsEachBelowThreshold_allowsTouch()372     public void testWhenTwoSawWindowsFromDifferentAppsEachBelowThreshold_allowsTouch()
373             throws Throwable {
374         addSawOverlay(APP_A, WINDOW_1, .7f);
375         addSawOverlay(APP_B, WINDOW_2, .7f);
376 
377         mTouchHelper.tapOnViewCenter(mContainer);
378 
379         assertTouchReceived();
380     }
381 
382     @Test
testWhenOneSawWindowAboveThresholdAndSelfSawWindow_blocksTouch()383     public void testWhenOneSawWindowAboveThresholdAndSelfSawWindow_blocksTouch()
384             throws Throwable {
385         addSawOverlay(APP_A, WINDOW_1, .9f);
386         addSawOverlay(APP_SELF, WINDOW_1, .7f);
387 
388         mTouchHelper.tapOnViewCenter(mContainer);
389 
390         assertTouchNotReceived();
391     }
392 
393     @Test
testWhenOneSawWindowBelowThresholdAndSelfSawWindow_allowsTouch()394     public void testWhenOneSawWindowBelowThresholdAndSelfSawWindow_allowsTouch()
395             throws Throwable {
396         addSawOverlay(APP_A, WINDOW_1, .7f);
397         addSawOverlay(APP_SELF, WINDOW_1, .7f);
398 
399         mTouchHelper.tapOnViewCenter(mContainer);
400 
401         assertTouchReceived();
402     }
403 
404     @Test
testWhenTwoSawWindowsTogetherBelowThresholdAndSelfSawWindow_allowsTouch()405     public void testWhenTwoSawWindowsTogetherBelowThresholdAndSelfSawWindow_allowsTouch()
406             throws Throwable {
407         // Resulting opacity for A = 1 - (1 - 0.5)*(1 - 0.5) = .75
408         addSawOverlay(APP_A, WINDOW_1, .5f);
409         addSawOverlay(APP_A, WINDOW_1, .5f);
410         addSawOverlay(APP_SELF, WINDOW_1, .7f);
411 
412         mTouchHelper.tapOnViewCenter(mContainer);
413 
414         assertTouchReceived();
415     }
416 
417     @Test
testWhenThresholdIs0AndSawWindowAtThreshold_allowsTouch()418     public void testWhenThresholdIs0AndSawWindowAtThreshold_allowsTouch()
419             throws Throwable {
420         setMaximumObscuringOpacityForTouch(0);
421         addSawOverlay(APP_A, WINDOW_1, 0);
422 
423         mTouchHelper.tapOnViewCenter(mContainer);
424 
425         assertTouchReceived();
426     }
427 
428     @Test
testWhenThresholdIs0AndSawWindowAboveThreshold_blocksTouch()429     public void testWhenThresholdIs0AndSawWindowAboveThreshold_blocksTouch()
430             throws Throwable {
431         setMaximumObscuringOpacityForTouch(0);
432         addSawOverlay(APP_A, WINDOW_1, .1f);
433 
434         mTouchHelper.tapOnViewCenter(mContainer);
435 
436         assertTouchNotReceived();
437     }
438 
439     @Test
testWhenThresholdIs1AndSawWindowAtThreshold_allowsTouch()440     public void testWhenThresholdIs1AndSawWindowAtThreshold_allowsTouch()
441             throws Throwable {
442         setMaximumObscuringOpacityForTouch(1);
443         addSawOverlay(APP_A, WINDOW_1, 1);
444 
445         mTouchHelper.tapOnViewCenter(mContainer);
446 
447         assertTouchReceived();
448     }
449 
450     @Test
testWhenThresholdIs1AndSawWindowBelowThreshold_allowsTouch()451     public void testWhenThresholdIs1AndSawWindowBelowThreshold_allowsTouch()
452             throws Throwable {
453         setMaximumObscuringOpacityForTouch(1);
454         addSawOverlay(APP_A, WINDOW_1, .9f);
455 
456         mTouchHelper.tapOnViewCenter(mContainer);
457 
458         assertTouchReceived();
459     }
460 
461     /** Activity windows */
462 
463     @Test
testWhenOneActivityWindowBelowThreshold_blocksTouch()464     public void testWhenOneActivityWindowBelowThreshold_blocksTouch()
465             throws Throwable {
466         addActivityOverlay(APP_A, /* opacity */ .5f);
467 
468         mTouchHelper.tapOnViewCenter(mContainer);
469 
470         assertTouchNotReceived();
471     }
472 
473     @Test
testWhenOneActivityWindowAboveThreshold_blocksTouch()474     public void testWhenOneActivityWindowAboveThreshold_blocksTouch()
475             throws Throwable {
476         addActivityOverlay(APP_A, /* opacity */ .9f);
477 
478         mTouchHelper.tapOnViewCenter(mContainer);
479 
480         assertTouchNotReceived();
481     }
482 
483     @Test
testWhenOneActivityWindowWithZeroOpacity_allowsTouch()484     public void testWhenOneActivityWindowWithZeroOpacity_allowsTouch()
485             throws Throwable {
486         addActivityOverlay(APP_A, /* opacity */ 0f);
487 
488         mTouchHelper.tapOnViewCenter(mContainer);
489 
490         assertTouchReceived();
491     }
492 
493     @Test
testWhenOneActivityWindowWithMinPositiveOpacity_blocksTouch()494     public void testWhenOneActivityWindowWithMinPositiveOpacity_blocksTouch()
495             throws Throwable {
496         addActivityOverlay(APP_A, /* opacity */ MIN_POSITIVE_OPACITY);
497 
498         mTouchHelper.tapOnViewCenter(mContainer);
499 
500         assertTouchNotReceived();
501     }
502 
503     @Test
testWhenOneActivityWindowWithSmallOpacity_blocksTouch()504     public void testWhenOneActivityWindowWithSmallOpacity_blocksTouch()
505             throws Throwable {
506         addActivityOverlay(APP_A, /* opacity */ .01f);
507 
508         mTouchHelper.tapOnViewCenter(mContainer);
509 
510         assertTouchNotReceived();
511     }
512 
513     @Test
testWhenOneSelfActivityWindow_allowsTouch()514     public void testWhenOneSelfActivityWindow_allowsTouch() throws Throwable {
515         addActivityOverlay(APP_SELF, /* opacity */ .9f);
516 
517         mTouchHelper.tapOnViewCenter(mContainer);
518 
519         assertTouchReceived();
520     }
521 
522     @Test
testWhenTwoActivityWindowsFromDifferentAppsTogetherBelowThreshold_blocksTouch()523     public void testWhenTwoActivityWindowsFromDifferentAppsTogetherBelowThreshold_blocksTouch()
524             throws Throwable {
525         addActivityOverlay(APP_A, /* opacity */ .7f);
526         addActivityOverlay(APP_B, /* opacity */ .7f);
527 
528         mTouchHelper.tapOnViewCenter(mContainer);
529 
530         assertTouchNotReceived();
531     }
532 
533     @Test
testWhenOneActivityWindowAndOneSawWindowTogetherBelowThreshold_blocksTouch()534     public void testWhenOneActivityWindowAndOneSawWindowTogetherBelowThreshold_blocksTouch()
535             throws Throwable {
536         addActivityOverlay(APP_A, /* opacity */ .5f);
537         addSawOverlay(APP_A, WINDOW_1, .5f);
538 
539         mTouchHelper.tapOnViewCenter(mContainer);
540 
541         assertTouchNotReceived();
542     }
543 
544     @Test
testWhenOneActivityWindowAndOneSelfCustomToastWindow_blocksTouch()545     public void testWhenOneActivityWindowAndOneSelfCustomToastWindow_blocksTouch()
546             throws Throwable {
547         // Toast has to be before otherwise it would be blocked from background
548         addToastOverlay(APP_SELF, /* custom */ true);
549         addActivityOverlay(APP_A, /* opacity */ .5f);
550 
551         mTouchHelper.tapOnViewCenter(mContainer);
552 
553         assertTouchNotReceived();
554     }
555 
556     @Test
testWhenOneActivityWindowAndOneSelfSawWindow_blocksTouch()557     public void testWhenOneActivityWindowAndOneSelfSawWindow_blocksTouch()
558             throws Throwable {
559         addActivityOverlay(APP_A, /* opacity */ .5f);
560         addSawOverlay(APP_SELF, WINDOW_1, .5f);
561 
562         mTouchHelper.tapOnViewCenter(mContainer);
563 
564         assertTouchNotReceived();
565     }
566 
567     @Test
testWhenOneActivityWindowAndOneSawWindowBelowThreshold_blocksTouch()568     public void testWhenOneActivityWindowAndOneSawWindowBelowThreshold_blocksTouch()
569             throws Throwable {
570         addActivityOverlay(APP_A, /* opacity */ .5f);
571         addSawOverlay(APP_A, WINDOW_1, .5f);
572 
573         mTouchHelper.tapOnViewCenter(mContainer);
574 
575         assertTouchNotReceived();
576     }
577 
578     @Test
testWhenOneActivityWindowAndOneSawWindowBelowThresholdFromDifferentApp_blocksTouch()579     public void testWhenOneActivityWindowAndOneSawWindowBelowThresholdFromDifferentApp_blocksTouch()
580             throws Throwable {
581         addActivityOverlay(APP_A, /* opacity */ .5f);
582         addSawOverlay(APP_B, WINDOW_1, .5f);
583 
584         mTouchHelper.tapOnViewCenter(mContainer);
585 
586         assertTouchNotReceived();
587     }
588 
589     /** Activity-type child windows on same activity */
590 
591     @Test
testWhenActivityChildWindowWithSameTokenFromDifferentApp_allowsTouch()592     public void testWhenActivityChildWindowWithSameTokenFromDifferentApp_allowsTouch()
593             throws Exception {
594         IBinder token = mActivity.getWindow().getAttributes().token;
595         addActivityChildWindow(APP_A, WINDOW_1, token);
596 
597         mTouchHelper.tapOnViewCenter(mContainer);
598 
599         assertTouchReceived();
600     }
601 
602     @Test
testWhenActivityChildWindowWithDifferentTokenFromDifferentApp_blocksTouch()603     public void testWhenActivityChildWindowWithDifferentTokenFromDifferentApp_blocksTouch()
604             throws Exception {
605         // Creates a new activity with 0 opacity
606         BlockingResultReceiver receiver = new BlockingResultReceiver();
607         addActivityOverlay(APP_A, /* opacity */ 0f, receiver);
608         // Verify it allows touches
609         mTouchHelper.tapOnViewCenter(mContainer);
610         assertTouchReceived();
611         // Now get its token and put a child window from another app with it
612         IBinder token = receiver.getData(TIMEOUT_MS).getBinder(EXTRA_TOKEN);
613         addActivityChildWindow(APP_B, WINDOW_1, token);
614 
615         mTouchHelper.tapOnViewCenter(mContainer);
616 
617         assertTouchNotReceived();
618     }
619 
620     @Test
testWhenActivityChildWindowWithDifferentTokenFromSameApp_allowsTouch()621     public void testWhenActivityChildWindowWithDifferentTokenFromSameApp_allowsTouch()
622             throws Exception {
623         // Creates a new activity with 0 opacity
624         BlockingResultReceiver receiver = new BlockingResultReceiver();
625         addActivityOverlay(APP_A, /* opacity */ 0f, receiver);
626         // Now get its token and put a child window owned by us
627         IBinder token = receiver.getData(TIMEOUT_MS).getBinder(EXTRA_TOKEN);
628         addActivityChildWindow(APP_SELF, WINDOW_1, token);
629 
630         mTouchHelper.tapOnViewCenter(mContainer);
631 
632         assertTouchReceived();
633     }
634 
635     /** Activity transitions */
636 
637     @Test
testLongEnterAnimations_areLimited()638     public void testLongEnterAnimations_areLimited() {
639         long durationSet = mResources.getInteger(R.integer.long_animation_duration);
640         assertThat(durationSet).isGreaterThan(
641                 MAX_ANIMATION_DURATION_MS + ANIMATION_DURATION_TOLERANCE_MS);
642         addAnimatedActivityOverlay(APP_A, /* touchable */ false, R.anim.long_alpha_0_7,
643                 R.anim.long_alpha_1);
644         assertTrue(mWmState.waitForAppTransitionRunningOnDisplay(Display.DEFAULT_DISPLAY));
645         long start = SystemClock.elapsedRealtime();
646 
647         assertTrue(mWmState.waitForAppTransitionIdleOnDisplay(Display.DEFAULT_DISPLAY));
648         long duration = SystemClock.elapsedRealtime() - start;
649         assertThat(duration).isAtMost(MAX_ANIMATION_DURATION_MS + ANIMATION_DURATION_TOLERANCE_MS);
650     }
651 
652     @Test
testLongExitAnimations_areLimited()653     public void testLongExitAnimations_areLimited() {
654         long durationSet = mResources.getInteger(R.integer.long_animation_duration);
655         assertThat(durationSet).isGreaterThan(
656                 MAX_ANIMATION_DURATION_MS + ANIMATION_DURATION_TOLERANCE_MS);
657         addExitAnimationActivity(APP_A);
658         sendFinishToExitAnimationActivity(APP_A,
659                 Components.ExitAnimationActivityReceiver.EXTRA_VALUE_LONG_ANIMATION_0_7);
660         assertTrue(mWmState.waitForAppTransitionRunningOnDisplay(Display.DEFAULT_DISPLAY));
661         long start = SystemClock.elapsedRealtime();
662 
663         assertTrue(mWmState.waitForAppTransitionIdleOnDisplay(Display.DEFAULT_DISPLAY));
664         long duration = SystemClock.elapsedRealtime() - start;
665         assertThat(duration).isAtMost(MAX_ANIMATION_DURATION_MS + ANIMATION_DURATION_TOLERANCE_MS);
666     }
667 
668     @Test
testWhenEnterAnimationAboveThresholdAndNewActivityNotTouchable_blocksTouch()669     public void testWhenEnterAnimationAboveThresholdAndNewActivityNotTouchable_blocksTouch() {
670         addAnimatedActivityOverlay(APP_A, /* touchable */ false, R.anim.alpha_0_9, R.anim.alpha_1);
671         assertTrue(mWmState.waitForAppTransitionRunningOnDisplay(Display.DEFAULT_DISPLAY));
672 
673         mTouchHelper.tapOnViewCenter(mContainer, /* waitAnimations*/ false);
674 
675         assertAnimationRunning();
676         assertTouchNotReceived();
677     }
678 
679     @Test
testWhenEnterAnimationBelowThresholdAndNewActivityNotTouchable_allowsTouch()680     public void testWhenEnterAnimationBelowThresholdAndNewActivityNotTouchable_allowsTouch() {
681         addAnimatedActivityOverlay(APP_A, /* touchable */ false, R.anim.alpha_0_7, R.anim.alpha_1);
682         assertTrue(mWmState.waitForAppTransitionRunningOnDisplay(Display.DEFAULT_DISPLAY));
683 
684         mTouchHelper.tapOnViewCenter(mContainer, /* waitAnimations*/ false);
685 
686         assertAnimationRunning();
687         assertTouchReceived();
688     }
689 
690     @Test
testWhenEnterAnimationBelowThresholdAndNewActivityTouchable_blocksTouch()691     public void testWhenEnterAnimationBelowThresholdAndNewActivityTouchable_blocksTouch() {
692         addAnimatedActivityOverlay(APP_A, /* touchable */ true, R.anim.alpha_0_7, R.anim.alpha_1);
693         assertTrue(mWmState.waitForAppTransitionRunningOnDisplay(Display.DEFAULT_DISPLAY));
694 
695         mTouchHelper.tapOnViewCenter(mContainer, /* waitAnimations*/ false);
696 
697         assertAnimationRunning();
698         assertTouchNotReceived();
699     }
700 
701     @Test
testWhenExitAnimationBelowThreshold_allowsTouch()702     public void testWhenExitAnimationBelowThreshold_allowsTouch() {
703         addExitAnimationActivity(APP_A);
704         sendFinishToExitAnimationActivity(APP_A,
705                 Components.ExitAnimationActivityReceiver.EXTRA_VALUE_ANIMATION_0_7);
706         assertTrue(mWmState.waitForAppTransitionRunningOnDisplay(Display.DEFAULT_DISPLAY));
707 
708         mTouchHelper.tapOnViewCenter(mContainer, /* waitAnimations*/ false);
709 
710         assertAnimationRunning();
711         assertTouchReceived();
712     }
713 
714     @Test
testWhenExitAnimationAboveThreshold_blocksTouch()715     public void testWhenExitAnimationAboveThreshold_blocksTouch() {
716         addExitAnimationActivity(APP_A);
717         sendFinishToExitAnimationActivity(APP_A,
718                 Components.ExitAnimationActivityReceiver.EXTRA_VALUE_ANIMATION_0_9);
719         assertTrue(mWmState.waitForAppTransitionRunningOnDisplay(Display.DEFAULT_DISPLAY));
720 
721         mTouchHelper.tapOnViewCenter(mContainer, /* waitAnimations*/ false);
722 
723         assertAnimationRunning();
724         assertTouchNotReceived();
725     }
726 
727     @Test
testWhenExitAnimationAboveThresholdFromSameUid_allowsTouch()728     public void testWhenExitAnimationAboveThresholdFromSameUid_allowsTouch() {
729         addExitAnimationActivity(APP_SELF);
730         sendFinishToExitAnimationActivity(APP_SELF,
731                 Components.ExitAnimationActivityReceiver.EXTRA_VALUE_ANIMATION_0_9);
732         assertTrue(mWmState.waitForAppTransitionRunningOnDisplay(Display.DEFAULT_DISPLAY));
733 
734         mTouchHelper.tapOnViewCenter(mContainer, /* waitAnimations*/ false);
735 
736         assertAnimationRunning();
737         assertTouchReceived();
738     }
739 
740     /** Toast windows */
741 
742     @Test
testWhenSelfTextToastWindow_allowsTouch()743     public void testWhenSelfTextToastWindow_allowsTouch() throws Throwable {
744         addToastOverlay(APP_SELF, /* custom */ false);
745         Rect toast = mWmState.waitForResult("toast bounds",
746                 state -> state.findFirstWindowWithType(LayoutParams.TYPE_TOAST).getFrame());
747 
748         mTouchHelper.tapOnCenter(toast, mActivity.getDisplayId());
749 
750         assertTouchReceived();
751     }
752 
753     @Test
testWhenTextToastWindow_allowsTouch()754     public void testWhenTextToastWindow_allowsTouch() throws Throwable {
755         addToastOverlay(APP_A, /* custom */ false);
756         Rect toast = mWmState.waitForResult("toast bounds",
757                 state -> state.findFirstWindowWithType(LayoutParams.TYPE_TOAST).getFrame());
758 
759         mTouchHelper.tapOnCenter(toast, mActivity.getDisplayId());
760 
761         assertTouchReceived();
762     }
763 
764     @Test
testWhenOneCustomToastWindow_blocksTouch()765     public void testWhenOneCustomToastWindow_blocksTouch() throws Throwable {
766         addToastOverlay(APP_A, /* custom */ true);
767 
768         mTouchHelper.tapOnViewCenter(mContainer);
769 
770         assertTouchNotReceived();
771     }
772 
773     @Test
testWhenOneSelfCustomToastWindow_allowsTouch()774     public void testWhenOneSelfCustomToastWindow_allowsTouch() throws Throwable {
775         addToastOverlay(APP_SELF, /* custom */ true);
776 
777         mTouchHelper.tapOnViewCenter(mContainer);
778 
779         assertTouchReceived();
780     }
781 
782     @Test
testWhenOneCustomToastWindowAndOneSelfSawWindow_blocksTouch()783     public void testWhenOneCustomToastWindowAndOneSelfSawWindow_blocksTouch()
784             throws Throwable {
785         addSawOverlay(APP_SELF, WINDOW_1, .9f);
786         addToastOverlay(APP_A, /* custom */ true);
787 
788         mTouchHelper.tapOnViewCenter(mContainer);
789 
790         assertTouchNotReceived();
791     }
792 
793     @Test
testWhenOneCustomToastWindowAndOneSawWindowBelowThreshold_blocksTouch()794     public void testWhenOneCustomToastWindowAndOneSawWindowBelowThreshold_blocksTouch()
795             throws Throwable {
796         addSawOverlay(APP_A, WINDOW_1, .5f);
797         addToastOverlay(APP_A, /* custom */ true);
798 
799         mTouchHelper.tapOnViewCenter(mContainer);
800 
801         assertTouchNotReceived();
802     }
803 
804     @Test
testWhenOneCustomToastWindowAndOneSawWindowBelowThresholdFromDifferentApp_blocksTouch()805     public void testWhenOneCustomToastWindowAndOneSawWindowBelowThresholdFromDifferentApp_blocksTouch()
806             throws Throwable {
807         addSawOverlay(APP_A, WINDOW_1, .5f);
808         addToastOverlay(APP_B, /* custom */ true);
809 
810         mTouchHelper.tapOnViewCenter(mContainer);
811 
812         assertTouchNotReceived();
813     }
814 
815     @Test
testWhenOneSelfCustomToastWindowOneSelfActivityWindowAndOneSawBelowThreshold_allowsTouch()816     public void testWhenOneSelfCustomToastWindowOneSelfActivityWindowAndOneSawBelowThreshold_allowsTouch()
817             throws Throwable {
818         addActivityOverlay(APP_SELF, /* opacity */ .9f);
819         addSawOverlay(APP_A, WINDOW_1, .5f);
820         addToastOverlay(APP_SELF, /* custom */ true);
821 
822         mTouchHelper.tapOnViewCenter(mContainer);
823 
824         assertTouchReceived();
825     }
826 
onTouchEvent(View view, MotionEvent event)827     private boolean onTouchEvent(View view, MotionEvent event) {
828         if (event.getAction() == MotionEvent.ACTION_DOWN) {
829             mTouchesReceived.incrementAndGet();
830         }
831         return true;
832     }
833 
assertTouchReceived()834     private void assertTouchReceived() {
835         mInstrumentation.waitForIdleSync();
836         assertThat(mTouchesReceived.get()).isEqualTo(1);
837         mTouchesReceived.set(0);
838     }
839 
assertTouchNotReceived()840     private void assertTouchNotReceived() {
841         mInstrumentation.waitForIdleSync();
842         assertThat(mTouchesReceived.get()).isEqualTo(0);
843         mTouchesReceived.set(0);
844     }
845 
assertAnimationRunning()846     private void assertAnimationRunning() {
847         assertThat(mWmState.getDisplay(Display.DEFAULT_DISPLAY).getAppTransitionState()).isEqualTo(
848                 WindowManagerStateHelper.APP_STATE_RUNNING);
849     }
850 
addToastOverlay(String packageName, boolean custom)851     private void addToastOverlay(String packageName, boolean custom) throws Exception {
852         // Making sure there are no toasts currently since we can only check for the presence of
853         // *any* toast afterwards and we don't want to be in a situation where this method returned
854         // because another toast was being displayed.
855         waitForNoToastOverlays();
856         if (custom) {
857             if (packageName.equals(APP_SELF)) {
858                 // We add the custom toast here because we already have foreground status due to
859                 // the activity rule, so no need to start another activity.
860                 addMyCustomToastOverlay();
861             } else {
862                 // We have to use an activity that will display the toast then finish itself because
863                 // custom toasts cannot be posted from the background.
864                 Intent intent = new Intent();
865                 intent.setComponent(repackage(packageName, Components.ToastActivity.COMPONENT));
866                 mActivity.startActivity(intent);
867             }
868         } else {
869             getService(packageName).showToast();
870         }
871         String message = "Toast from app " + packageName + " did not appear on time";
872         // TODO: WindowStateProto does not have package/UID information from the window, the current
873         //  package test relies on the window name, which is not how toast windows are named. We
874         //  should ideally incorporate that information in WindowStateProto and use here.
875         if (!mWmState.waitFor("toast window", this::hasVisibleToast)) {
876             fail(message);
877         }
878     }
879 
hasVisibleToast(WindowManagerState state)880     private boolean hasVisibleToast(WindowManagerState state) {
881         return !state.getMatchingWindowType(LayoutParams.TYPE_TOAST).isEmpty()
882                 && state.findFirstWindowWithType(LayoutParams.TYPE_TOAST).isSurfaceShown();
883     }
884 
addMyCustomToastOverlay()885     private void addMyCustomToastOverlay() {
886         mActivity.runOnUiThread(() -> {
887             mToast = new Toast(mContext);
888             View view = new View(mContext);
889             view.setBackgroundColor(OVERLAY_COLOR);
890             mToast.setView(view);
891             mToast.setGravity(Gravity.FILL, 0, 0);
892             mToast.setDuration(Toast.LENGTH_LONG);
893             mToast.show();
894         });
895         mInstrumentation.waitForIdleSync();
896     }
897 
removeMyCustomToastOverlay()898     private void removeMyCustomToastOverlay() {
899         mActivity.runOnUiThread(() -> {
900             if (mToast != null) {
901                 mToast.cancel();
902                 mToast = null;
903             }
904         });
905         mInstrumentation.waitForIdleSync();
906     }
907 
waitForNoToastOverlays()908     private void waitForNoToastOverlays() {
909         waitForNoToastOverlays("Toast windows did not hide on time");
910     }
911 
waitForNoToastOverlays(String message)912     private void waitForNoToastOverlays(String message) {
913         if (!mWmState.waitFor("no toast windows",
914                 state -> state.getMatchingWindowType(LayoutParams.TYPE_TOAST).isEmpty())) {
915             fail(message);
916         }
917     }
918 
addExitAnimationActivity(String packageName)919     private void addExitAnimationActivity(String packageName) {
920         // This activity responds to broadcasts to exit with animations and it's opaque (translucent
921         // activities don't honor custom exit animations).
922         addActivity(repackage(packageName, Components.ExitAnimationActivity.COMPONENT),
923                 /* extras */ null, /* options */ null);
924     }
925 
sendFinishToExitAnimationActivity(String packageName, int exitAnimation)926     private void sendFinishToExitAnimationActivity(String packageName, int exitAnimation) {
927         Intent intent = new Intent(Components.ExitAnimationActivityReceiver.ACTION_FINISH);
928         intent.setPackage(packageName);
929         intent.putExtra(Components.ExitAnimationActivityReceiver.EXTRA_ANIMATION, exitAnimation);
930         mContext.sendBroadcast(intent);
931     }
932 
addAnimatedActivityOverlay(String packageName, boolean touchable, @AnimRes int enterAnim, @AnimRes int exitAnim)933     private void addAnimatedActivityOverlay(String packageName, boolean touchable,
934             @AnimRes int enterAnim, @AnimRes int exitAnim) {
935         ConditionVariable animationsStarted = new ConditionVariable(false);
936         ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, enterAnim, exitAnim,
937                 mMainHandler, animationsStarted::open, /* finishedListener */ null);
938         // We're testing the opacity coming from the animation here, not the one declared in the
939         // activity, so we set its opacity to 1
940         addActivityOverlay(packageName, /* opacity */ 1, touchable, options.toBundle());
941         animationsStarted.block();
942     }
943 
addActivityChildWindow(String packageName, String windowSuffix, IBinder token)944     private void addActivityChildWindow(String packageName, String windowSuffix, IBinder token)
945             throws Exception {
946         String name = getWindowName(packageName, windowSuffix);
947         getService(packageName).showActivityChildWindow(name, token);
948         if (!mWmState.waitFor("activity child window " + name,
949                 state -> state.isWindowVisible(name) && state.isWindowSurfaceShown(name))) {
950             fail("Activity child window " + name + " did not appear on time");
951         }
952     }
953 
addActivityOverlay(String packageName, float opacity)954     private void addActivityOverlay(String packageName, float opacity) {
955         addActivityOverlay(packageName, opacity, /* touchable */ false, /* options */ null);
956     }
957 
addActivityOverlay(String packageName, float opacity, boolean touchable, @Nullable Bundle options)958     private void addActivityOverlay(String packageName, float opacity, boolean touchable,
959             @Nullable Bundle options) {
960         Bundle extras = new Bundle();
961         extras.putFloat(Components.OverlayActivity.EXTRA_OPACITY, opacity);
962         extras.putBoolean(Components.OverlayActivity.EXTRA_TOUCHABLE, touchable);
963         addActivityOverlay(packageName, extras, options);
964     }
965 
addActivityOverlay(String packageName, float opacity, BlockingResultReceiver tokenReceiver)966     private void addActivityOverlay(String packageName, float opacity,
967             BlockingResultReceiver tokenReceiver) {
968         Bundle extras = new Bundle();
969         extras.putFloat(Components.OverlayActivity.EXTRA_OPACITY, opacity);
970         extras.putParcelable(Components.OverlayActivity.EXTRA_TOKEN_RECEIVER, tokenReceiver);
971         addActivityOverlay(packageName, extras, /* options */ null);
972     }
973 
addActivityOverlay(String packageName, @Nullable Bundle extras, @Nullable Bundle options)974     private void addActivityOverlay(String packageName, @Nullable Bundle extras,
975             @Nullable Bundle options) {
976         addActivity(repackage(packageName, Components.OverlayActivity.COMPONENT), extras, options);
977     }
978 
addActivity(ComponentName component, @Nullable Bundle extras, @Nullable Bundle options)979     private void addActivity(ComponentName component, @Nullable Bundle extras,
980             @Nullable Bundle options) {
981         Intent intent = new Intent();
982         intent.setComponent(component);
983         if (extras != null) {
984             intent.putExtras(extras);
985         }
986         mActivity.startActivity(intent, options);
987         String packageName = component.getPackageName();
988         String activity = ComponentNameUtils.getActivityName(component);
989         if (!mWmState.waitFor("activity window " + activity,
990                 state -> activity.equals(state.getFocusedActivity())
991                         && state.hasActivityState(component, STATE_RESUMED))) {
992             fail("Activity from app " + packageName + " did not appear on time");
993         }
994     }
995 
removeActivityOverlays()996     private void removeActivityOverlays() {
997         Intent intent = new Intent(mContext, mActivity.getClass());
998         // Will clear any activity on top of it and it will become the new top
999         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1000         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
1001         mActivity.startActivity(intent);
1002     }
1003 
waitForNoActivityOverlays(String message)1004     private void waitForNoActivityOverlays(String message) {
1005         // Base activity focused means no activities on top
1006         ComponentName component = mActivity.getComponentName();
1007         String name = ComponentNameUtils.getActivityName(component);
1008         if (!mWmState.waitFor("test rule activity focused",
1009                 state -> name.equals(state.getFocusedActivity())
1010                         && state.hasActivityState(component, STATE_RESUMED))) {
1011             fail(message);
1012         }
1013     }
1014 
addSawOverlay(String packageName, String windowSuffix, float opacity)1015     private void addSawOverlay(String packageName, String windowSuffix, float opacity)
1016             throws Throwable {
1017         String name = getWindowName(packageName, windowSuffix);
1018         getService(packageName).showSystemAlertWindow(name, opacity);
1019         mSawWindowsAdded.add(name);
1020         if (!mWmState.waitFor("saw window " + name,
1021                 state -> state.isWindowVisible(name) && state.isWindowSurfaceShown(name))) {
1022             fail("Saw window " + name + " did not appear on time");
1023         }
1024     }
1025 
waitForNoSawOverlays(String message)1026     private void waitForNoSawOverlays(String message) {
1027         if (!mWmState.waitFor("no SAW windows",
1028                 state -> mSawWindowsAdded.stream().allMatch(w -> !state.isWindowVisible(w)))) {
1029             fail(message);
1030         }
1031         mSawWindowsAdded.clear();
1032     }
1033 
removeOverlays()1034     private void removeOverlays() throws Throwable {
1035         for (FutureConnection<IUntrustedTouchTestService> connection : mConnections.values()) {
1036             connection.getCurrent().removeOverlays();
1037         }
1038         // We need to stop the app because not every overlay is created via the service (eg.
1039         // activity overlays and custom toasts)
1040         for (String app : APPS) {
1041             stopPackage(app);
1042         }
1043         waitForNoSawOverlays("SAWs not removed on time");
1044         removeActivityOverlays();
1045         waitForNoActivityOverlays("Activities not removed on time");
1046         removeMyCustomToastOverlay();
1047         waitForNoToastOverlays("Toasts not removed on time");
1048     }
1049 
stopPackage(String packageName)1050     private void stopPackage(String packageName) {
1051         SystemUtil.runWithShellPermissionIdentity(
1052                 () -> mActivityManager.forceStopPackage(packageName));
1053     }
1054 
setBlockUntrustedTouchesMode(int mode)1055     private int setBlockUntrustedTouchesMode(int mode) throws Exception {
1056         return SystemUtil.callWithShellPermissionIdentity(() -> {
1057             int previous = mInputManager.getBlockUntrustedTouchesMode(mContext);
1058             mInputManager.setBlockUntrustedTouchesMode(mContext, mode);
1059             return previous;
1060         });
1061     }
1062 
setMaximumObscuringOpacityForTouch(float opacity)1063     private float setMaximumObscuringOpacityForTouch(float opacity) throws Exception {
1064         return SystemUtil.callWithShellPermissionIdentity(() -> {
1065             float previous = mInputManager.getMaximumObscuringOpacityForTouch();
1066             mInputManager.setMaximumObscuringOpacityForTouch(opacity);
1067             return previous;
1068         });
1069     }
1070 
1071     private IUntrustedTouchTestService getService(String packageName) throws Exception {
1072         return mConnections.computeIfAbsent(packageName, this::connect).get(TIMEOUT_MS);
1073     }
1074 
1075     private FutureConnection<IUntrustedTouchTestService> connect(String packageName) {
1076         FutureConnection<IUntrustedTouchTestService> connection =
1077                 new FutureConnection<>(IUntrustedTouchTestService.Stub::asInterface);
1078         Intent intent = new Intent();
1079         intent.setComponent(repackage(packageName, Components.UntrustedTouchTestService.COMPONENT));
1080         assertTrue(mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE));
1081         return connection;
1082     }
1083 
1084     private static String getWindowName(String packageName, String windowSuffix) {
1085         return packageName + "." + windowSuffix;
1086     }
1087 
1088     private static ComponentName repackage(String packageName, ComponentName baseComponent) {
1089         return new ComponentName(packageName, baseComponent.getClassName());
1090     }
1091 
1092     public static class TestActivity extends Activity {
1093         public View view;
1094 
1095         @Override
1096         protected void onCreate(@Nullable Bundle savedInstanceState) {
1097             super.onCreate(savedInstanceState);
1098             view = new View(this);
1099             view.setBackgroundColor(ACTIVITY_COLOR);
1100             setContentView(view);
1101         }
1102     }
1103 }
1104