Merge "Layout status/nav bar and decor window as normal window" into sc-v2-dev

This commit is contained in:
Yunfan Chen
2021-06-17 01:46:00 +00:00
committed by Android (Google) Code Review
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;
@@ -3467,6 +3468,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.
*
@@ -3566,6 +3583,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;
@@ -3818,6 +3847,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
@@ -3887,6 +3924,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"})
@@ -4169,6 +4212,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;
}
@@ -4356,6 +4410,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;
@@ -1259,8 +1260,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) {
@@ -1271,7 +1272,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
@@ -1384,7 +1385,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)) {
@@ -1477,6 +1479,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;
@@ -4412,12 +4426,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
@@ -4427,49 +4442,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()) {
@@ -4496,13 +4516,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.
}