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