Layout status/nav bar and decor window as normal window

Use the general layout process for system bar windows. The hard-coded
logic of the bar position is also disabled by the patch. Such that, the
system UI will have the ability to layout the window freely.

The bars sometimes need to be layout with new rotation before the actual
rotation when we simulate the display with fixed layout. To support
that, new layout params for orientation is introduced to the layout params.

The bar may need to provide a different insets frame in gesture
navigation mode. That is for the IME to draw the hide button. Introduced
a new param called providedInternalInsets to resolve that usage.

The new flexible layout is protected by the flag
persist.debug.flexible_insets.

Bug: 161689946
Bug: 169329927
Test: DisplayPolicyTests InsetsSourceProviderTest
      InsetsStateControllerTest
Change-Id: If8ec79b3cb3b989eed578c44e8749b13fd2e8592
This commit is contained in:
Yunfan Chen
2021-02-05 14:57:12 +09:00
parent 123e88c56f
commit fce2e99c68
14 changed files with 613 additions and 159 deletions

View File

@@ -284,6 +284,21 @@ public final class ViewRootImpl implements ViewParent,
*/
private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500;
/**
* If set to {@code true}, the new logic to layout system bars as normal window and to use
* layout result to get insets will be applied. Otherwise, the old hard-coded window logic will
* be applied.
*/
private static final String USE_FLEXIBLE_INSETS = "persist.debug.flexible_insets";
/**
* A flag to indicate to use the new generalized insets window logic, or the old hard-coded
* insets window layout logic.
* {@hide}
*/
public static final boolean INSETS_LAYOUT_GENERALIZATION =
SystemProperties.getBoolean(USE_FLEXIBLE_INSETS, false);
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();

View File

@@ -97,6 +97,7 @@ import android.content.ClipData;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -3454,6 +3455,22 @@ public interface WindowManager extends ViewManager {
*/
public @InsetsState.InternalInsetsType int[] providesInsetsTypes;
/**
* If specified, the insets provided by this window will be our window frame minus the
* insets specified by providedInternalInsets.
*
* @hide
*/
public Insets providedInternalInsets = Insets.NONE;
/**
* {@link LayoutParams} to be applied to the window when layout with a assigned rotation.
* This will make layout during rotation change smoothly.
*
* @hide
*/
public LayoutParams[] paramsForRotation;
/**
* Specifies types of insets that this window should avoid overlapping during layout.
*
@@ -3553,6 +3570,18 @@ public interface WindowManager extends ViewManager {
return mFitInsetsIgnoringVisibility;
}
private void checkNonRecursiveParams() {
if (paramsForRotation == null) {
return;
}
for (int i = paramsForRotation.length - 1; i >= 0; i--) {
if (paramsForRotation[i].paramsForRotation != null) {
throw new IllegalArgumentException(
"Params cannot contain params recursively.");
}
}
}
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
@@ -3805,6 +3834,14 @@ public interface WindowManager extends ViewManager {
} else {
out.writeInt(0);
}
providedInternalInsets.writeToParcel(out, 0 /* parcelableFlags */);
if (paramsForRotation != null) {
checkNonRecursiveParams();
out.writeInt(paramsForRotation.length);
out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
} else {
out.writeInt(0);
}
}
public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -3874,6 +3911,12 @@ public interface WindowManager extends ViewManager {
providesInsetsTypes = new int[insetsTypesLength];
in.readIntArray(providesInsetsTypes);
}
providedInternalInsets = Insets.CREATOR.createFromParcel(in);
int paramsForRotationLength = in.readInt();
if (paramsForRotationLength > 0) {
paramsForRotation = new LayoutParams[paramsForRotationLength];
in.readTypedArray(paramsForRotation, LayoutParams.CREATOR);
}
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -4156,6 +4199,17 @@ public interface WindowManager extends ViewManager {
changes |= LAYOUT_CHANGED;
}
if (!providedInternalInsets.equals(o.providedInternalInsets)) {
providedInternalInsets = o.providedInternalInsets;
changes |= LAYOUT_CHANGED;
}
if (!Arrays.equals(paramsForRotation, o.paramsForRotation)) {
paramsForRotation = o.paramsForRotation;
checkNonRecursiveParams();
changes |= LAYOUT_CHANGED;
}
return changes;
}
@@ -4343,6 +4397,18 @@ public interface WindowManager extends ViewManager {
sb.append(InsetsState.typeToString(providesInsetsTypes[i]));
}
}
if (!providedInternalInsets.equals(Insets.NONE)) {
sb.append(" providedInternalInsets=");
sb.append(providedInternalInsets);
}
if (paramsForRotation != null && paramsForRotation.length != 0) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" paramsForRotation=");
for (int i = 0; i < paramsForRotation.length; ++i) {
if (i > 0) sb.append(' ');
sb.append(paramsForRotation[i].toString());
}
}
sb.append('}');
return sb.toString();

View File

@@ -23,10 +23,12 @@ import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.WindowType;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.containsType;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
@@ -67,6 +69,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -199,6 +202,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private Bundle mSavedState;
private NavigationBarView mNavigationBarView;
private NavigationBarFrame mFrame;
private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
@@ -489,34 +493,17 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
public View createView(Bundle savedState) {
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
lp.accessibilityTitle = mContext.getString(R.string.nav_bar);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
lp.windowAnimations = 0;
lp.setTitle("NavigationBar" + mContext.getDisplayId());
lp.setFitInsetsTypes(0 /* types */);
lp.setTrustedOverlay();
NavigationBarFrame frame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
mFrame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
R.layout.navigation_bar_window, null);
View barView = LayoutInflater.from(frame.getContext()).inflate(
R.layout.navigation_bar, frame);
View barView = LayoutInflater.from(mFrame.getContext()).inflate(
R.layout.navigation_bar, mFrame);
barView.addOnAttachStateChangeListener(this);
mNavigationBarView = barView.findViewById(R.id.navigation_bar_view);
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
mContext.getSystemService(WindowManager.class).addView(frame, lp);
mContext.getSystemService(WindowManager.class).addView(mFrame,
getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration
.getRotation()));
mDisplayId = mContext.getDisplayId();
mIsOnDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
@@ -670,6 +657,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mHandler.removeCallbacks(mAutoDim);
mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
mHandler.removeCallbacks(mEnableLayoutTransitions);
mFrame = null;
mNavigationBarView = null;
mOrientationHandle = null;
}
@@ -688,6 +676,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
* Called when a non-reloading configuration change happens and we need to update.
*/
public void onConfigurationChanged(Configuration newConfig) {
final int rotation = newConfig.windowConfiguration.getRotation();
final Locale locale = mContext.getResources().getConfiguration().locale;
final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
if (!locale.equals(mLocale) || ld != mLayoutDirection) {
@@ -701,9 +690,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
refreshLayout(ld);
}
repositionNavigationBar();
repositionNavigationBar(rotation);
if (canShowSecondaryHandle()) {
int rotation = newConfig.windowConfiguration.getRotation();
if (rotation != mCurrentRotation) {
mCurrentRotation = rotation;
orientSecondaryHomeHandle();
@@ -1068,13 +1056,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|| (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
}
private void repositionNavigationBar() {
if (!mNavigationBarView.isAttachedToWindow()) return;
private void repositionNavigationBar(int rotation) {
if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
prepareNavigationBarView();
mWindowManager.updateViewLayout((View) mNavigationBarView.getParent(),
((View) mNavigationBarView.getParent()).getLayoutParams());
mWindowManager.updateViewLayout(mFrame, getBarLayoutParams(rotation));
}
private void updateScreenPinningGestures() {
@@ -1509,13 +1496,94 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final NavigationBarA11yHelper.NavA11yEventListener mAccessibilityListener =
this::updateAccessibilityServicesState;
private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
WindowManager.LayoutParams lp = getBarLayoutParamsForRotation(rotation);
lp.paramsForRotation = new WindowManager.LayoutParams[4];
for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
lp.paramsForRotation[rot] = getBarLayoutParamsForRotation(rot);
}
return lp;
}
private WindowManager.LayoutParams getBarLayoutParamsForRotation(int rotation) {
int width = WindowManager.LayoutParams.MATCH_PARENT;
int height = WindowManager.LayoutParams.MATCH_PARENT;
int insetsHeight = -1;
int gravity = Gravity.BOTTOM;
if (INSETS_LAYOUT_GENERALIZATION) {
boolean navBarCanMove = true;
if (mWindowManager != null && mWindowManager.getCurrentWindowMetrics() != null) {
Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds();
navBarCanMove = displaySize.width() != displaySize.height()
&& mContext.getResources().getBoolean(
com.android.internal.R.bool.config_navBarCanMove);
}
if (!navBarCanMove) {
height = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_frame_height);
insetsHeight = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_height);
} else {
switch (rotation) {
case ROTATION_UNDEFINED:
case Surface.ROTATION_0:
case Surface.ROTATION_180:
height = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_frame_height);
insetsHeight = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_height);
break;
case Surface.ROTATION_90:
gravity = Gravity.RIGHT;
width = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_width);
break;
case Surface.ROTATION_270:
gravity = Gravity.LEFT;
width = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_width);
break;
}
}
}
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
width,
height,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
if (INSETS_LAYOUT_GENERALIZATION) {
lp.gravity = gravity;
if (insetsHeight != -1) {
lp.providedInternalInsets = Insets.of(0, height - insetsHeight, 0, 0);
} else {
lp.providedInternalInsets = Insets.NONE;
}
}
lp.token = new Binder();
lp.accessibilityTitle = mContext.getString(R.string.nav_bar);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
lp.windowAnimations = 0;
lp.setTitle("NavigationBar" + mContext.getDisplayId());
lp.setFitInsetsTypes(0 /* types */);
lp.setTrustedOverlay();
return lp;
}
private boolean canShowSecondaryHandle() {
return mNavBarMode == NAV_BAR_MODE_GESTURAL && mOrientationHandle != null;
}
private final Consumer<Integer> mRotationWatcher = rotation -> {
if (mNavigationBarView.needsReorient(rotation)) {
repositionNavigationBar();
if (mNavigationBarView != null
&& mNavigationBarView.needsReorient(rotation)) {
repositionNavigationBar(rotation);
}
};

View File

@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
@@ -34,6 +36,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.Gravity;
import android.view.IWindowManager;
import android.view.Surface;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -118,21 +121,7 @@ public class StatusBarWindowController {
// Now that the status bar window encompasses the sliding panel and its
// translucent backdrop, the entire thing is made TRANSLUCENT and is
// hardware-accelerated.
mLp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
mBarHeight,
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT);
mLp.privateFlags |= PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
mLp.token = new Binder();
mLp.gravity = Gravity.TOP;
mLp.setFitInsetsTypes(0 /* types */);
mLp.setTitle("StatusBar");
mLp.packageName = mContext.getPackageName();
mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mLp = getBarLayoutParams(mContext.getDisplay().getRotation());
mWindowManager.addView(mStatusBarView, mLp);
mLpChanged.copyFrom(mLp);
@@ -141,6 +130,63 @@ public class StatusBarWindowController {
calculateStatusBarLocationsForAllRotations();
}
private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
WindowManager.LayoutParams lp = getBarLayoutParamsForRotation(rotation);
lp.paramsForRotation = new WindowManager.LayoutParams[4];
for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
lp.paramsForRotation[rot] = getBarLayoutParamsForRotation(rot);
}
return lp;
}
private WindowManager.LayoutParams getBarLayoutParamsForRotation(int rotation) {
int height = mBarHeight;
if (INSETS_LAYOUT_GENERALIZATION) {
Rect displayBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
int defaultAndUpsideDownHeight;
int theOtherHeight;
if (displayBounds.width() > displayBounds.height()) {
defaultAndUpsideDownHeight = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height_landscape);
theOtherHeight = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height_portrait);
} else {
defaultAndUpsideDownHeight = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height_portrait);
theOtherHeight = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height_landscape);
}
switch (rotation) {
case ROTATION_UNDEFINED:
case Surface.ROTATION_0:
case Surface.ROTATION_180:
height = defaultAndUpsideDownHeight;
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
height = theOtherHeight;
break;
}
}
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
height,
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
lp.token = new Binder();
lp.gravity = Gravity.TOP;
lp.setFitInsetsTypes(0 /* types */);
lp.setTitle("StatusBar");
lp.packageName = mContext.getPackageName();
lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
return lp;
}
private void calculateStatusBarLocationsForAllRotations() {
Rect[] bounds = new Rect[4];
bounds[0] = mContentInsetsProvider

View File

@@ -39,6 +39,7 @@ import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
import static android.view.ViewRootImpl.computeWindowBounds;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
@@ -333,6 +334,7 @@ public class DisplayPolicy {
private static final Rect sTmpRect = new Rect();
private static final Rect sTmpNavFrame = new Rect();
private static final Rect sTmpStatusFrame = new Rect();
private static final Rect sTmpDecorFrame = new Rect();
private static final Rect sTmpScreenDecorFrame = new Rect();
private static final Rect sTmpLastParentFrame = new Rect();
private static final Rect sTmpDisplayFrameBounds = new Rect();
@@ -430,8 +432,10 @@ public class DisplayPolicy {
final int displayId = displayContent.getDisplayId();
mBarContentFrames.put(TYPE_STATUS_BAR, new Rect());
mBarContentFrames.put(TYPE_NAVIGATION_BAR, new Rect());
if (!INSETS_LAYOUT_GENERALIZATION) {
mBarContentFrames.put(TYPE_STATUS_BAR, new Rect());
mBarContentFrames.put(TYPE_NAVIGATION_BAR, new Rect());
}
final Resources r = mContext.getResources();
mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
@@ -1081,7 +1085,9 @@ public class DisplayPolicy {
mStatusBar = win;
final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
(displayFrames, windowState, rect) -> {
rect.bottom = rect.top + getStatusBarHeight(displayFrames);
if (!INSETS_LAYOUT_GENERALIZATION) {
rect.bottom = rect.top + getStatusBarHeight(displayFrames);
}
};
mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider);
mDisplayContent.setInsetProvider(ITYPE_TOP_MANDATORY_GESTURES, win, frameProvider);
@@ -1091,18 +1097,22 @@ public class DisplayPolicy {
mNavigationBar = win;
mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
(displayFrames, windowState, inOutFrame) -> {
// In Gesture Nav, navigation bar frame is larger than frame to
// calculate inset.
if (navigationBarPosition(displayFrames.mDisplayWidth,
displayFrames.mDisplayHeight,
displayFrames.mRotation) == NAV_BAR_BOTTOM
&& !mNavButtonForcedVisible) {
sTmpRect.set(inOutFrame);
sTmpRect.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
inOutFrame.top = sTmpRect.bottom
- getNavigationBarHeight(displayFrames.mRotation,
mDisplayContent.getConfiguration().uiMode);
if (INSETS_LAYOUT_GENERALIZATION) {
inOutFrame.inset(windowState.getLayoutingAttrs(
displayFrames.mRotation).providedInternalInsets);
} else {
// In Gesture Nav, navigation bar frame is larger than frame to
// calculate inset.
if (navigationBarPosition(displayFrames.mDisplayWidth,
displayFrames.mDisplayHeight,
displayFrames.mRotation) == NAV_BAR_BOTTOM
&& !mNavButtonForcedVisible) {
sTmpRect.set(inOutFrame);
sTmpRect.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
inOutFrame.top = sTmpRect.bottom
- getNavigationBarHeight(displayFrames.mRotation,
mDisplayContent.getConfiguration().uiMode);
}
}
},
@@ -1163,7 +1173,14 @@ public class DisplayPolicy {
mExtraNavBarAltPosition = getAltBarPosition(attrs);
break;
}
mDisplayContent.setInsetProvider(insetsType, win, null);
if (!INSETS_LAYOUT_GENERALIZATION) {
mDisplayContent.setInsetProvider(insetsType, win, null);
} else {
mDisplayContent.setInsetProvider(insetsType, win, (displayFrames,
windowState, inOutFrame) -> inOutFrame.inset(
windowState.getLayoutingAttrs(displayFrames.mRotation)
.providedInternalInsets));
}
}
}
break;
@@ -1254,8 +1271,17 @@ public class DisplayPolicy {
}
private int getStatusBarHeight(DisplayFrames displayFrames) {
return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
displayFrames.mDisplayCutoutSafe.top);
int statusBarHeight;
if (INSETS_LAYOUT_GENERALIZATION) {
if (mStatusBar != null) {
statusBarHeight = mStatusBar.getLayoutingAttrs(displayFrames.mRotation).height;
} else {
statusBarHeight = 0;
}
} else {
statusBarHeight = mStatusBarHeightForRotation[displayFrames.mRotation];
}
return Math.max(statusBarHeight, displayFrames.mDisplayCutoutSafe.top);
}
WindowState getStatusBar() {
@@ -1425,13 +1451,30 @@ public class DisplayPolicy {
WindowFrames simulatedWindowFrames, SparseArray<Rect> contentFrames,
Consumer<Rect> layout) {
win.setSimulatedWindowFrames(simulatedWindowFrames);
final int requestedHeight = win.mRequestedHeight;
final int requestedWidth = win.mRequestedWidth;
if (INSETS_LAYOUT_GENERALIZATION) {
// Without a full layout process, in order to layout the system bars correctly, we need
// to set the requested size and the initial display frames to the window.
WindowManager.LayoutParams params = win.getLayoutingAttrs(displayFrames.mRotation);
win.setRequestedSize(params.width, params.height);
sTmpDecorFrame.set(0, 0, displayFrames.mDisplayWidth, displayFrames.mDisplayHeight);
simulatedWindowFrames.setFrames(sTmpDecorFrame /* parentFrame */,
sTmpDecorFrame /* displayFrame */);
simulatedWindowFrames.mIsSimulatingDecorWindow = true;
}
final Rect contentFrame = new Rect();
try {
layout.accept(contentFrame);
} finally {
win.setSimulatedWindowFrames(null);
if (INSETS_LAYOUT_GENERALIZATION) {
win.setRequestedSize(requestedWidth, requestedHeight);
}
}
if (!INSETS_LAYOUT_GENERALIZATION) {
contentFrames.put(win.mAttrs.type, contentFrame);
}
contentFrames.put(win.mAttrs.type, contentFrame);
mDisplayContent.getInsetsStateController().computeSimulatedState(
win, displayFrames, simulatedWindowFrames);
}
@@ -1442,15 +1485,31 @@ public class DisplayPolicy {
* some temporal states, but doesn't change the window frames used to show on screen.
*/
void simulateLayoutDisplay(DisplayFrames displayFrames, SparseArray<Rect> barContentFrames) {
final WindowFrames simulatedWindowFrames = new WindowFrames();
if (mNavigationBar != null) {
simulateLayoutDecorWindow(mNavigationBar, displayFrames, simulatedWindowFrames,
barContentFrames, contentFrame -> layoutNavigationBar(displayFrames,
contentFrame));
final WindowFrames simulatedWindowFrames = new WindowFrames();
if (INSETS_LAYOUT_GENERALIZATION) {
simulateLayoutDecorWindow(mNavigationBar, displayFrames, simulatedWindowFrames,
barContentFrames,
contentFrame -> simulateLayoutForContentFrame(displayFrames,
mNavigationBar, contentFrame));
} else {
simulateLayoutDecorWindow(mNavigationBar, displayFrames, simulatedWindowFrames,
barContentFrames, contentFrame -> layoutNavigationBar(displayFrames,
contentFrame));
}
}
if (mStatusBar != null) {
simulateLayoutDecorWindow(mStatusBar, displayFrames, simulatedWindowFrames,
barContentFrames, contentFrame -> layoutStatusBar(displayFrames, contentFrame));
final WindowFrames simulatedWindowFrames = new WindowFrames();
if (INSETS_LAYOUT_GENERALIZATION) {
simulateLayoutDecorWindow(mStatusBar, displayFrames, simulatedWindowFrames,
barContentFrames,
contentFrame -> simulateLayoutForContentFrame(displayFrames,
mStatusBar, contentFrame));
} else {
simulateLayoutDecorWindow(mStatusBar, displayFrames, simulatedWindowFrames,
barContentFrames,
contentFrame -> layoutStatusBar(displayFrames, contentFrame));
}
}
}
@@ -1469,7 +1528,7 @@ public class DisplayPolicy {
windowFrames.setFrames(sTmpStatusFrame /* parentFrame */,
sTmpStatusFrame /* displayFrame */);
// Let the status bar determine its size.
mStatusBar.computeFrameAndUpdateSourceFrame();
mStatusBar.computeFrameAndUpdateSourceFrame(displayFrames);
// For layout, the status bar is always at the top with our fixed height.
int statusBarBottom = displayFrames.mUnrestricted.top
@@ -1520,18 +1579,18 @@ public class DisplayPolicy {
} else if (navBarPosition == NAV_BAR_RIGHT) {
// Landscape screen; nav bar goes to the right.
navigationFrame.left = Math.min(cutoutSafeUnrestricted.right, navigationFrame.right)
- getNavigationBarWidth(rotation, uiMode);
- getNavigationBarWidth(rotation, uiMode, navBarPosition);
} else if (navBarPosition == NAV_BAR_LEFT) {
// Seascape screen; nav bar goes to the left.
navigationFrame.right = Math.max(cutoutSafeUnrestricted.left, navigationFrame.left)
+ getNavigationBarWidth(rotation, uiMode);
+ getNavigationBarWidth(rotation, uiMode, navBarPosition);
}
// Compute the final frame.
final WindowFrames windowFrames = mNavigationBar.getLayoutingWindowFrames();
windowFrames.setFrames(navigationFrame /* parentFrame */,
navigationFrame /* displayFrame */);
mNavigationBar.computeFrameAndUpdateSourceFrame();
mNavigationBar.computeFrameAndUpdateSourceFrame(displayFrames);
sTmpRect.set(windowFrames.mFrame);
sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
contentFrame.set(sTmpRect);
@@ -1540,6 +1599,16 @@ public class DisplayPolicy {
return navBarPosition;
}
private void simulateLayoutForContentFrame(DisplayFrames displayFrames, WindowState win,
Rect simulatedContentFrame) {
layoutWindowLw(win, null /* attached */, displayFrames);
final Rect contentFrame = sTmpRect;
contentFrame.set(win.getLayoutingWindowFrames().mFrame);
// Excluding the display cutout before set to the simulated content frame.
contentFrame.intersect(displayFrames.mDisplayCutoutSafe);
simulatedContentFrame.set(contentFrame);
}
private boolean canReceiveInput(WindowState win) {
boolean notFocusable =
(win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
@@ -1561,16 +1630,16 @@ public class DisplayPolicy {
* @param displayFrames The display frames.
*/
public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
if (win == mNavigationBar) {
if (win == mNavigationBar && !INSETS_LAYOUT_GENERALIZATION) {
mNavigationBarPosition = layoutNavigationBar(displayFrames,
mBarContentFrames.get(TYPE_NAVIGATION_BAR));
return;
}
if ((win == mStatusBar && !canReceiveInput(win))) {
if ((win == mStatusBar && !canReceiveInput(win)) && !INSETS_LAYOUT_GENERALIZATION) {
layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR));
return;
}
final WindowManager.LayoutParams attrs = win.getAttrs();
final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);
final int type = attrs.type;
final int fl = attrs.flags;
@@ -1578,7 +1647,7 @@ public class DisplayPolicy {
final int sim = attrs.softInputMode;
displayFrames = win.getDisplayFrames(displayFrames);
final WindowFrames windowFrames = win.getWindowFrames();
final WindowFrames windowFrames = win.getLayoutingWindowFrames();
sTmpLastParentFrame.set(windowFrames.mParentFrame);
final Rect pf = windowFrames.mParentFrame;
@@ -1589,7 +1658,13 @@ public class DisplayPolicy {
final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
final InsetsState state = win.getInsetsState();
computeWindowBounds(attrs, state, win.mToken.getBounds(), df);
if (windowFrames.mIsSimulatingDecorWindow && INSETS_LAYOUT_GENERALIZATION) {
// Override the bounds in window token has many side effects. Directly use the display
// frame set for the simulated layout for this case.
computeWindowBounds(attrs, state, df, df);
} else {
computeWindowBounds(attrs, state, win.mToken.getBounds(), df);
}
if (attached == null) {
pf.set(df);
if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
@@ -1689,7 +1764,17 @@ public class DisplayPolicy {
windowFrames.setContentChanged(true);
}
win.computeFrameAndUpdateSourceFrame();
win.computeFrameAndUpdateSourceFrame(displayFrames);
if (INSETS_LAYOUT_GENERALIZATION && attrs.type == TYPE_STATUS_BAR) {
if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
// Make sure that the zone we're avoiding for the cutout is at least as tall as the
// status bar; otherwise fullscreen apps will end up cutting halfway into the status
// bar.
displayFrames.mDisplayCutoutSafe.top = Math.max(
displayFrames.mDisplayCutoutSafe.top,
windowFrames.mFrame.bottom);
}
}
}
WindowState getTopFullscreenOpaqueWindow() {
@@ -2118,11 +2203,37 @@ public class DisplayPolicy {
return mUiContext;
}
private int getNavigationBarWidth(int rotation, int uiMode) {
if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
return mNavigationBarWidthForRotationInCarMode[rotation];
private int getNavigationBarWidth(int rotation, int uiMode, int position) {
if (INSETS_LAYOUT_GENERALIZATION) {
if (mNavigationBar == null) {
return 0;
}
LayoutParams lp = mNavigationBar.mAttrs;
if (lp.paramsForRotation != null
&& lp.paramsForRotation.length == 4
&& lp.paramsForRotation[rotation] != null) {
lp = lp.paramsForRotation[rotation];
}
if (position == NAV_BAR_LEFT) {
if (lp.width > lp.providedInternalInsets.right) {
return lp.width - lp.providedInternalInsets.right;
} else {
return 0;
}
} else if (position == NAV_BAR_RIGHT) {
if (lp.width > lp.providedInternalInsets.left) {
return lp.width - lp.providedInternalInsets.left;
} else {
return 0;
}
}
return lp.width;
} else {
return mNavigationBarWidthForRotationDefault[rotation];
if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
return mNavigationBarWidthForRotationInCarMode[rotation];
} else {
return mNavigationBarWidthForRotationDefault[rotation];
}
}
}
@@ -2149,7 +2260,7 @@ public class DisplayPolicy {
if (hasNavigationBar()) {
final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
width -= getNavigationBarWidth(rotation, uiMode);
width -= getNavigationBarWidth(rotation, uiMode, navBarPosition);
}
}
if (displayCutout != null) {
@@ -2159,10 +2270,21 @@ public class DisplayPolicy {
}
private int getNavigationBarHeight(int rotation, int uiMode) {
if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
return mNavigationBarHeightForRotationInCarMode[rotation];
if (INSETS_LAYOUT_GENERALIZATION) {
if (mNavigationBar == null) {
return 0;
}
LayoutParams lp = mNavigationBar.getLayoutingAttrs(rotation);
if (lp.height < lp.providedInternalInsets.top) {
return 0;
}
return lp.height - lp.providedInternalInsets.top;
} else {
return mNavigationBarHeightForRotationDefault[rotation];
if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
return mNavigationBarHeightForRotationInCarMode[rotation];
} else {
return mNavigationBarHeightForRotationDefault[rotation];
}
}
}
@@ -2179,10 +2301,17 @@ public class DisplayPolicy {
* @return navigation bar frame height
*/
private int getNavigationBarFrameHeight(int rotation, int uiMode) {
if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
return mNavigationBarHeightForRotationInCarMode[rotation];
if (INSETS_LAYOUT_GENERALIZATION) {
if (mNavigationBar == null) {
return 0;
}
return mNavigationBar.mAttrs.height;
} else {
return mNavigationBarFrameHeightForRotationDefault[rotation];
if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
return mNavigationBarHeightForRotationInCarMode[rotation];
} else {
return mNavigationBarFrameHeightForRotationDefault[rotation];
}
}
}
@@ -2303,9 +2432,9 @@ public class DisplayPolicy {
if (position == NAV_BAR_BOTTOM) {
outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
} else if (position == NAV_BAR_RIGHT) {
outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
outInsets.right = getNavigationBarWidth(displayRotation, uiMode, position);
} else if (position == NAV_BAR_LEFT) {
outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
outInsets.left = getNavigationBarWidth(displayRotation, uiMode, position);
}
}
@@ -2331,6 +2460,17 @@ public class DisplayPolicy {
@NavigationBarPosition
int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
if (INSETS_LAYOUT_GENERALIZATION && mNavigationBar != null) {
final int gravity = mNavigationBar.getLayoutingAttrs(displayRotation).gravity;
switch (gravity) {
case Gravity.LEFT:
return NAV_BAR_LEFT;
case Gravity.RIGHT:
return NAV_BAR_RIGHT;
default:
return NAV_BAR_BOTTOM;
}
}
if (navigationBarCanMove() && displayWidth > displayHeight) {
if (displayRotation == Surface.ROTATION_270) {
return NAV_BAR_LEFT;
@@ -2694,7 +2834,24 @@ public class DisplayPolicy {
private Rect getBarContentFrameForWindow(WindowState win, int windowType) {
final Rect rotatedBarFrame = win.mToken.getFixedRotationBarContentFrame(windowType);
return rotatedBarFrame != null ? rotatedBarFrame : mBarContentFrames.get(windowType);
if (rotatedBarFrame != null) {
return rotatedBarFrame;
}
if (!INSETS_LAYOUT_GENERALIZATION) {
return mBarContentFrames.get(windowType);
}
// We only need a window specific information for the fixed rotation, use raw insets state
// for all other cases.
InsetsState insetsState = mDisplayContent.getInsetsStateController().getRawInsetsState();
final Rect tmpRect = new Rect();
if (windowType == TYPE_NAVIGATION_BAR) {
tmpRect.set(insetsState.getSource(InsetsState.ITYPE_NAVIGATION_BAR).getFrame());
}
if (windowType == TYPE_STATUS_BAR) {
tmpRect.set(insetsState.getSource(InsetsState.ITYPE_STATUS_BAR).getFrame());
}
tmpRect.intersect(mDisplayContent.mDisplayFrames.mDisplayCutoutSafe);
return tmpRect;
}
/**

View File

@@ -88,6 +88,11 @@ public class WindowFrames {
// screen size compatibility mode.
final Rect mCompatFrame = new Rect();
/**
* {@code true} if the window frame is a simulated frame and attached to a decor window.
*/
boolean mIsSimulatingDecorWindow = false;
/**
* Whether the parent frame would have been different if there was no display cutout.
*/

View File

@@ -2515,7 +2515,8 @@ public class WindowManagerService extends IWindowManager.Stub
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
if (winAnimator.mSurfaceController != null) {
win.calculateSurfaceBounds(win.getAttrs(), mTmpRect);
win.calculateSurfaceBounds(win.getLayoutingAttrs(
win.getWindowConfiguration().getRotation()), mTmpRect);
outSurfaceSize.set(mTmpRect.width(), mTmpRect.height());
}
getInsetsSourceControls(win, outActiveControls);

View File

@@ -34,6 +34,7 @@ import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.SurfaceControl.Transaction;
import static android.view.SurfaceControl.getGlobalTransaction;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -1258,8 +1259,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
frame.inset(left, top, right, bottom);
}
void computeFrameAndUpdateSourceFrame() {
computeFrame();
void computeFrameAndUpdateSourceFrame(DisplayFrames displayFrames) {
computeFrame(displayFrames);
// Update the source frame to provide insets to other windows during layout. If the
// simulated frames exist, then this is not computing a stable result so just skip.
if (mControllableInsetProvider != null && mSimulatedWindowFrames == null) {
@@ -1270,7 +1271,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/**
* Perform standard frame computation. The result can be obtained with getFrame() if so desired.
*/
void computeFrame() {
void computeFrame(DisplayFrames displayFrames) {
if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
// This window is being replaced and either already got information that it's being
// removed or we are still waiting for some information. Because of this we don't
@@ -1383,7 +1384,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final int fw = windowFrames.mFrame.width();
final int fh = windowFrames.mFrame.height();
applyGravityAndUpdateFrame(windowFrames, layoutContainingFrame, layoutDisplayFrame);
applyGravityAndUpdateFrame(windowFrames, layoutContainingFrame, layoutDisplayFrame,
displayFrames);
if (mAttrs.type == TYPE_DOCK_DIVIDER) {
if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) {
@@ -1476,6 +1478,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mAttrs;
}
WindowManager.LayoutParams getLayoutingAttrs(int rotation) {
if (!INSETS_LAYOUT_GENERALIZATION) {
return mAttrs;
}
final WindowManager.LayoutParams[] paramsForRotation = mAttrs.paramsForRotation;
if (paramsForRotation == null || paramsForRotation.length != 4
|| paramsForRotation[rotation] == null) {
return mAttrs;
}
return paramsForRotation[rotation];
}
/** Retrieves the flags used to disable system UI functions. */
int getDisableFlags() {
return mDisableFlags;
@@ -4395,12 +4409,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
private void applyGravityAndUpdateFrame(WindowFrames windowFrames, Rect containingFrame,
Rect displayFrame) {
Rect displayFrame, DisplayFrames displayFrames) {
final int pw = containingFrame.width();
final int ph = containingFrame.height();
final Task task = getTask();
final boolean inNonFullscreenContainer = !inAppWindowThatMatchesParentBounds();
final boolean noLimits = (mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
final WindowManager.LayoutParams attrs = getLayoutingAttrs(displayFrames.mRotation);
final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
// We need to fit it to the display if either
// a) The window is in a fullscreen container, or we don't have a task (we assume fullscreen
@@ -4410,49 +4425,54 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// screen, but SurfaceViews want to be always at a specific location so we don't fit it to
// the display.
final boolean fitToDisplay = (task == null || !inNonFullscreenContainer)
|| ((mAttrs.type != TYPE_BASE_APPLICATION) && !noLimits);
|| ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits);
float x, y;
int w,h;
final boolean hasCompatScale = hasCompatScale();
if ((mAttrs.flags & FLAG_SCALED) != 0) {
if (mAttrs.width < 0) {
if ((attrs.flags & FLAG_SCALED) != 0 || mAttrs != attrs) {
// For the window with different layout attrs for different rotations, we need to avoid
// using requested size. Otherwise, when finishing a simulated rotation, the information
// coming from WindowManagerServices to the ViewRootImpl may not contain the correct
// value for the new rotation, and there will be a quick flash of wrong layout when the
// simulated activity faded out.
if (attrs.width < 0) {
w = pw;
} else if (hasCompatScale) {
w = (int)(mAttrs.width * mGlobalScale + .5f);
w = (int) (attrs.width * mGlobalScale + .5f);
} else {
w = mAttrs.width;
w = attrs.width;
}
if (mAttrs.height < 0) {
if (attrs.height < 0) {
h = ph;
} else if (hasCompatScale) {
h = (int)(mAttrs.height * mGlobalScale + .5f);
h = (int) (attrs.height * mGlobalScale + .5f);
} else {
h = mAttrs.height;
h = attrs.height;
}
} else {
if (mAttrs.width == MATCH_PARENT) {
if (attrs.width == MATCH_PARENT) {
w = pw;
} else if (hasCompatScale) {
w = (int)(mRequestedWidth * mGlobalScale + .5f);
w = (int) (mRequestedWidth * mGlobalScale + .5f);
} else {
w = mRequestedWidth;
}
if (mAttrs.height == MATCH_PARENT) {
if (attrs.height == MATCH_PARENT) {
h = ph;
} else if (hasCompatScale) {
h = (int)(mRequestedHeight * mGlobalScale + .5f);
h = (int) (mRequestedHeight * mGlobalScale + .5f);
} else {
h = mRequestedHeight;
}
}
if (hasCompatScale) {
x = mAttrs.x * mGlobalScale;
y = mAttrs.y * mGlobalScale;
x = attrs.x * mGlobalScale;
y = attrs.y * mGlobalScale;
} else {
x = mAttrs.x;
y = mAttrs.y;
x = attrs.x;
y = attrs.y;
}
if (inNonFullscreenContainer && !layoutInParentFrame()) {
@@ -4479,13 +4499,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
// Set mFrame
Gravity.apply(mAttrs.gravity, w, h, containingFrame,
(int) (x + mAttrs.horizontalMargin * pw),
(int) (y + mAttrs.verticalMargin * ph), windowFrames.mFrame);
Gravity.apply(attrs.gravity, w, h, containingFrame,
(int) (x + attrs.horizontalMargin * pw),
(int) (y + attrs.verticalMargin * ph), windowFrames.mFrame);
// Now make sure the window fits in the overall display frame.
if (fitToDisplay) {
Gravity.applyDisplay(mAttrs.gravity, displayFrame, windowFrames.mFrame);
Gravity.applyDisplay(attrs.gravity, displayFrame, windowFrames.mFrame);
}
// We need to make sure we update the CompatFrame as it is used for

View File

@@ -16,9 +16,11 @@
package com.android.server.wm;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -451,9 +453,24 @@ class WindowToken extends WindowContainer<WindowState> {
}
Rect getFixedRotationBarContentFrame(int windowType) {
return isFixedRotationTransforming()
? mFixedRotationTransformState.mBarContentFrames.get(windowType)
: null;
if (!isFixedRotationTransforming()) {
return null;
}
if (!INSETS_LAYOUT_GENERALIZATION) {
return mFixedRotationTransformState.mBarContentFrames.get(windowType);
}
final DisplayFrames displayFrames = mFixedRotationTransformState.mDisplayFrames;
final Rect tmpRect = new Rect();
if (windowType == TYPE_NAVIGATION_BAR) {
tmpRect.set(displayFrames.mInsetsState.getSource(InsetsState.ITYPE_NAVIGATION_BAR)
.getFrame());
}
if (windowType == TYPE_STATUS_BAR) {
tmpRect.set(displayFrames.mInsetsState.getSource(InsetsState.ITYPE_STATUS_BAR)
.getFrame());
}
tmpRect.intersect(displayFrames.mDisplayCutoutSafe);
return tmpRect;
}
InsetsState getFixedRotationTransformInsetsState() {

View File

@@ -24,7 +24,7 @@ import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
@@ -50,13 +50,13 @@ import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import static org.testng.Assert.expectThrows;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
@@ -69,7 +69,6 @@ import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -109,12 +108,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow = spy(createWindow(null, TYPE_APPLICATION, "window"));
// We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from
// changing those frames.
doNothing().when(mWindow).computeFrame();
final WindowManager.LayoutParams attrs = mWindow.mAttrs;
attrs.width = MATCH_PARENT;
attrs.height = MATCH_PARENT;
attrs.format = PixelFormat.TRANSLUCENT;
doNothing().when(mWindow).computeFrame(any());
spyOn(mStatusBarWindow);
spyOn(mNavBarWindow);
@@ -219,7 +213,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
}
@Test
public void addingWindow_ignoresInsetsTypes_InWindowTypeWithPredefinedInsets() {
public void addingWindow_InWindowTypeWithPredefinedInsets() {
mDisplayPolicy.removeWindowLw(mStatusBarWindow); // Removes the existing one.
WindowState win = createWindow(null, TYPE_STATUS_BAR, "StatusBar");
win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR};
@@ -230,7 +224,13 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
InsetsSourceProvider provider =
mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR);
assertNotEquals(new Rect(0, 0, 500, 100), provider.getSource().getFrame());
if (INSETS_LAYOUT_GENERALIZATION) {
// In the new flexible insets setup, the insets frame should always respect the window
// layout result.
assertEquals(new Rect(0, 0, 500, 100), provider.getSource().getFrame());
} else {
assertNotEquals(new Rect(0, 0, 500, 100), provider.getSource().getFrame());
}
}
@Test
@@ -733,10 +733,12 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
@Test
public void testFixedRotationInsetsSourceFrame() {
mDisplayContent.mBaseDisplayHeight = DISPLAY_HEIGHT;
mDisplayContent.mBaseDisplayWidth = DISPLAY_WIDTH;
doReturn((mDisplayContent.getRotation() + 1) % 4).when(mDisplayContent)
.rotationForActivityInDifferentOrientation(eq(mWindow.mActivityRecord));
mWindow.mAboveInsetsState.addSource(mDisplayContent.getInsetsStateController()
.getRawInsetsState().peekSource(ITYPE_STATUS_BAR));
mWindow.mAboveInsetsState.set(
mDisplayContent.getInsetsStateController().getRawInsetsState());
final Rect frame = mDisplayPolicy.getInsetsPolicy().getInsetsForWindow(mWindow)
.getSource(ITYPE_STATUS_BAR).getFrame();
mDisplayContent.rotateInDifferentOrientationIfNeeded(mWindow.mActivityRecord);

View File

@@ -313,7 +313,9 @@ public class DisplayPolicyTests extends WindowTestsBase {
displayInfo.logicalHeight = 2000;
displayInfo.rotation = ROTATION_0;
displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
WindowManager.LayoutParams attrs = mNavBarWindow.mAttrs;
displayPolicy.addWindowLw(mNavBarWindow, attrs);
mNavBarWindow.setRequestedSize(attrs.width, attrs.height);
mNavBarWindow.getControllableInsetProvider().setServerVisible(true);
final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
mImeWindow.mAboveInsetsState.set(state);

View File

@@ -58,8 +58,6 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
static final int DISPLAY_HEIGHT = 1000;
static final int DISPLAY_DENSITY = 320;
static final int STATUS_BAR_HEIGHT = 10;
static final int NAV_BAR_HEIGHT = 15;
static final int DISPLAY_CUTOUT_HEIGHT = 8;
static final int IME_HEIGHT = 415;

View File

@@ -57,12 +57,14 @@ import org.mockito.Mockito;
public class WindowFrameTests extends WindowTestsBase {
private DisplayContent mTestDisplayContent;
private DisplayFrames mTestDisplayFrames;
@Before
public void setUp() throws Exception {
DisplayInfo testDisplayInfo = new DisplayInfo(mDisplayInfo);
testDisplayInfo.displayCutout = null;
mTestDisplayContent = createNewDisplay(testDisplayInfo);
mTestDisplayFrames = mTestDisplayContent.mDisplayFrames;
}
// Do not use this function directly in the tests below. Instead, use more explicit function
@@ -99,7 +101,7 @@ public class WindowFrameTests extends WindowTestsBase {
// Here the window has FILL_PARENT, FILL_PARENT
// so we expect it to fill the entire available frame.
w.getWindowFrames().setFrames(pf, pf);
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, 0, 0, 1000, 1000);
assertRelFrame(w, 0, 0, 1000, 1000);
@@ -108,14 +110,14 @@ public class WindowFrameTests extends WindowTestsBase {
// and we use mRequestedWidth/mRequestedHeight
w.mAttrs.width = 300;
w.mAttrs.height = 300;
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
// Explicit width and height without requested width/height
// gets us nothing.
assertFrame(w, 0, 0, 0, 0);
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
// With requestedWidth/Height we can freely choose our size within the
// parent bounds.
assertFrame(w, 0, 0, 300, 300);
@@ -128,14 +130,14 @@ public class WindowFrameTests extends WindowTestsBase {
w.mRequestedWidth = -1;
w.mAttrs.width = 100;
w.mAttrs.height = 100;
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, 0, 0, 100, 100);
w.mAttrs.flags = 0;
// But sizes too large will be clipped to the containing frame
w.mRequestedWidth = 1200;
w.mRequestedHeight = 1200;
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, 0, 0, 1000, 1000);
// Before they are clipped though windows will be shifted
@@ -143,7 +145,7 @@ public class WindowFrameTests extends WindowTestsBase {
w.mAttrs.y = 300;
w.mRequestedWidth = 1000;
w.mRequestedHeight = 1000;
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, 0, 0, 1000, 1000);
// If there is room to move around in the parent frame the window will be shifted according
@@ -153,18 +155,18 @@ public class WindowFrameTests extends WindowTestsBase {
w.mRequestedWidth = 300;
w.mRequestedHeight = 300;
w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, 700, 0, 1000, 300);
assertRelFrame(w, 700, 0, 1000, 300);
w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, 700, 700, 1000, 1000);
assertRelFrame(w, 700, 700, 1000, 1000);
// Window specified x and y are interpreted as offsets in the opposite
// direction of gravity
w.mAttrs.x = 100;
w.mAttrs.y = 100;
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, 600, 600, 900, 900);
assertRelFrame(w, 600, 600, 900, 900);
}
@@ -191,7 +193,7 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, pf);
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertEquals(resolvedTaskBounds, w.getFrame());
@@ -204,7 +206,7 @@ public class WindowFrameTests extends WindowTestsBase {
final int cfBottom = logicalHeight / 2;
final Rect cf = new Rect(0, 0, cfRight, cfBottom);
windowFrames.setFrames(pf, pf);
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertEquals(resolvedTaskBounds, w.getFrame());
assertEquals(0, w.getRelativeFrame().left);
assertEquals(0, w.getRelativeFrame().top);
@@ -233,7 +235,7 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
final WindowFrames windowFrames = w.getWindowFrames();
windowFrames.setFrames(pf, pf);
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -249,7 +251,7 @@ public class WindowFrameTests extends WindowTestsBase {
task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
task.setBounds(null);
windowFrames.setFrames(pf, pf);
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, cf);
}
@@ -285,7 +287,7 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect winRect = new Rect(200, 200, 300, 500);
task.setBounds(winRect);
w.getWindowFrames().setFrames(pf, pf);
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, winRect.left, imeFrame.top - winRect.height(), winRect.right, imeFrame.top);
// Now check that it won't get moved beyond the top
@@ -293,7 +295,7 @@ public class WindowFrameTests extends WindowTestsBase {
task.setBounds(winRect);
w.setBounds(winRect);
w.getWindowFrames().setFrames(pf, pf);
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, winRect.left, 0, winRect.right, winRect.height());
// Now we have status bar. Check that it won't go into the status bar area.
@@ -301,14 +303,14 @@ public class WindowFrameTests extends WindowTestsBase {
statusBarFrame.bottom = 60;
state.getSource(ITYPE_STATUS_BAR).setFrame(statusBarFrame);
w.getWindowFrames().setFrames(pf, pf);
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertFrame(w, winRect.left, statusBarFrame.bottom, winRect.right,
statusBarFrame.bottom + winRect.height());
// Check that it's moved back without ime insets
state.removeSource(ITYPE_IME);
w.getWindowFrames().setFrames(pf, pf);
w.computeFrame();
w.computeFrame(mTestDisplayFrames);
assertEquals(winRect, w.getFrame());
}

View File

@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -29,11 +30,13 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.os.Process.SYSTEM_UID;
import static android.view.View.VISIBLE;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -83,10 +86,12 @@ import android.service.voice.IVoiceInteractionSession;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IDisplayWindowInsetsController;
import android.view.IWindow;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
@@ -132,6 +137,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
DisplayInfo mDisplayInfo = new DisplayInfo();
DisplayContent mDefaultDisplay;
static final int STATUS_BAR_HEIGHT = 10;
static final int NAV_BAR_HEIGHT = 15;
/**
* It is {@link #mDefaultDisplay} by default. If the test class or method is annotated with
* {@link UseTestDisplay}, it will be an additional display.
@@ -268,6 +276,14 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
if (addAll || ArrayUtils.contains(requestedWindows, W_STATUS_BAR)) {
mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
if (INSETS_LAYOUT_GENERALIZATION) {
mStatusBarWindow.mAttrs.height = STATUS_BAR_HEIGHT;
mStatusBarWindow.mAttrs.gravity = Gravity.TOP;
mStatusBarWindow.mAttrs.layoutInDisplayCutoutMode =
LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mStatusBarWindow.setRequestedSize(WindowManager.LayoutParams.MATCH_PARENT,
STATUS_BAR_HEIGHT);
}
}
if (addAll || ArrayUtils.contains(requestedWindows, W_NOTIFICATION_SHADE)) {
mNotificationShadeWindow = createCommonWindow(null, TYPE_NOTIFICATION_SHADE,
@@ -275,6 +291,15 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
if (addAll || ArrayUtils.contains(requestedWindows, W_NAVIGATION_BAR)) {
mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
if (INSETS_LAYOUT_GENERALIZATION) {
mNavBarWindow.mAttrs.height = NAV_BAR_HEIGHT;
mNavBarWindow.mAttrs.gravity = Gravity.BOTTOM;
mNavBarWindow.mAttrs.paramsForRotation = new WindowManager.LayoutParams[4];
for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
mNavBarWindow.mAttrs.paramsForRotation[rot] =
getNavBarLayoutParamsForRotation(rot);
}
}
}
if (addAll || ArrayUtils.contains(requestedWindows, W_DOCK_DIVIDER)) {
mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER,
@@ -302,6 +327,37 @@ class WindowTestsBase extends SystemServiceTestsBase {
waitUntilHandlersIdle();
}
private WindowManager.LayoutParams getNavBarLayoutParamsForRotation(int rotation) {
int width = WindowManager.LayoutParams.MATCH_PARENT;
int height = WindowManager.LayoutParams.MATCH_PARENT;
int gravity = Gravity.BOTTOM;
if (INSETS_LAYOUT_GENERALIZATION) {
switch (rotation) {
case ROTATION_UNDEFINED:
case Surface.ROTATION_0:
case Surface.ROTATION_180:
height = NAV_BAR_HEIGHT;
break;
case Surface.ROTATION_90:
gravity = Gravity.RIGHT;
width = NAV_BAR_HEIGHT;
break;
case Surface.ROTATION_270:
gravity = Gravity.LEFT;
width = NAV_BAR_HEIGHT;
break;
}
}
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR);
lp.width = width;
lp.height = height;
if (INSETS_LAYOUT_GENERALIZATION) {
lp.gravity = gravity;
}
return lp;
}
void beforeCreateTestDisplay() {
// Called before display is created.
}