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