Refine the provide insets parameters

There're 3 different parameters trying to affect the insets provided by
a window and can be set independently but are related. This change will
make a new class InsetsFrameProvider to let the window set all the
information needed for the insets at the same place.

Besides, this change also extends the insets calculation logic to
support more use cases. With this, the bars can provide insets outside
of its window frame as well.

Test: atest DisplayPolicyLayoutTests
Bug: 161689946
Bug: 232044523
Change-Id: I7059b3a222745818b6852a288416e197e2afd7b2
This commit is contained in:
Yunfan Chen
2022-04-18 18:55:08 +09:00
parent 833288448a
commit bcadfd2476
9 changed files with 373 additions and 193 deletions

View File

@@ -0,0 +1,205 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import android.graphics.Insets;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* Insets provided by a window.
*
* The insets frame will by default as the window frame size. If the providers are set, the
* calculation result based on the source size will be used as the insets frame.
* @hide
*/
public class InsetsFrameProvider implements Parcelable {
/**
* If specified in source field, the insets calculation will be based on the display frame.
*/
public static final int SOURCE_DISPLAY = 0;
/**
* If specified in source field, the insets calculation will be based on the window bounds. The
* container bounds can sometimes be different from the window frame. For example, when a task
* bar needs the entire screen to be prepared to showing the apps, the window container can take
* the entire display, or display area, but the window frame, as a result of the layout, will
* stay small until it actually taking the entire display to draw their view.
*/
public static final int SOURCE_CONTAINER_BOUNDS = 1;
/**
* If specified in source field, the insets calculation will be based on the window frame. This
* is also the default value of the source.
*/
public static final int SOURCE_FRAME = 2;
private static final int HAS_INSETS_SIZE = 1;
private static final int HAS_IME_INSETS_SIZE = 2;
/**
* The type of insets to provide.
*/
public @InsetsState.InternalInsetsType int type;
/**
* The source of frame. By default, all adjustment will be based on the window frame, it
* can be set to window bounds or display bounds instead.
*/
public int source = SOURCE_FRAME;
/**
* The provided insets size based on the source frame. The result will be used as the insets
* size to windows other than IME. Only one side should be set.
*
* For example, when the given source frame is (0, 0) - (100, 200), and the insetsSize is null,
* the source frame will be directly used as the final insets frame. If the insetsSize is set to
* (0, 0, 0, 50) instead, the insets frame will be a frame starting from the bottom side of the
* source frame with height of 50, i.e., (0, 150) - (100, 200).
*/
public Insets insetsSize = null;
/**
* The provided frame based on the source frame. The result will be used as the insets
* size to IME window. Only one side should be set.
*/
public Insets imeInsetsSize = null;
public InsetsFrameProvider(int type) {
this(type, SOURCE_FRAME, null, null);
}
public InsetsFrameProvider(int type, Insets insetsSize) {
this(type, SOURCE_FRAME, insetsSize, insetsSize);
}
public InsetsFrameProvider(int type, Insets insetsSize, Insets imeInsetsSize) {
this(type, SOURCE_FRAME, insetsSize, imeInsetsSize);
}
public InsetsFrameProvider(int type, int source, Insets insetsSize,
Insets imeInsetsSize) {
this.type = type;
this.source = source;
this.insetsSize = insetsSize;
this.imeInsetsSize = imeInsetsSize;
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(32);
sb.append("InsetsFrameProvider: {");
sb.append("type=").append(InsetsState.typeToString(type));
sb.append(", source=");
switch (source) {
case SOURCE_DISPLAY:
sb.append("SOURCE_DISPLAY");
break;
case SOURCE_CONTAINER_BOUNDS:
sb.append("SOURCE_CONTAINER_BOUNDS Bounds");
break;
case SOURCE_FRAME:
sb.append("SOURCE_FRAME");
break;
}
if (insetsSize != null) {
sb.append(", insetsSize=").append(insetsSize);
}
if (imeInsetsSize != null) {
sb.append(", imeInsetsSize=").append(imeInsetsSize);
}
sb.append("}");
return sb.toString();
}
public InsetsFrameProvider(Parcel in) {
int insetsSizeModified = in.readInt();
type = in.readInt();
source = in.readInt();
if ((insetsSizeModified & HAS_INSETS_SIZE) != 0) {
insetsSize = Insets.CREATOR.createFromParcel(in);
}
if ((insetsSizeModified & HAS_IME_INSETS_SIZE) != 0) {
imeInsetsSize = Insets.CREATOR.createFromParcel(in);
}
}
@Override
public void writeToParcel(Parcel out, int flags) {
int insetsSizeModified = 0;
if (insetsSize != null) {
insetsSizeModified |= HAS_INSETS_SIZE;
}
if (imeInsetsSize != null) {
insetsSizeModified |= HAS_IME_INSETS_SIZE;
}
out.writeInt(insetsSizeModified);
out.writeInt(type);
out.writeInt(source);
if (insetsSize != null) {
insetsSize.writeToParcel(out, flags);
}
if (imeInsetsSize != null) {
imeInsetsSize.writeToParcel(out, flags);
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
InsetsFrameProvider other = (InsetsFrameProvider) o;
return type == other.type && source == other.source
&& Objects.equals(insetsSize, other.insetsSize)
&& Objects.equals(imeInsetsSize, other.imeInsetsSize);
}
@Override
public int hashCode() {
int result = type;
result = 31 * result + source;
result = 31 * result + (insetsSize != null ? insetsSize.hashCode() : 0);
result = 31 * result + (imeInsetsSize != null ? imeInsetsSize.hashCode() : 0);
return result;
}
public static final @android.annotation.NonNull Parcelable.Creator<InsetsFrameProvider>
CREATOR = new Parcelable.Creator<InsetsFrameProvider>() {
@Override
public InsetsFrameProvider createFromParcel(Parcel in) {
return new InsetsFrameProvider(in);
}
@Override
public InsetsFrameProvider[] newArray(int size) {
return new InsetsFrameProvider[size];
}
};
}

View File

@@ -98,7 +98,6 @@ import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -3610,34 +3609,17 @@ public interface WindowManager extends ViewManager {
private boolean mFitInsetsIgnoringVisibility = false;
/**
* {@link InsetsState.InternalInsetsType}s to be applied to the window
* If {@link #type} has the predefined insets (like {@link #TYPE_STATUS_BAR} or
* {@link #TYPE_NAVIGATION_BAR}), this field will be ignored.
*
* <p>Note: provide only one inset corresponding to the window type (like
* {@link InsetsState.InternalInsetsType#ITYPE_STATUS_BAR} or
* {@link InsetsState.InternalInsetsType#ITYPE_NAVIGATION_BAR})</p>
* @hide
*/
public @InsetsState.InternalInsetsType int[] providesInsetsTypes;
/**
* If specified, the insets provided by this window will be our window frame minus the
* insets specified by providedInternalInsets for each type. This should not be used
* together with {@link WindowState#mGivenContentInsets}. If both of them are set, both will
* be applied.
* If set, the specified insets types will be provided by the window and the insets frame
* will be calculated based on the provider's parameters. The insets types and the array
* should not be modified after the window is added. If multiple layout parameters are
* provided for different rotations in {@link LayoutParams#paramsForRotation}, the types in
* the providedInsets array should be the same in all rotations, including the base one.
* All other params can be adjusted at runtime.
* See {@link InsetsFrameProvider}.
*
* @hide
*/
public Insets[] providedInternalInsets;
/**
* If specified, the insets provided by this window for the IME will be our window frame
* minus the insets specified by providedInternalImeInsets.
*
* @hide
*/
public Insets[] providedInternalImeInsets;
public InsetsFrameProvider[] providedInsets;
/**
* If specified, the frame that used to calculate relative {@link RoundedCorner} will be
@@ -4051,33 +4033,11 @@ public interface WindowManager extends ViewManager {
out.writeBoolean(mFitInsetsIgnoringVisibility);
out.writeBoolean(preferMinimalPostProcessing);
out.writeInt(mBlurBehindRadius);
if (providesInsetsTypes != null) {
out.writeInt(providesInsetsTypes.length);
out.writeIntArray(providesInsetsTypes);
} else {
out.writeInt(0);
}
if (providedInternalInsets != null) {
out.writeInt(providedInternalInsets.length);
out.writeTypedArray(providedInternalInsets, 0 /* parcelableFlags */);
} else {
out.writeInt(0);
}
if (providedInternalImeInsets != null) {
out.writeInt(providedInternalImeInsets.length);
out.writeTypedArray(providedInternalImeInsets, 0 /* parcelableFlags */);
} else {
out.writeInt(0);
}
out.writeBoolean(insetsRoundedCornerFrame);
if (paramsForRotation != null) {
checkNonRecursiveParams();
out.writeInt(paramsForRotation.length);
out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
} else {
out.writeInt(0);
}
out.writeBoolean(mWallpaperTouchEventsEnabled);
out.writeTypedArray(providedInsets, 0 /* parcelableFlags */);
checkNonRecursiveParams();
out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
}
public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -4144,28 +4104,10 @@ public interface WindowManager extends ViewManager {
mFitInsetsIgnoringVisibility = in.readBoolean();
preferMinimalPostProcessing = in.readBoolean();
mBlurBehindRadius = in.readInt();
int insetsTypesLength = in.readInt();
if (insetsTypesLength > 0) {
providesInsetsTypes = new int[insetsTypesLength];
in.readIntArray(providesInsetsTypes);
}
int providedInternalInsetsLength = in.readInt();
if (providedInternalInsetsLength > 0) {
providedInternalInsets = new Insets[providedInternalInsetsLength];
in.readTypedArray(providedInternalInsets, Insets.CREATOR);
}
int providedInternalImeInsetsLength = in.readInt();
if (providedInternalImeInsetsLength > 0) {
providedInternalImeInsets = new Insets[providedInternalImeInsetsLength];
in.readTypedArray(providedInternalImeInsets, Insets.CREATOR);
}
insetsRoundedCornerFrame = in.readBoolean();
int paramsForRotationLength = in.readInt();
if (paramsForRotationLength > 0) {
paramsForRotation = new LayoutParams[paramsForRotationLength];
in.readTypedArray(paramsForRotation, LayoutParams.CREATOR);
}
mWallpaperTouchEventsEnabled = in.readBoolean();
providedInsets = in.createTypedArray(InsetsFrameProvider.CREATOR);
paramsForRotation = in.createTypedArray(LayoutParams.CREATOR);
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -4457,18 +4399,8 @@ public interface WindowManager extends ViewManager {
changes |= LAYOUT_CHANGED;
}
if (!Arrays.equals(providesInsetsTypes, o.providesInsetsTypes)) {
providesInsetsTypes = o.providesInsetsTypes;
changes |= LAYOUT_CHANGED;
}
if (!Arrays.equals(providedInternalInsets, o.providedInternalInsets)) {
providedInternalInsets = o.providedInternalInsets;
changes |= LAYOUT_CHANGED;
}
if (!Arrays.equals(providedInternalImeInsets, o.providedInternalImeInsets)) {
providedInternalImeInsets = o.providedInternalImeInsets;
if (!Arrays.equals(providedInsets, o.providedInsets)) {
providedInsets = o.providedInsets;
changes |= LAYOUT_CHANGED;
}
@@ -4675,28 +4607,12 @@ public interface WindowManager extends ViewManager {
sb.append(System.lineSeparator());
sb.append(prefix).append(" fitIgnoreVis");
}
if (providesInsetsTypes != null) {
if (providedInsets != null) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" insetsTypes=");
for (int i = 0; i < providesInsetsTypes.length; ++i) {
sb.append(" providedInsets=");
for (int i = 0; i < providedInsets.length; ++i) {
if (i > 0) sb.append(' ');
sb.append(InsetsState.typeToString(providesInsetsTypes[i]));
}
}
if (providedInternalInsets != null) {
sb.append(System.lineSeparator());
sb.append(" providedInternalInsets=");
for (int i = 0; i < providedInternalInsets.length; ++i) {
if (i > 0) sb.append(' ');
sb.append((providedInternalInsets[i]));
}
}
if (providedInternalImeInsets != null) {
sb.append(System.lineSeparator());
sb.append(" providedInternalImeInsets=");
for (int i = 0; i < providedInternalImeInsets.length; ++i) {
if (i > 0) sb.append(' ');
sb.append((providedInternalImeInsets[i]));
sb.append((providedInsets[i]));
}
}
if (insetsRoundedCornerFrame) {

View File

@@ -28,6 +28,7 @@ import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.InsetsController;
import android.view.InsetsFrameProvider;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -105,7 +106,11 @@ public class WindowManagerWrapper {
*/
public void setProvidesInsetsTypes(WindowManager.LayoutParams params,
int[] providesInsetsTypes) {
params.providesInsetsTypes = providesInsetsTypes;
final int length = providesInsetsTypes.length;
params.providedInsets = new InsetsFrameProvider[length];
for (int i = 0; i < length; i++) {
params.providedInsets[i] = new InsetsFrameProvider(providesInsetsTypes[i]);
}
}
/**

View File

@@ -80,7 +80,7 @@ import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.InsetsState;
import android.view.InsetsFrameProvider;
import android.view.InsetsState.InternalInsetsType;
import android.view.InsetsVisibilities;
import android.view.KeyEvent;
@@ -1631,12 +1631,14 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
lp.gravity = gravity;
lp.providedInternalInsets = new Insets[InsetsState.SIZE];
if (insetsHeight != -1) {
lp.providedInternalInsets[ITYPE_NAVIGATION_BAR] =
Insets.of(0, height - insetsHeight, 0, 0);
lp.providedInsets = new InsetsFrameProvider[] {
new InsetsFrameProvider(ITYPE_NAVIGATION_BAR, Insets.of(0, 0, 0, insetsHeight))
};
} else {
lp.providedInternalInsets[ITYPE_NAVIGATION_BAR] = null;
lp.providedInsets = new InsetsFrameProvider[] {
new InsetsFrameProvider(ITYPE_NAVIGATION_BAR)
};
}
lp.token = new Binder();
lp.accessibilityTitle = userContext.getString(R.string.nav_bar);

View File

@@ -120,6 +120,7 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsFlags;
import android.view.InsetsFrameProvider;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
@@ -1078,17 +1079,18 @@ public class DisplayPolicy {
return WindowManagerGlobal.ADD_INVALID_TYPE;
}
if (attrs.providesInsetsTypes != null) {
if (attrs.providedInsets != null) {
// Recents component is allowed to add inset types.
if (!mService.mAtmService.isCallerRecents(callingUid)) {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
}
enforceSingleInsetsTypeCorrespondingToWindowType(attrs.providesInsetsTypes);
enforceSingleInsetsTypeCorrespondingToWindowType(attrs.providedInsets);
for (@InternalInsetsType int insetType : attrs.providesInsetsTypes) {
switch (insetType) {
for (InsetsFrameProvider provider : attrs.providedInsets) {
@InternalInsetsType int insetsType = provider.type;
switch (insetsType) {
case ITYPE_STATUS_BAR:
if ((mStatusBar != null && mStatusBar.isAlive())
|| (mStatusBarAlt != null && mStatusBarAlt.isAlive())) {
@@ -1154,12 +1156,19 @@ public class DisplayPolicy {
mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
(displayFrames, windowContainer, inOutFrame) -> {
if (!mNavButtonForcedVisible) {
final Insets[] providedInternalInsets = win.getLayoutingAttrs(
displayFrames.mRotation).providedInternalInsets;
if (providedInternalInsets != null
&& providedInternalInsets.length > ITYPE_NAVIGATION_BAR
&& providedInternalInsets[ITYPE_NAVIGATION_BAR] != null) {
inOutFrame.inset(providedInternalInsets[ITYPE_NAVIGATION_BAR]);
final LayoutParams lp =
win.getLayoutingAttrs(displayFrames.mRotation);
if (lp.providedInsets != null) {
for (InsetsFrameProvider provider :
win.getLayoutingAttrs(displayFrames.mRotation)
.providedInsets) {
if (provider.type != ITYPE_NAVIGATION_BAR) {
continue;
}
calculateInsetsFrame(displayFrames, win, inOutFrame,
provider.source, provider.insetsSize
);
}
}
inOutFrame.inset(win.mGivenContentInsets);
}
@@ -1203,21 +1212,9 @@ public class DisplayPolicy {
if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
break;
default:
if (attrs.providesInsetsTypes != null) {
for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
final TriConsumer<DisplayFrames, WindowContainer, Rect> imeFrameProvider =
win.getAttrs().providedInternalImeInsets != null
? (displayFrames, windowContainer, inOutFrame) -> {
final Insets[] providedInternalImeInsets =
win.getLayoutingAttrs(displayFrames.mRotation)
.providedInternalImeInsets;
if (providedInternalImeInsets != null
&& providedInternalImeInsets.length > insetsType
&& providedInternalImeInsets[insetsType] != null) {
inOutFrame.inset(providedInternalImeInsets[insetsType]);
}
} : null;
switch (insetsType) {
if (attrs.providedInsets != null) {
for (InsetsFrameProvider provider : attrs.providedInsets) {
switch (provider.type) {
case ITYPE_STATUS_BAR:
mStatusBarAlt = win;
mStatusBarAltPosition = getAltBarPosition(attrs);
@@ -1235,18 +1232,24 @@ public class DisplayPolicy {
mExtraNavBarAltPosition = getAltBarPosition(attrs);
break;
}
mDisplayContent.setInsetProvider(insetsType, win,
win.getAttrs().providedInternalInsets != null ? (displayFrames,
windowContainer, inOutFrame) -> {
final Insets[] providedInternalInsets = win.getLayoutingAttrs(
displayFrames.mRotation).providedInternalInsets;
if (providedInternalInsets != null
&& providedInternalInsets.length > insetsType
&& providedInternalInsets[insetsType] != null) {
inOutFrame.inset(providedInternalInsets[insetsType]);
}
inOutFrame.inset(win.mGivenContentInsets);
} : null, imeFrameProvider);
final TriConsumer<DisplayFrames, WindowContainer, Rect> frameProvider =
provider.insetsSize != null
? (displayFrames, windowContainer, inOutFrame) -> {
inOutFrame.inset(win.mGivenContentInsets);
calculateInsetsFrame(displayFrames, windowContainer,
inOutFrame, provider.source,
provider.insetsSize);
} : null;
final TriConsumer<DisplayFrames, WindowContainer, Rect> imeFrameProvider =
provider.imeInsetsSize != null
? (displayFrames, windowContainer, inOutFrame) -> {
inOutFrame.inset(win.mGivenContentInsets);
calculateInsetsFrame(displayFrames, windowContainer,
inOutFrame, provider.source,
provider.imeInsetsSize);
} : null;
mDisplayContent.setInsetProvider(provider.type, win, frameProvider,
imeFrameProvider);
mInsetsSourceWindowsExceptIme.add(win);
}
}
@@ -1254,6 +1257,29 @@ public class DisplayPolicy {
}
}
private void calculateInsetsFrame(DisplayFrames df, WindowContainer coutainer, Rect inOutFrame,
int source, Insets insetsSize) {
if (source == InsetsFrameProvider.SOURCE_DISPLAY) {
inOutFrame.set(df.mUnrestricted);
} else if (source == InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS) {
inOutFrame.set(coutainer.getBounds());
}
if (insetsSize == null || insetsSize.equals(Insets.NONE)) {
return;
}
// Only one side of the provider shall be applied. Check in the order of left - top -
// right - bottom, only the first non-zero value will be applied.
if (insetsSize.left != 0) {
inOutFrame.right = inOutFrame.left + insetsSize.left;
} else if (insetsSize.top != 0) {
inOutFrame.bottom = inOutFrame.top + insetsSize.top;
} else if (insetsSize.right != 0) {
inOutFrame.left = inOutFrame.right - insetsSize.right;
} else if (insetsSize.bottom != 0) {
inOutFrame.top = inOutFrame.bottom - insetsSize.bottom;
}
}
@WindowManagerPolicy.AltBarPosition
private int getAltBarPosition(WindowManager.LayoutParams params) {
switch (params.gravity) {
@@ -1292,10 +1318,11 @@ public class DisplayPolicy {
};
}
private static void enforceSingleInsetsTypeCorrespondingToWindowType(int[] insetsTypes) {
private static void enforceSingleInsetsTypeCorrespondingToWindowType(
InsetsFrameProvider[] providers) {
int count = 0;
for (int insetsType : insetsTypes) {
switch (insetsType) {
for (InsetsFrameProvider provider : providers) {
switch (provider.type) {
case ITYPE_NAVIGATION_BAR:
case ITYPE_STATUS_BAR:
case ITYPE_CLIMATE_BAR:
@@ -1954,25 +1981,20 @@ public class DisplayPolicy {
&& lp.paramsForRotation[rotation] != null) {
lp = lp.paramsForRotation[rotation];
}
final Insets providedInternalInsets;
if (lp.providedInternalInsets != null
&& lp.providedInternalInsets.length > ITYPE_NAVIGATION_BAR
&& lp.providedInternalInsets[ITYPE_NAVIGATION_BAR] != null) {
providedInternalInsets = lp.providedInternalInsets[ITYPE_NAVIGATION_BAR];
} else {
providedInternalInsets = Insets.NONE;
}
if (position == NAV_BAR_LEFT) {
if (lp.width > providedInternalInsets.right) {
return lp.width - providedInternalInsets.right;
} else {
return 0;
Insets providedInsetsSize = null;
if (lp.providedInsets != null) {
for (InsetsFrameProvider provider : lp.providedInsets) {
if (provider.type != ITYPE_NAVIGATION_BAR) {
continue;
}
providedInsetsSize = provider.insetsSize;
}
} else if (position == NAV_BAR_RIGHT) {
if (lp.width > providedInternalInsets.left) {
return lp.width - providedInternalInsets.left;
} else {
return 0;
}
if (providedInsetsSize != null) {
if (position == NAV_BAR_LEFT) {
return providedInsetsSize.left;
} else if (position == NAV_BAR_RIGHT) {
return providedInsetsSize.right;
}
}
return lp.width;
@@ -2019,18 +2041,20 @@ public class DisplayPolicy {
return 0;
}
LayoutParams lp = mNavigationBar.getLayoutingAttrs(rotation);
final Insets providedInternalInsets;
if (lp.providedInternalInsets != null
&& lp.providedInternalInsets.length > ITYPE_NAVIGATION_BAR
&& lp.providedInternalInsets[ITYPE_NAVIGATION_BAR] != null) {
providedInternalInsets = lp.providedInternalInsets[ITYPE_NAVIGATION_BAR];
} else {
providedInternalInsets = Insets.NONE;
Insets providedInsetsSize = null;
if (lp.providedInsets != null) {
for (InsetsFrameProvider provider : lp.providedInsets) {
if (provider.type != ITYPE_NAVIGATION_BAR) {
continue;
}
providedInsetsSize = provider.insetsSize;
if (providedInsetsSize != null) {
return providedInsetsSize.bottom;
}
break;
}
}
if (lp.height < providedInternalInsets.top) {
return 0;
}
return lp.height - providedInternalInsets.top;
return lp.height;
}
/**

View File

@@ -55,6 +55,7 @@ import android.view.InsetsAnimationControlCallbacks;
import android.view.InsetsAnimationControlImpl;
import android.view.InsetsAnimationControlRunner;
import android.view.InsetsController;
import android.view.InsetsFrameProvider;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
@@ -322,14 +323,14 @@ class InsetsPolicy {
}
// If not one of the types above, check whether an internal inset mapping is specified.
if (attrs.providesInsetsTypes != null) {
for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
switch (insetsType) {
if (attrs.providedInsets != null) {
for (InsetsFrameProvider provider : attrs.providedInsets) {
switch (provider.type) {
case ITYPE_STATUS_BAR:
case ITYPE_NAVIGATION_BAR:
case ITYPE_CLIMATE_BAR:
case ITYPE_EXTRA_NAVIGATION_BAR:
return insetsType;
return provider.type;
}
}
}

View File

@@ -42,6 +42,7 @@ import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsFrameProvider;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
@@ -513,12 +514,13 @@ abstract class InsetsSourceProvider {
if (mWindowContainer.asWindowState() == null) {
return false;
}
final int[] provides = ((WindowState) mWindowContainer).mAttrs.providesInsetsTypes;
if (provides == null) {
final InsetsFrameProvider[] providers =
((WindowState) mWindowContainer).mAttrs.providedInsets;
if (providers == null) {
return false;
}
for (int i = 0; i < provides.length; i++) {
if (provides[i] == ITYPE_IME) {
for (int i = 0; i < providers.length; i++) {
if (providers[i].type == ITYPE_IME) {
return true;
}
}

View File

@@ -2247,9 +2247,21 @@ public class WindowManagerService extends IWindowManager.Stub
throw new IllegalArgumentException(
"Window type can not be changed after the window is added.");
}
if (!Arrays.equals(win.mAttrs.providesInsetsTypes, attrs.providesInsetsTypes)) {
throw new IllegalArgumentException(
"Insets types can not be changed after the window is added.");
if (!(win.mAttrs.providedInsets == null && attrs.providedInsets == null)) {
if (win.mAttrs.providedInsets == null || attrs.providedInsets == null
|| (win.mAttrs.providedInsets.length != attrs.providedInsets.length)) {
throw new IllegalArgumentException(
"Insets types can not be changed after the window is added.");
} else {
final int insetsTypes = attrs.providedInsets.length;
for (int i = 0; i < insetsTypes; i++) {
if (win.mAttrs.providedInsets[i].type != attrs.providedInsets[i].type) {
throw new IllegalArgumentException(
"Insets types can not be changed after the window is "
+ "added.");
}
}
}
}
flagChanges = win.mAttrs.flags ^ attrs.flags;

View File

@@ -43,6 +43,7 @@ import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
import android.view.DisplayInfo;
import android.view.InsetsFrameProvider;
import android.view.InsetsState;
import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
@@ -153,7 +154,10 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mDisplayPolicy.removeWindowLw(mStatusBarWindow); // Removes the existing one.
WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel");
win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
win.mAttrs.providedInsets = new InsetsFrameProvider[] {
new InsetsFrameProvider(ITYPE_STATUS_BAR),
new InsetsFrameProvider(ITYPE_TOP_GESTURES)
};
win.getFrame().set(0, 0, 500, 100);
addWindow(win);
@@ -182,7 +186,9 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
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};
win.mAttrs.providedInsets = new InsetsFrameProvider[] {
new InsetsFrameProvider(ITYPE_STATUS_BAR)
};
win.getFrame().set(0, 0, 500, 100);
addWindow(win);
@@ -199,12 +205,19 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
@Test
public void addingWindow_throwsException_WithMultipleInsetTypes() {
WindowState win1 = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel");
win1.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR};
win1.mAttrs.providedInsets = new InsetsFrameProvider[] {
new InsetsFrameProvider(ITYPE_STATUS_BAR),
new InsetsFrameProvider(ITYPE_NAVIGATION_BAR)
};
expectThrows(IllegalArgumentException.class, () -> addWindow(win1));
WindowState win2 = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel");
win2.mAttrs.providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR, ITYPE_EXTRA_NAVIGATION_BAR};
win2.mAttrs.providedInsets = new InsetsFrameProvider[] {
new InsetsFrameProvider(ITYPE_CLIMATE_BAR),
new InsetsFrameProvider(ITYPE_EXTRA_NAVIGATION_BAR)
};
expectThrows(IllegalArgumentException.class, () -> addWindow(win2));
}