Remove PRIVATE_FLAG_IS_SCREEN_DECOR
Applying this flag won't make the window provide insets anymore in the new insets system. A screen decor window should use providesInsetsTypes to provide insets instead. Bug: 149813814 Test: Presubmit Change-Id: I567bfc4f2e687aa2e9d65fe8e7edda867497c324
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user