Merge "Remove PRIVATE_FLAG_IS_SCREEN_DECOR"

This commit is contained in:
Tiger Huang
2020-11-30 15:38:54 +00:00
committed by Android (Google) Code Review
7 changed files with 11 additions and 482 deletions

View File

@@ -2156,15 +2156,6 @@ public interface WindowManager extends ViewManager {
*/
public static final int PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY = 0x00100000;
/**
* Flag to indicate that this window should be considered a screen decoration similar to the
* nav bar and status bar. This will cause this window to affect the window insets reported
* to other windows when it is visible.
* @hide
*/
@RequiresPermission(permission.STATUS_BAR_SERVICE)
public static final int PRIVATE_FLAG_IS_SCREEN_DECOR = 0x00400000;
/**
* Flag to indicate that the status bar window is in a state such that it forces showing
* the navigation bar unless the navigation bar window is explicitly set to
@@ -2270,7 +2261,6 @@ public interface WindowManager extends ViewManager {
PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
PRIVATE_FLAG_IS_SCREEN_DECOR,
PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
PRIVATE_FLAG_USE_BLAST,
@@ -2357,10 +2347,6 @@ public interface WindowManager extends ViewManager {
mask = PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
equals = PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
name = "IS_ROUNDED_CORNERS_OVERLAY"),
@ViewDebug.FlagToString(
mask = PRIVATE_FLAG_IS_SCREEN_DECOR,
equals = PRIVATE_FLAG_IS_SCREEN_DECOR,
name = "IS_SCREEN_DECOR"),
@ViewDebug.FlagToString(
mask = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
equals = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,

View File

@@ -66,7 +66,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BA
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -279,7 +278,6 @@ public class DisplayPolicy {
private volatile boolean mKeyguardDrawComplete;
private volatile boolean mWindowManagerDrawComplete;
private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
private WindowState mStatusBar = null;
private WindowState mNotificationShade = null;
private final int[] mStatusBarHeightForRotation = new int[4];
@@ -864,19 +862,7 @@ public class DisplayPolicy {
* @param attrs The window layout parameters to be modified. These values
* are modified in-place.
*/
public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
int callingPid, int callingUid) {
final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
if (mScreenDecorWindows.contains(win)) {
if (!isScreenDecor) {
// No longer has the flag set, so remove from the set.
mScreenDecorWindows.remove(win);
}
} else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
mScreenDecorWindows.add(win);
}
public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs) {
switch (attrs.type) {
case TYPE_SYSTEM_OVERLAY:
case TYPE_SECURE_SYSTEM_OVERLAY:
@@ -966,11 +952,6 @@ public class DisplayPolicy {
* WindowManagerImpl.ADD_MULTIPLE_SINGLETON
*/
int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) {
if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
}
if ((attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
mContext.enforcePermission(
android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid,
@@ -1090,10 +1071,6 @@ public class DisplayPolicy {
* @param attrs Information about the window to be added.
*/
void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
mScreenDecorWindows.add(win);
}
switch (attrs.type) {
case TYPE_NOTIFICATION_SHADE:
mNotificationShade = win;
@@ -1275,7 +1252,6 @@ public class DisplayPolicy {
if (mLastFocusedWindow == win) {
mLastFocusedWindow = null;
}
mScreenDecorWindows.remove(win);
}
private int getStatusBarHeight(DisplayFrames displayFrames) {
@@ -1457,14 +1433,12 @@ public class DisplayPolicy {
}
final int fl = attrs.flags;
final int pfl = attrs.privateFlags;
final boolean layoutInScreenAndInsetDecor = (fl & FLAG_LAYOUT_IN_SCREEN) != 0
&& (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
final DisplayFrames displayFrames = isFixedRotationTransforming
? windowToken.getFixedRotationTransformDisplayFrames()
: mDisplayContent.mDisplayFrames;
if (layoutInScreenAndInsetDecor && !screenDecor) {
if (layoutInScreenAndInsetDecor) {
outDisplayCutout.set(
displayFrames.mDisplayCutout.calculateRelativeTo(outFrame).getDisplayCutout());
} else {
@@ -1564,7 +1538,6 @@ public class DisplayPolicy {
simulatedWindowFrames, barContentFrames,
contentFrame -> layoutStatusBar(displayFrames, contentFrame));
}
layoutScreenDecorWindows(displayFrames, simulatedWindowFrames);
}
/**
@@ -1585,7 +1558,6 @@ public class DisplayPolicy {
layoutNavigationBar(displayFrames, uiMode, null /* simulatedContentFrame */);
layoutStatusBar(displayFrames, null /* simulatedContentFrame */);
layoutScreenDecorWindows(displayFrames, null /* simulatedFrames */);
}
void updateHideNavInputEventReceiver() {
@@ -1640,47 +1612,6 @@ public class DisplayPolicy {
state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(u.left, s.bottom, u.right, u.bottom);
}
/**
* Layout the decor windows with {@link #PRIVATE_FLAG_IS_SCREEN_DECOR}.
*
* @param displayFrames The display frames to be layouted.
* @param simulatedFrames Non-null if the caller only needs the result of display frames (see
* {@link WindowState#mSimulatedWindowFrames}).
*/
private void layoutScreenDecorWindows(DisplayFrames displayFrames,
WindowFrames simulatedFrames) {
if (mScreenDecorWindows.isEmpty()) {
return;
}
sTmpRect.setEmpty();
final int displayId = displayFrames.mDisplayId;
for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
final WindowState w = mScreenDecorWindows.valueAt(i);
if (w.getDisplayId() != displayId || !w.isVisible()) {
// Skip if not on the same display or not visible.
continue;
}
final boolean isSimulatedLayout = simulatedFrames != null;
if (isSimulatedLayout) {
w.setSimulatedWindowFrames(simulatedFrames);
}
getRotatedWindowBounds(displayFrames, w, sTmpScreenDecorFrame);
final WindowFrames windowFrames = w.getLayoutingWindowFrames();
windowFrames.setFrames(sTmpScreenDecorFrame /* parentFrame */,
sTmpScreenDecorFrame /* displayFrame */);
try {
w.computeFrame(displayFrames);
} finally {
if (isSimulatedLayout) {
w.setSimulatedWindowFrames(null);
}
}
}
}
private void layoutStatusBar(DisplayFrames displayFrames, Rect simulatedContentFrame) {
// decide where the status bar goes ahead of time
if (mStatusBar == null) {
@@ -1819,8 +1750,7 @@ public class DisplayPolicy {
// We've already done the navigation bar, status bar, and all screen decor windows. If the
// status bar can receive input, we need to layout it again to accommodate for the IME
// window.
if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
|| mScreenDecorWindows.contains(win)) {
if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar) {
return;
}
final WindowManager.LayoutParams attrs = win.getAttrs();

View File

@@ -48,6 +48,7 @@ import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY
import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -78,7 +79,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
import static android.view.WindowManagerGlobal.ADD_OKAY;
@@ -256,9 +256,9 @@ import android.view.View;
import android.view.WindowContentFrameStats;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.RemoveContentMode;
import android.view.WindowManager.DisplayImePolicy;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import android.window.ClientWindowFrames;
@@ -1627,7 +1627,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
displayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid);
displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
win.updateRequestedVisibility(requestedVisibility);
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
@@ -2197,7 +2197,7 @@ public class WindowManagerService extends IWindowManager.Stub
int flagChanges = 0;
int privateFlagChanges = 0;
if (attrs != null) {
displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
displayPolicy.adjustWindowParamsLw(win, attrs);
win.mToken.adjustWindowParams(win, attrs);
int disableFlags =
(attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility) & DISABLE_MASK;

View File

@@ -65,8 +65,6 @@
android:turnScreenOn="true" />
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ResumeWhilePausingActivity"
android:resumeWhilePausing="true"/>
<activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
android:showWhenLocked="true" android:allowEmbedded="true"/>
<activity android:name="com.android.server.wm.ActivityLeakTests$DetectLeakActivity" />
</application>

View File

@@ -236,8 +236,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
final WindowState activity = createBaseApplicationWindow();
activity.mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
policy.adjustWindowParamsLw(activity, activity.mAttrs, 0 /* callingPid */,
0 /* callingUid */);
policy.adjustWindowParamsLw(activity, activity.mAttrs);
}
private WindowState createApplicationWindow() {

View File

@@ -107,11 +107,9 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
}
void addWindow(WindowState win) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid);
assertEquals(WindowManagerGlobal.ADD_OKAY,
mDisplayPolicy.validateAddingWindowLw(win.mAttrs, callingPid, callingUid));
mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs);
assertEquals(WindowManagerGlobal.ADD_OKAY, mDisplayPolicy.validateAddingWindowLw(
win.mAttrs, Binder.getCallingPid(), Binder.getCallingUid()));
mDisplayPolicy.addWindowLw(win, win.mAttrs);
win.mHasSurface = true;
}

View File

@@ -1,382 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wm;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.graphics.Color.RED;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.LEFT;
import static android.view.Gravity.RIGHT;
import static android.view.Gravity.TOP;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import android.app.Activity;
import android.app.ActivityOptions;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.ImageReader;
import android.os.Handler;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.TextView;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayList;
import java.util.function.BooleanSupplier;
/**
* Tests for the {@link android.view.WindowManager.LayoutParams#PRIVATE_FLAG_IS_SCREEN_DECOR} flag.
*
* Build/Install/Run:
* atest WmTests:ScreenDecorWindowTests
*/
// TODO: Add test for FLAG_FULLSCREEN which hides the status bar and also other flags.
// TODO: Test non-Activity windows.
@SmallTest
@Presubmit
public class ScreenDecorWindowTests {
private final Context mContext = getInstrumentation().getTargetContext();
private final Instrumentation mInstrumentation = getInstrumentation();
private WindowManager mWm;
private ArrayList<View> mWindows = new ArrayList<>();
private Activity mTestActivity;
private VirtualDisplay mDisplay;
private ImageReader mImageReader;
private int mDecorThickness;
private int mHalfDecorThickness;
@Before
public void setUp() {
final Pair<VirtualDisplay, ImageReader> result = createDisplay();
mDisplay = result.first;
mImageReader = result.second;
final Display display = mDisplay.getDisplay();
final Context dContext = mContext.createDisplayContext(display);
mWm = dContext.getSystemService(WindowManager.class);
mTestActivity = startActivityOnDisplay(TestActivity.class, display.getDisplayId());
final Point size = new Point();
mDisplay.getDisplay().getRealSize(size);
mDecorThickness = Math.min(size.x, size.y) / 3;
mHalfDecorThickness = mDecorThickness / 2;
}
@After
public void tearDown() {
while (!mWindows.isEmpty()) {
removeWindow(mWindows.get(0));
}
finishActivity(mTestActivity);
mDisplay.release();
mImageReader.close();
}
@Test
public void testScreenSides() {
// Decor on top
final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
// Decor at the bottom
updateWindow(decorWindow, BOTTOM, MATCH_PARENT, mDecorThickness, 0, 0);
assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mDecorThickness);
// Decor to the left
updateWindow(decorWindow, LEFT, mDecorThickness, MATCH_PARENT, 0, 0);
assertInsetGreaterOrEqual(mTestActivity, LEFT, mDecorThickness);
// Decor to the right
updateWindow(decorWindow, RIGHT, mDecorThickness, MATCH_PARENT, 0, 0);
assertInsetGreaterOrEqual(mTestActivity, RIGHT, mDecorThickness);
}
// Decor windows (i.e windows using PRIVATE_FLAG_IS_SCREEN_DECOR) are no longer supported.
// PRIVATE_FLAG_IS_SCREEN_DECOR and related code will be deprecated/removed soon.
@Ignore
@Test
public void testMultipleDecors() {
// Test 2 decor windows on-top.
createDecorWindow(TOP, MATCH_PARENT, mHalfDecorThickness);
assertInsetGreaterOrEqual(mTestActivity, TOP, mHalfDecorThickness);
createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
// And one at the bottom.
createDecorWindow(BOTTOM, MATCH_PARENT, mHalfDecorThickness);
assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mHalfDecorThickness);
}
@Test
public void testFlagChange() {
WindowInsets initialInsets = getInsets(mTestActivity);
final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
assertTopInsetEquals(mTestActivity, mDecorThickness);
updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
0, PRIVATE_FLAG_IS_SCREEN_DECOR);
// TODO: fix test and re-enable assertion.
// initialInsets was not actually immutable and just updated to the current insets,
// meaning this assertion never actually tested anything. Now that WindowInsets actually is
// immutable, it turns out the test was broken.
// assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
PRIVATE_FLAG_IS_SCREEN_DECOR, PRIVATE_FLAG_IS_SCREEN_DECOR);
assertTopInsetEquals(mTestActivity, mDecorThickness);
}
@Test
public void testRemoval() {
WindowInsets initialInsets = getInsets(mTestActivity);
final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
removeWindow(decorWindow);
assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
}
@Test
public void testProvidesInsetsTypes() {
int[] providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
final View win = createWindow("StatusBarSubPanel", TOP, MATCH_PARENT, mDecorThickness, RED,
FLAG_LAYOUT_IN_SCREEN, 0, providesInsetsTypes);
assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
}
private View createDecorWindow(int gravity, int width, int height) {
int[] providesInsetsTypes =
new int[]{gravity == TOP ? ITYPE_CLIMATE_BAR : ITYPE_EXTRA_NAVIGATION_BAR};
return createWindow("decorWindow", gravity, width, height, RED,
FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR, providesInsetsTypes);
}
private View createWindow(String name, int gravity, int width, int height, int color, int flags,
int privateFlags, int[] providesInsetsTypes) {
final View[] viewHolder = new View[1];
final int finalFlag = flags
| FLAG_NOT_FOCUSABLE | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_NOT_TOUCHABLE;
// Needs to run on the UI thread.
Handler.getMain().runWithScissors(() -> {
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
width, height, TYPE_APPLICATION_OVERLAY, finalFlag, PixelFormat.OPAQUE);
lp.gravity = gravity;
lp.privateFlags |= privateFlags;
lp.providesInsetsTypes = providesInsetsTypes;
final TextView view = new TextView(mContext);
view.setText("ScreenDecorWindowTests - " + name);
view.setBackgroundColor(color);
mWm.addView(view, lp);
mWindows.add(view);
viewHolder[0] = view;
}, 0);
waitForIdle();
return viewHolder[0];
}
private void updateWindow(View v, int gravity, int width, int height,
int privateFlags, int privateFlagsMask) {
// Needs to run on the UI thread.
Handler.getMain().runWithScissors(() -> {
final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) v.getLayoutParams();
lp.gravity = gravity;
lp.width = width;
lp.height = height;
setPrivateFlags(lp, privateFlags, privateFlagsMask);
mWm.updateViewLayout(v, lp);
}, 0);
waitForIdle();
}
private void removeWindow(View v) {
Handler.getMain().runWithScissors(() -> mWm.removeView(v), 0);
mWindows.remove(v);
waitForIdle();
}
private WindowInsets getInsets(Activity a) {
return new WindowInsets(a.getWindow().getDecorView().getRootWindowInsets());
}
/**
* Set the flags of the window, as per the
* {@link WindowManager.LayoutParams WindowManager.LayoutParams}
* flags.
*
* @param flags The new window flags (see WindowManager.LayoutParams).
* @param mask Which of the window flag bits to modify.
*/
public void setPrivateFlags(WindowManager.LayoutParams lp, int flags, int mask) {
lp.flags = (lp.flags & ~mask) | (flags & mask);
}
/**
* Asserts the top inset of {@param activity} is equal to {@param expected} waiting as needed.
*/
private void assertTopInsetEquals(Activity activity, int expected) {
waitForTopInsetEqual(activity, expected);
assertEquals(expected, getInsets(activity).getSystemWindowInsetTop());
}
private void waitForTopInsetEqual(Activity activity, int expected) {
waitFor(() -> getInsets(activity).getSystemWindowInsetTop() == expected);
}
/**
* Asserts the inset at {@param side} of {@param activity} is equal to {@param expected}
* waiting as needed.
*/
private void assertInsetGreaterOrEqual(Activity activity, int side, int expected) {
waitForInsetGreaterOrEqual(activity, side, expected);
final WindowInsets insets = getInsets(activity);
switch (side) {
case TOP:
assertThat(insets.getSystemWindowInsetTop()).isAtLeast(expected);
break;
case BOTTOM:
assertThat(insets.getSystemWindowInsetBottom()).isAtLeast(expected);
break;
case LEFT:
assertThat(insets.getSystemWindowInsetLeft()).isAtLeast(expected);
break;
case RIGHT:
assertThat(insets.getSystemWindowInsetRight()).isAtLeast(expected);
break;
}
}
private void waitForInsetGreaterOrEqual(Activity activity, int side, int expected) {
waitFor(() -> {
final WindowInsets insets = getInsets(activity);
switch (side) {
case TOP: return insets.getSystemWindowInsetTop() >= expected;
case BOTTOM: return insets.getSystemWindowInsetBottom() >= expected;
case LEFT: return insets.getSystemWindowInsetLeft() >= expected;
case RIGHT: return insets.getSystemWindowInsetRight() >= expected;
default: return true;
}
});
}
private void waitFor(BooleanSupplier waitCondition) {
int retriesLeft = 5;
do {
if (waitCondition.getAsBoolean()) {
break;
}
SystemClock.sleep(500);
} while (retriesLeft-- > 0);
}
private void finishActivity(Activity a) {
if (a == null) {
return;
}
a.finish();
waitForIdle();
}
private void waitForIdle() {
mInstrumentation.waitForIdleSync();
}
private Activity startActivityOnDisplay(Class<?> cls, int displayId) {
final Intent intent = new Intent(mContext, cls);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(displayId);
final Activity activity = SystemUtil.runWithShellPermissionIdentity(
() -> mInstrumentation.startActivitySync(intent, options.toBundle()),
"android.permission.ACTIVITY_EMBEDDING");
waitForIdle();
assertEquals(displayId, activity.getDisplayId());
return activity;
}
private Pair<VirtualDisplay, ImageReader> createDisplay() {
final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
final DisplayInfo displayInfo = new DisplayInfo();
final Display defaultDisplay = dm.getDisplay(DEFAULT_DISPLAY);
defaultDisplay.getDisplayInfo(displayInfo);
final String name = "ScreenDecorWindowTests";
int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
final ImageReader imageReader = ImageReader.newInstance(
displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
final VirtualDisplay display = dm.createVirtualDisplay(name, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.logicalDensityDpi, imageReader.getSurface(),
flags);
return Pair.create(display, imageReader);
}
public static class TestActivity extends Activity {
}
}