1c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale/*
2c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * Copyright (C) 2017 The Android Open Source Project
3c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale *
4c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * Licensed under the Apache License, Version 2.0 (the "License");
5c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * you may not use this file except in compliance with the License.
6c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * You may obtain a copy of the License at
7c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale *
8c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale *      http://www.apache.org/licenses/LICENSE-2.0
9c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale *
10c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * Unless required by applicable law or agreed to in writing, software
11c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * distributed under the License is distributed on an "AS IS" BASIS,
12c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * See the License for the specific language governing permissions and
14c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * limitations under the License
15c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale */
16c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
17c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwalepackage com.android.server.wm;
18c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
19828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
20c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.graphics.Color.RED;
21828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
22828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
23828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport static android.view.Display.DEFAULT_DISPLAY;
24c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.Gravity.BOTTOM;
25c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.Gravity.LEFT;
26c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.Gravity.RIGHT;
27c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.Gravity.TOP;
28c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
29c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
30c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
31c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
32c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
33c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
34c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
35c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport static org.junit.Assert.assertEquals;
36c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
37c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.app.Activity;
38828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport android.app.ActivityOptions;
39c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.app.Instrumentation;
40c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.content.Context;
41828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport android.content.Intent;
42c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.graphics.PixelFormat;
43c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.graphics.Point;
44828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport android.hardware.display.DisplayManager;
45828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport android.hardware.display.VirtualDisplay;
46828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport android.media.ImageReader;
47c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.os.Handler;
48c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.platform.test.annotations.Presubmit;
49c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.support.test.InstrumentationRegistry;
50c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.support.test.filters.SmallTest;
51c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.support.test.runner.AndroidJUnit4;
52828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport android.util.Pair;
53828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport android.view.Display;
54828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwaleimport android.view.DisplayInfo;
55c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.view.View;
56c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.view.WindowInsets;
57c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.view.WindowManager;
58c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport android.widget.TextView;
59c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
60c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport org.junit.After;
61c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport org.junit.Assert;
62c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport org.junit.Before;
63c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport org.junit.Test;
64c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport org.junit.runner.RunWith;
65c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
66c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwaleimport java.util.ArrayList;
677a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwaleimport java.util.function.BooleanSupplier;
68c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
69c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale/**
70c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * Tests for the {@link android.view.WindowManager.LayoutParams#PRIVATE_FLAG_IS_SCREEN_DECOR} flag.
71c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale *
72c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale * Build/Install/Run:
737a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale *  atest FrameworksServicesTests:com.android.server.wm.ScreenDecorWindowTests
74c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale */
75c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale// TODO: Add test for FLAG_FULLSCREEN which hides the status bar and also other flags.
76c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale// TODO: Test non-Activity windows.
77c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale@SmallTest
787a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale@Presubmit
79c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale@RunWith(AndroidJUnit4.class)
80c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwalepublic class ScreenDecorWindowTests {
81c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
82c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private final Context mContext = InstrumentationRegistry.getTargetContext();
83c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
84c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
85c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private WindowManager mWm;
86c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private ArrayList<View> mWindows = new ArrayList<>();
87c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
88c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private Activity mTestActivity;
89828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale    private VirtualDisplay mDisplay;
90828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale    private ImageReader mImageReader;
91c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
92c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private int mDecorThickness;
93c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private int mHalfDecorThickness;
94c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
95c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    @Before
96c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    public void setUp() {
97828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final Pair<VirtualDisplay, ImageReader> result = createDisplay();
98828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        mDisplay = result.first;
99828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        mImageReader = result.second;
100828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final Display display = mDisplay.getDisplay();
101828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final Context dContext = mContext.createDisplayContext(display);
102828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        mWm = dContext.getSystemService(WindowManager.class);
103828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        mTestActivity = startActivityOnDisplay(TestActivity.class, display.getDisplayId());
104c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        final Point size = new Point();
105828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        mDisplay.getDisplay().getRealSize(size);
106c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        mDecorThickness = Math.min(size.x, size.y) / 3;
107c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        mHalfDecorThickness = mDecorThickness / 2;
108c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
109c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
110c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    @After
111c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    public void tearDown() {
112c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        while (!mWindows.isEmpty()) {
113c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            removeWindow(mWindows.get(0));
114c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        }
115828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        finishActivity(mTestActivity);
116828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        mDisplay.release();
117828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        mImageReader.close();
118c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
119c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
120c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    @Test
121c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    public void testScreenSides() throws Exception {
122c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        // Decor on top
123c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
1247a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
125c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
126c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        // Decor at the bottom
127c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        updateWindow(decorWindow, BOTTOM, MATCH_PARENT, mDecorThickness, 0, 0);
1287a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mDecorThickness);
129c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
130c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        // Decor to the left
131c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        updateWindow(decorWindow, LEFT, mDecorThickness, MATCH_PARENT, 0, 0);
1327a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertInsetGreaterOrEqual(mTestActivity, LEFT, mDecorThickness);
133c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
134c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        // Decor to the right
135c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        updateWindow(decorWindow, RIGHT, mDecorThickness, MATCH_PARENT, 0, 0);
1367a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertInsetGreaterOrEqual(mTestActivity, RIGHT, mDecorThickness);
137c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
138c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
139c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    @Test
140c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    public void testMultipleDecors() throws Exception {
141c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        // Test 2 decor windows on-top.
142c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        createDecorWindow(TOP, MATCH_PARENT, mHalfDecorThickness);
1437a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertInsetGreaterOrEqual(mTestActivity, TOP, mHalfDecorThickness);
144c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
1457a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
146c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
147c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        // And one at the bottom.
148c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        createDecorWindow(BOTTOM, MATCH_PARENT, mHalfDecorThickness);
1497a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
1507a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mHalfDecorThickness);
151c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
152c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
153c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    @Test
154c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    public void testFlagChange() throws Exception {
155c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        WindowInsets initialInsets = getInsets(mTestActivity);
156c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
157c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
1587a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertTopInsetEquals(mTestActivity, mDecorThickness);
159c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
160c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
161c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale                0, PRIVATE_FLAG_IS_SCREEN_DECOR);
162f7b7426d81c5365473d00362cf158aa5ae35cee3Adrian Roos
163f7b7426d81c5365473d00362cf158aa5ae35cee3Adrian Roos        // TODO: fix test and re-enable assertion.
164f7b7426d81c5365473d00362cf158aa5ae35cee3Adrian Roos        // initialInsets was not actually immutable and just updated to the current insets,
165f7b7426d81c5365473d00362cf158aa5ae35cee3Adrian Roos        // meaning this assertion never actually tested anything. Now that WindowInsets actually is
166f7b7426d81c5365473d00362cf158aa5ae35cee3Adrian Roos        // immutable, it turns out the test was broken.
167f7b7426d81c5365473d00362cf158aa5ae35cee3Adrian Roos        // assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
168c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
169c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
170c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale                PRIVATE_FLAG_IS_SCREEN_DECOR, PRIVATE_FLAG_IS_SCREEN_DECOR);
1717a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertTopInsetEquals(mTestActivity, mDecorThickness);
172c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
173c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
174c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    @Test
175c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    public void testRemoval() throws Exception {
176c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        WindowInsets initialInsets = getInsets(mTestActivity);
177c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
178c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
1797a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
180c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
181c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        removeWindow(decorWindow);
1827a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
183c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
184c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
185c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private View createDecorWindow(int gravity, int width, int height) {
186c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        return createWindow("decorWindow", gravity, width, height, RED,
187c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale                FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR);
188c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
189c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
190c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private View createWindow(String name, int gravity, int width, int height, int color, int flags,
191c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            int privateFlags) {
192c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
193c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        final View[] viewHolder = new View[1];
194c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        final int finalFlag = flags
195c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale                | FLAG_NOT_FOCUSABLE | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_NOT_TOUCHABLE;
196c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
197c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        // Needs to run on the UI thread.
198c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        Handler.getMain().runWithScissors(() -> {
199c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
200c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale                    width, height, TYPE_APPLICATION_OVERLAY, finalFlag, PixelFormat.OPAQUE);
201c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            lp.gravity = gravity;
202c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            lp.privateFlags |= privateFlags;
203c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
204c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            final TextView view = new TextView(mContext);
205c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            view.setText("ScreenDecorWindowTests - " + name);
206c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            view.setBackgroundColor(color);
207c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            mWm.addView(view, lp);
208c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            mWindows.add(view);
209c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            viewHolder[0] = view;
210c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        }, 0);
211c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
212c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        waitForIdle();
213c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        return viewHolder[0];
214c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
215c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
216c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private void updateWindow(View v, int gravity, int width, int height,
217c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            int privateFlags, int privateFlagsMask) {
218c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        // Needs to run on the UI thread.
219c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        Handler.getMain().runWithScissors(() -> {
220c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) v.getLayoutParams();
221c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            lp.gravity = gravity;
222c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            lp.width = width;
223c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            lp.height = height;
224c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            setPrivateFlags(lp, privateFlags, privateFlagsMask);
225c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
226c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale            mWm.updateViewLayout(v, lp);
227c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        }, 0);
228c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
229c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        waitForIdle();
230c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
231c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
232c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private void removeWindow(View v) {
233c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        Handler.getMain().runWithScissors(() -> mWm.removeView(v), 0);
234c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        mWindows.remove(v);
235c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        waitForIdle();
236c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
237c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
238c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private WindowInsets getInsets(Activity a) {
239c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        return new WindowInsets(a.getWindow().getDecorView().getRootWindowInsets());
240c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
241c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
242c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    /**
243c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale     * Set the flags of the window, as per the
244c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale     * {@link WindowManager.LayoutParams WindowManager.LayoutParams}
245c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale     * flags.
246c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale     *
247c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale     * @param flags The new window flags (see WindowManager.LayoutParams).
248c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale     * @param mask Which of the window flag bits to modify.
249c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale     */
250c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    public void setPrivateFlags(WindowManager.LayoutParams lp, int flags, int mask) {
251c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        lp.flags = (lp.flags & ~mask) | (flags & mask);
252c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
253c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
2547a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale    /**
2557a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale     * Asserts the top inset of {@param activity} is equal to {@param expected} waiting as needed.
2567a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale     */
2577a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale    private void assertTopInsetEquals(Activity activity, int expected) throws Exception {
2587a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        waitFor(() -> getInsets(activity).getSystemWindowInsetTop() == expected);
2597a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        assertEquals(expected, getInsets(activity).getSystemWindowInsetTop());
2607a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale    }
2617a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale
2627a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale    /**
2637a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale     * Asserts the inset at {@param side} of {@param activity} is equal to {@param expected}
2647a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale     * waiting as needed.
2657a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale     */
2667a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale    private void assertInsetGreaterOrEqual(Activity activity, int side, int expected)
2677a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            throws Exception {
2687a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        waitFor(() -> {
2697a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            final WindowInsets insets = getInsets(activity);
2707a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            switch (side) {
2717a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale                case TOP: return insets.getSystemWindowInsetTop() >= expected;
2727a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale                case BOTTOM: return insets.getSystemWindowInsetBottom() >= expected;
2737a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale                case LEFT: return insets.getSystemWindowInsetLeft() >= expected;
2747a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale                case RIGHT: return insets.getSystemWindowInsetRight() >= expected;
2757a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale                default: return true;
2767a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            }
2777a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        });
2787a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale
2797a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        final WindowInsets insets = getInsets(activity);
2807a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        switch (side) {
2817a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            case TOP: assertGreaterOrEqual(insets.getSystemWindowInsetTop(), expected); break;
2827a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            case BOTTOM: assertGreaterOrEqual(insets.getSystemWindowInsetBottom(), expected); break;
2837a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            case LEFT: assertGreaterOrEqual(insets.getSystemWindowInsetLeft(), expected); break;
2847a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            case RIGHT: assertGreaterOrEqual(insets.getSystemWindowInsetRight(), expected); break;
2857a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        }
2867a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale    }
2877a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale
288c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    /** Asserts that the first entry is greater than or equal to the second entry. */
289c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    private void assertGreaterOrEqual(int first, int second) throws Exception {
290c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale        Assert.assertTrue("Excepted " + first + " >= " + second, first >= second);
291c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
292c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale
2937a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale    private void waitFor(BooleanSupplier waitCondition) {
2947a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        int retriesLeft = 5;
2957a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        do {
2967a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            if (waitCondition.getAsBoolean()) {
2977a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale                break;
2987a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            }
2997a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            try {
3007a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale                Thread.sleep(500);
3017a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            } catch (InterruptedException e) {
3027a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale                // Well I guess we are not waiting...
3037a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale            }
3047a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale        } while (retriesLeft-- > 0);
3057a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale    }
3067a561ea05ed5ef73a9009e2bdf70a032803d669aWale Ogunwale
307828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale    private void finishActivity(Activity a) {
308828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        if (a == null) {
309828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale            return;
3107bb06e012a33c94c68b173bc8f276f78e0d60764Wale Ogunwale        }
311828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        a.finish();
312828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        waitForIdle();
3137bb06e012a33c94c68b173bc8f276f78e0d60764Wale Ogunwale    }
3149bc2692939d4dececbfde5ea67df4594a7842bd1Wale Ogunwale
3157bb06e012a33c94c68b173bc8f276f78e0d60764Wale Ogunwale    private void waitForIdle() {
3167bb06e012a33c94c68b173bc8f276f78e0d60764Wale Ogunwale        mInstrumentation.waitForIdleSync();
3179bc2692939d4dececbfde5ea67df4594a7842bd1Wale Ogunwale    }
3189bc2692939d4dececbfde5ea67df4594a7842bd1Wale Ogunwale
319828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale    private Activity startActivityOnDisplay(Class<?> cls, int displayId) {
320828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final Intent intent = new Intent(mContext, cls);
321828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
322828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final ActivityOptions options = ActivityOptions.makeBasic();
323828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        options.setLaunchDisplayId(displayId);
324828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final Activity activity = mInstrumentation.startActivitySync(intent, options.toBundle());
325828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        waitForIdle();
326828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale
327828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        assertEquals(displayId, activity.getDisplay().getDisplayId());
328828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        return activity;
329828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale    }
330828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale
331828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale    private Pair<VirtualDisplay, ImageReader> createDisplay() {
332828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
333828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final DisplayInfo displayInfo = new DisplayInfo();
334828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final Display defaultDisplay = dm.getDisplay(DEFAULT_DISPLAY);
335828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        defaultDisplay.getDisplayInfo(displayInfo);
336828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final String name = "ScreenDecorWindowTests";
337828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
338828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale
339828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final ImageReader imageReader = ImageReader.newInstance(
340828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale                displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
341828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale
342828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        final VirtualDisplay display = dm.createVirtualDisplay(name, displayInfo.logicalWidth,
343828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale                displayInfo.logicalHeight, displayInfo.logicalDensityDpi, imageReader.getSurface(),
344828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale                flags);
345828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale
346828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale        return Pair.create(display, imageReader);
347828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale    }
348828ff7e3ef032f3c3b149be9961fa39a979d2fd2Wale Ogunwale
349c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    public static class TestActivity extends Activity {
350c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale    }
351c0b0f93e96a290c819b77da169fc41e789027d21Wale Ogunwale}
352