Merge "Only update mAboveInsetsState when necessary" into sc-dev
This commit is contained in:
@@ -20,8 +20,6 @@ import static android.view.InsetsStateProto.DISPLAY_CUTOUT;
|
|||||||
import static android.view.InsetsStateProto.DISPLAY_FRAME;
|
import static android.view.InsetsStateProto.DISPLAY_FRAME;
|
||||||
import static android.view.InsetsStateProto.SOURCES;
|
import static android.view.InsetsStateProto.SOURCES;
|
||||||
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
|
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
|
||||||
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
|
|
||||||
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
|
|
||||||
import static android.view.WindowInsets.Type.displayCutout;
|
import static android.view.WindowInsets.Type.displayCutout;
|
||||||
import static android.view.WindowInsets.Type.ime;
|
import static android.view.WindowInsets.Type.ime;
|
||||||
import static android.view.WindowInsets.Type.indexOf;
|
import static android.view.WindowInsets.Type.indexOf;
|
||||||
@@ -106,14 +104,11 @@ public class InsetsState implements Parcelable {
|
|||||||
public static final int ITYPE_NAVIGATION_BAR = 1;
|
public static final int ITYPE_NAVIGATION_BAR = 1;
|
||||||
public static final int ITYPE_CAPTION_BAR = 2;
|
public static final int ITYPE_CAPTION_BAR = 2;
|
||||||
|
|
||||||
// The always visible types are visible to all windows regardless of the z-order.
|
public static final int ITYPE_TOP_GESTURES = 3;
|
||||||
public static final int FIRST_ALWAYS_VISIBLE_TYPE = 3;
|
|
||||||
public static final int ITYPE_TOP_GESTURES = FIRST_ALWAYS_VISIBLE_TYPE;
|
|
||||||
public static final int ITYPE_BOTTOM_GESTURES = 4;
|
public static final int ITYPE_BOTTOM_GESTURES = 4;
|
||||||
public static final int ITYPE_LEFT_GESTURES = 5;
|
public static final int ITYPE_LEFT_GESTURES = 5;
|
||||||
public static final int ITYPE_RIGHT_GESTURES = 6;
|
public static final int ITYPE_RIGHT_GESTURES = 6;
|
||||||
|
|
||||||
/** Additional gesture inset types that map into {@link Type.MANDATORY_SYSTEM_GESTURES}. */
|
|
||||||
public static final int ITYPE_TOP_MANDATORY_GESTURES = 7;
|
public static final int ITYPE_TOP_MANDATORY_GESTURES = 7;
|
||||||
public static final int ITYPE_BOTTOM_MANDATORY_GESTURES = 8;
|
public static final int ITYPE_BOTTOM_MANDATORY_GESTURES = 8;
|
||||||
public static final int ITYPE_LEFT_MANDATORY_GESTURES = 9;
|
public static final int ITYPE_LEFT_MANDATORY_GESTURES = 9;
|
||||||
@@ -123,7 +118,6 @@ public class InsetsState implements Parcelable {
|
|||||||
public static final int ITYPE_TOP_DISPLAY_CUTOUT = 12;
|
public static final int ITYPE_TOP_DISPLAY_CUTOUT = 12;
|
||||||
public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 13;
|
public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 13;
|
||||||
public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 14;
|
public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 14;
|
||||||
public static final int LAST_ALWAYS_VISIBLE_TYPE = ITYPE_BOTTOM_DISPLAY_CUTOUT;
|
|
||||||
|
|
||||||
public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = 15;
|
public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = 15;
|
||||||
public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 16;
|
public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 16;
|
||||||
@@ -187,18 +181,6 @@ public class InsetsState implements Parcelable {
|
|||||||
set(copy, copySources);
|
set(copy, copySources);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Mirror the always visible sources from the other state. They will share the same object for
|
|
||||||
* the always visible types.
|
|
||||||
*
|
|
||||||
* @param other the state to mirror the mirrored sources from.
|
|
||||||
*/
|
|
||||||
public void mirrorAlwaysVisibleInsetsSources(InsetsState other) {
|
|
||||||
for (int type = FIRST_ALWAYS_VISIBLE_TYPE; type <= LAST_ALWAYS_VISIBLE_TYPE; type++) {
|
|
||||||
mSources[type] = other.mSources[type];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates {@link WindowInsets} based on the current source configuration.
|
* Calculates {@link WindowInsets} based on the current source configuration.
|
||||||
*
|
*
|
||||||
@@ -380,14 +362,14 @@ public class InsetsState implements Parcelable {
|
|||||||
processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap,
|
processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap,
|
||||||
insets, type);
|
insets, type);
|
||||||
|
|
||||||
if (type == MANDATORY_SYSTEM_GESTURES) {
|
if (type == Type.MANDATORY_SYSTEM_GESTURES) {
|
||||||
// Mandatory system gestures are also system gestures.
|
// Mandatory system gestures are also system gestures.
|
||||||
// TODO: find a way to express this more generally. One option would be to define
|
// TODO: find a way to express this more generally. One option would be to define
|
||||||
// Type.systemGestureInsets() as NORMAL | MANDATORY, but then we lose the
|
// Type.systemGestureInsets() as NORMAL | MANDATORY, but then we lose the
|
||||||
// ability to set systemGestureInsets() independently from
|
// ability to set systemGestureInsets() independently from
|
||||||
// mandatorySystemGestureInsets() in the Builder.
|
// mandatorySystemGestureInsets() in the Builder.
|
||||||
processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap,
|
processSourceAsPublicType(source, typeInsetsMap, typeSideMap, typeVisibilityMap,
|
||||||
insets, SYSTEM_GESTURES);
|
insets, Type.SYSTEM_GESTURES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,9 +475,14 @@ public class InsetsState implements Parcelable {
|
|||||||
* to the client.
|
* to the client.
|
||||||
*
|
*
|
||||||
* @param type The {@link InternalInsetsType} of the source to remove
|
* @param type The {@link InternalInsetsType} of the source to remove
|
||||||
|
* @return {@code true} if this InsetsState was modified; {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
public void removeSource(@InternalInsetsType int type) {
|
public boolean removeSource(@InternalInsetsType int type) {
|
||||||
|
if (mSources[type] == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
mSources[type] = null;
|
mSources[type] = null;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -552,6 +539,24 @@ public class InsetsState implements Parcelable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the values from the other InsetsState. But for sources, only specific types of source
|
||||||
|
* would be set.
|
||||||
|
*
|
||||||
|
* @param other the other InsetsState.
|
||||||
|
* @param types the only types of sources would be set.
|
||||||
|
*/
|
||||||
|
public void set(InsetsState other, @InsetsType int types) {
|
||||||
|
mDisplayFrame.set(other.mDisplayFrame);
|
||||||
|
mDisplayCutout.set(other.mDisplayCutout);
|
||||||
|
mRoundedCorners = other.getRoundedCorners();
|
||||||
|
final ArraySet<Integer> t = toInternalType(types);
|
||||||
|
for (int i = t.size() - 1; i >= 0; i--) {
|
||||||
|
final int type = t.valueAt(i);
|
||||||
|
mSources[type] = other.mSources[type];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addSource(InsetsSource source) {
|
public void addSource(InsetsSource source) {
|
||||||
mSources[source.getType()] = source;
|
mSources[source.getType()] = source;
|
||||||
}
|
}
|
||||||
@@ -575,6 +580,18 @@ public class InsetsState implements Parcelable {
|
|||||||
if ((types & Type.CAPTION_BAR) != 0) {
|
if ((types & Type.CAPTION_BAR) != 0) {
|
||||||
result.add(ITYPE_CAPTION_BAR);
|
result.add(ITYPE_CAPTION_BAR);
|
||||||
}
|
}
|
||||||
|
if ((types & Type.SYSTEM_GESTURES) != 0) {
|
||||||
|
result.add(ITYPE_LEFT_GESTURES);
|
||||||
|
result.add(ITYPE_TOP_GESTURES);
|
||||||
|
result.add(ITYPE_RIGHT_GESTURES);
|
||||||
|
result.add(ITYPE_BOTTOM_GESTURES);
|
||||||
|
}
|
||||||
|
if ((types & Type.MANDATORY_SYSTEM_GESTURES) != 0) {
|
||||||
|
result.add(ITYPE_LEFT_MANDATORY_GESTURES);
|
||||||
|
result.add(ITYPE_TOP_MANDATORY_GESTURES);
|
||||||
|
result.add(ITYPE_RIGHT_MANDATORY_GESTURES);
|
||||||
|
result.add(ITYPE_BOTTOM_MANDATORY_GESTURES);
|
||||||
|
}
|
||||||
if ((types & Type.DISPLAY_CUTOUT) != 0) {
|
if ((types & Type.DISPLAY_CUTOUT) != 0) {
|
||||||
result.add(ITYPE_LEFT_DISPLAY_CUTOUT);
|
result.add(ITYPE_LEFT_DISPLAY_CUTOUT);
|
||||||
result.add(ITYPE_TOP_DISPLAY_CUTOUT);
|
result.add(ITYPE_TOP_DISPLAY_CUTOUT);
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ public class RoundedCorners implements Parcelable {
|
|||||||
}
|
}
|
||||||
if (o instanceof RoundedCorners) {
|
if (o instanceof RoundedCorners) {
|
||||||
RoundedCorners r = (RoundedCorners) o;
|
RoundedCorners r = (RoundedCorners) o;
|
||||||
return Arrays.deepEquals(mRoundedCorners, ((RoundedCorners) o).mRoundedCorners);
|
return Arrays.deepEquals(mRoundedCorners, r.mRoundedCorners);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -673,10 +673,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
// Used in updating override configurations
|
// Used in updating override configurations
|
||||||
private final Configuration mTempConfig = new Configuration();
|
private final Configuration mTempConfig = new Configuration();
|
||||||
|
|
||||||
// Used in performing layout, to record the insets provided by other windows above the current
|
|
||||||
// window.
|
|
||||||
private InsetsState mTmpAboveInsetsState = new InsetsState();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to prevent recursions when calling
|
* Used to prevent recursions when calling
|
||||||
* {@link #ensureActivitiesVisible(ActivityRecord, int, boolean, boolean)}
|
* {@link #ensureActivitiesVisible(ActivityRecord, int, boolean, boolean)}
|
||||||
@@ -778,13 +774,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
+ " parentHidden=" + w.isParentWindowHidden());
|
+ " parentHidden=" + w.isParentWindowHidden());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets mAboveInsets for each window. Windows behind the window providing the insets can
|
|
||||||
// receive the insets.
|
|
||||||
if (!w.mAboveInsetsState.equals(mTmpAboveInsetsState)) {
|
|
||||||
w.mAboveInsetsState.set(mTmpAboveInsetsState);
|
|
||||||
mWinInsetsChanged.add(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this view is GONE, then skip it -- keep the current frame, and let the caller know
|
// If this view is GONE, then skip it -- keep the current frame, and let the caller know
|
||||||
// so they can ignore it if they want. (We do the normal layout for INVISIBLE windows,
|
// so they can ignore it if they want. (We do the normal layout for INVISIBLE windows,
|
||||||
// since that means "perform layout as normal, just don't display").
|
// since that means "perform layout as normal, just don't display").
|
||||||
@@ -818,16 +807,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
+ " mContainingFrame=" + w.getContainingFrame()
|
+ " mContainingFrame=" + w.getContainingFrame()
|
||||||
+ " mDisplayFrame=" + w.getDisplayFrame());
|
+ " mDisplayFrame=" + w.getDisplayFrame());
|
||||||
}
|
}
|
||||||
provideInsetsByWindow(w);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private void provideInsetsByWindow(WindowState w) {
|
|
||||||
for (int i = 0; i < w.mProvidedInsetsSources.size(); i++) {
|
|
||||||
final InsetsSource providedSource = w.mProvidedInsetsSources.valueAt(i);
|
|
||||||
mTmpAboveInsetsState.addSource(providedSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Consumer<WindowState> mPerformLayoutAttached = w -> {
|
private final Consumer<WindowState> mPerformLayoutAttached = w -> {
|
||||||
if (w.mLayoutAttached) {
|
if (w.mLayoutAttached) {
|
||||||
if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame
|
if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame
|
||||||
@@ -2511,8 +2492,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
|
|
||||||
void onDisplayInfoChanged() {
|
void onDisplayInfoChanged() {
|
||||||
final DisplayInfo info = mDisplayInfo;
|
final DisplayInfo info = mDisplayInfo;
|
||||||
mDisplayFrames.onDisplayInfoUpdated(info, calculateDisplayCutoutForRotation(info.rotation),
|
if (mDisplayFrames.onDisplayInfoUpdated(info,
|
||||||
calculateRoundedCornersForRotation(info.rotation));
|
calculateDisplayCutoutForRotation(info.rotation),
|
||||||
|
calculateRoundedCornersForRotation(info.rotation))) {
|
||||||
|
// TODO(b/161810301): Set notifyInsetsChange to true while the server no longer performs
|
||||||
|
// layout.
|
||||||
|
mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChange */);
|
||||||
|
}
|
||||||
mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight);
|
mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight);
|
||||||
mDisplayPolicy.onDisplayInfoChanged(info);
|
mDisplayPolicy.onDisplayInfoChanged(info);
|
||||||
}
|
}
|
||||||
@@ -3767,8 +3753,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
// 2. Assign window layers based on the IME surface parent to make sure it is on top of the
|
// 2. Assign window layers based on the IME surface parent to make sure it is on top of the
|
||||||
// app.
|
// app.
|
||||||
assignWindowLayers(true /* setLayoutNeeded */);
|
assignWindowLayers(true /* setLayoutNeeded */);
|
||||||
// 3. Update the IME control target to apply any inset change and animation.
|
// 3. The z-order of IME might have been changed. Update the above insets state.
|
||||||
// 4. Reparent the IME container surface to either the input target app, or the IME window
|
mInsetsStateController.updateAboveInsetsState(
|
||||||
|
mInputMethodWindow, true /* notifyInsetsChange */);
|
||||||
|
// 4. Update the IME control target to apply any inset change and animation.
|
||||||
|
// 5. Reparent the IME container surface to either the input target app, or the IME window
|
||||||
// parent.
|
// parent.
|
||||||
updateImeControlTarget();
|
updateImeControlTarget();
|
||||||
}
|
}
|
||||||
@@ -4341,14 +4330,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
+ " dh=" + mDisplayInfo.logicalHeight);
|
+ " dh=" + mDisplayInfo.logicalHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to indicate that we have processed the insets windows. This needs to be after
|
|
||||||
// beginLayoutLw to ensure the raw insets state display related info is initialized.
|
|
||||||
final InsetsState rawInsetsState = getInsetsStateController().getRawInsetsState();
|
|
||||||
mTmpAboveInsetsState = new InsetsState();
|
|
||||||
mTmpAboveInsetsState.setDisplayFrame(rawInsetsState.getDisplayFrame());
|
|
||||||
mTmpAboveInsetsState.setDisplayCutout(rawInsetsState.getDisplayCutout());
|
|
||||||
mTmpAboveInsetsState.mirrorAlwaysVisibleInsetsSources(rawInsetsState);
|
|
||||||
|
|
||||||
int seq = mLayoutSeq + 1;
|
int seq = mLayoutSeq + 1;
|
||||||
if (seq < 0) seq = 0;
|
if (seq < 0) seq = 0;
|
||||||
mLayoutSeq = seq;
|
mLayoutSeq = seq;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
|
|||||||
import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
|
import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
|
||||||
import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
|
import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.util.proto.ProtoOutputStream;
|
import android.util.proto.ProtoOutputStream;
|
||||||
import android.view.DisplayCutout;
|
import android.view.DisplayCutout;
|
||||||
@@ -70,25 +71,28 @@ public class DisplayFrames {
|
|||||||
* @param info the updated {@link DisplayInfo}.
|
* @param info the updated {@link DisplayInfo}.
|
||||||
* @param displayCutout the updated {@link DisplayCutout}.
|
* @param displayCutout the updated {@link DisplayCutout}.
|
||||||
* @param roundedCorners the updated {@link RoundedCorners}.
|
* @param roundedCorners the updated {@link RoundedCorners}.
|
||||||
|
* @return {@code true} if the insets state has been changed; {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
public void onDisplayInfoUpdated(DisplayInfo info, WmDisplayCutout displayCutout,
|
public boolean onDisplayInfoUpdated(DisplayInfo info, @NonNull WmDisplayCutout displayCutout,
|
||||||
RoundedCorners roundedCorners) {
|
@NonNull RoundedCorners roundedCorners) {
|
||||||
mDisplayWidth = info.logicalWidth;
|
|
||||||
mDisplayHeight = info.logicalHeight;
|
|
||||||
mRotation = info.rotation;
|
mRotation = info.rotation;
|
||||||
final WmDisplayCutout wmDisplayCutout =
|
|
||||||
displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT;
|
|
||||||
|
|
||||||
final InsetsState state = mInsetsState;
|
final InsetsState state = mInsetsState;
|
||||||
final Rect unrestricted = mUnrestricted;
|
|
||||||
final Rect safe = mDisplayCutoutSafe;
|
final Rect safe = mDisplayCutoutSafe;
|
||||||
final DisplayCutout cutout = wmDisplayCutout.getDisplayCutout();
|
final DisplayCutout cutout = displayCutout.getDisplayCutout();
|
||||||
|
if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
|
||||||
|
&& state.getDisplayCutout().equals(cutout)
|
||||||
|
&& state.getRoundedCorners().equals(roundedCorners)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mDisplayWidth = info.logicalWidth;
|
||||||
|
mDisplayHeight = info.logicalHeight;
|
||||||
|
final Rect unrestricted = mUnrestricted;
|
||||||
unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
|
unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
|
||||||
safe.set(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
safe.set(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||||
state.setDisplayFrame(unrestricted);
|
state.setDisplayFrame(unrestricted);
|
||||||
state.setDisplayCutout(cutout);
|
state.setDisplayCutout(cutout);
|
||||||
state.setRoundedCorners(roundedCorners != null ? roundedCorners
|
state.setRoundedCorners(roundedCorners);
|
||||||
: RoundedCorners.NO_ROUNDED_CORNERS);
|
|
||||||
if (!cutout.isEmpty()) {
|
if (!cutout.isEmpty()) {
|
||||||
if (cutout.getSafeInsetLeft() > 0) {
|
if (cutout.getSafeInsetLeft() > 0) {
|
||||||
safe.left = unrestricted.left + cutout.getSafeInsetLeft();
|
safe.left = unrestricted.left + cutout.getSafeInsetLeft();
|
||||||
@@ -116,6 +120,7 @@ public class DisplayFrames {
|
|||||||
state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT);
|
state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT);
|
||||||
state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT);
|
state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
|
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ import static android.view.InsetsState.ITYPE_IME;
|
|||||||
import static android.view.InsetsState.ITYPE_INVALID;
|
import static android.view.InsetsState.ITYPE_INVALID;
|
||||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||||
import static android.view.InsetsState.ITYPE_STATUS_BAR;
|
import static android.view.InsetsState.ITYPE_STATUS_BAR;
|
||||||
|
import static android.view.WindowInsets.Type.displayCutout;
|
||||||
|
import static android.view.WindowInsets.Type.mandatorySystemGestures;
|
||||||
|
import static android.view.WindowInsets.Type.systemGestures;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
|
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
|
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
|
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
|
||||||
@@ -293,6 +296,76 @@ class InsetsStateController {
|
|||||||
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
|
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates {@link WindowState#mAboveInsetsState} for all windows in the display while the
|
||||||
|
* z-order of a window is changed.
|
||||||
|
*
|
||||||
|
* @param win The window whose z-order has changed.
|
||||||
|
* @param notifyInsetsChange {@code true} if the clients should be notified about the change.
|
||||||
|
*/
|
||||||
|
void updateAboveInsetsState(WindowState win, boolean notifyInsetsChange) {
|
||||||
|
if (win == null || win.getDisplayContent() != mDisplayContent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final boolean[] aboveWin = { true };
|
||||||
|
final InsetsState aboveInsetsState = new InsetsState();
|
||||||
|
aboveInsetsState.set(mState,
|
||||||
|
displayCutout() | systemGestures() | mandatorySystemGestures());
|
||||||
|
final SparseArray<InsetsSource> winProvidedSources = win.mProvidedInsetsSources;
|
||||||
|
final ArrayList<WindowState> insetsChangedWindows = new ArrayList<>();
|
||||||
|
mDisplayContent.forAllWindows(w -> {
|
||||||
|
if (aboveWin[0]) {
|
||||||
|
if (w == win) {
|
||||||
|
aboveWin[0] = false;
|
||||||
|
if (!win.mAboveInsetsState.equals(aboveInsetsState)) {
|
||||||
|
win.mAboveInsetsState.set(aboveInsetsState);
|
||||||
|
insetsChangedWindows.add(win);
|
||||||
|
}
|
||||||
|
return winProvidedSources.size() == 0;
|
||||||
|
} else {
|
||||||
|
final SparseArray<InsetsSource> providedSources = w.mProvidedInsetsSources;
|
||||||
|
for (int i = providedSources.size() - 1; i >= 0; i--) {
|
||||||
|
aboveInsetsState.addSource(providedSources.valueAt(i));
|
||||||
|
}
|
||||||
|
if (winProvidedSources.size() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean changed = false;
|
||||||
|
for (int i = winProvidedSources.size() - 1; i >= 0; i--) {
|
||||||
|
changed |= w.mAboveInsetsState.removeSource(winProvidedSources.keyAt(i));
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
insetsChangedWindows.add(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = winProvidedSources.size() - 1; i >= 0; i--) {
|
||||||
|
w.mAboveInsetsState.addSource(winProvidedSources.valueAt(i));
|
||||||
|
}
|
||||||
|
insetsChangedWindows.add(w);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}, true /* traverseTopToBottom */);
|
||||||
|
if (notifyInsetsChange) {
|
||||||
|
for (int i = insetsChangedWindows.size() - 1; i >= 0; i--) {
|
||||||
|
mDispatchInsetsChanged.accept(insetsChangedWindows.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDisplayInfoUpdated(boolean notifyInsetsChange) {
|
||||||
|
final ArrayList<WindowState> insetsChangedWindows = new ArrayList<>();
|
||||||
|
mDisplayContent.forAllWindows(w -> {
|
||||||
|
w.mAboveInsetsState.set(mState, displayCutout());
|
||||||
|
insetsChangedWindows.add(w);
|
||||||
|
}, true /* traverseTopToBottom */);
|
||||||
|
if (notifyInsetsChange) {
|
||||||
|
for (int i = insetsChangedWindows.size() - 1; i >= 0; i--) {
|
||||||
|
mDispatchInsetsChanged.accept(insetsChangedWindows.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void onInsetsModified(InsetsControlTarget caller) {
|
void onInsetsModified(InsetsControlTarget caller) {
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (int i = mProviders.size() - 1; i >= 0; i--) {
|
for (int i = mProviders.size() - 1; i >= 0; i--) {
|
||||||
|
|||||||
@@ -1881,6 +1881,10 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
displayContent.sendNewConfiguration();
|
displayContent.sendNewConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This window doesn't have a frame yet. Don't let this window cause the insets change.
|
||||||
|
displayContent.getInsetsStateController().updateAboveInsetsState(
|
||||||
|
win, false /* notifyInsetsChanged */);
|
||||||
|
|
||||||
getInsetsSourceControls(win, outActiveControls);
|
getInsetsSourceControls(win, outActiveControls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -211,11 +211,11 @@ import android.os.Trace;
|
|||||||
import android.os.WorkSource;
|
import android.os.WorkSource;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.MergedConfiguration;
|
import android.util.MergedConfiguration;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
import android.util.SparseArray;
|
||||||
import android.util.TimeUtils;
|
import android.util.TimeUtils;
|
||||||
import android.util.proto.ProtoOutputStream;
|
import android.util.proto.ProtoOutputStream;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
@@ -651,12 +651,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
|||||||
/**
|
/**
|
||||||
* The insets state of sources provided by windows above the current window.
|
* The insets state of sources provided by windows above the current window.
|
||||||
*/
|
*/
|
||||||
InsetsState mAboveInsetsState = new InsetsState();
|
final InsetsState mAboveInsetsState = new InsetsState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The insets sources provided by this window.
|
* The insets sources provided by this window.
|
||||||
*/
|
*/
|
||||||
ArrayMap<Integer, InsetsSource> mProvidedInsetsSources = new ArrayMap<>();
|
final SparseArray<InsetsSource> mProvidedInsetsSources = new SparseArray<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Surface insets from the previous call to relayout(), used to track
|
* Surface insets from the previous call to relayout(), used to track
|
||||||
@@ -2202,7 +2202,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void removeImmediately() {
|
void removeImmediately() {
|
||||||
super.removeImmediately();
|
super.removeImmediately();
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
|
|||||||
// insets state with the global one.
|
// insets state with the global one.
|
||||||
final InsetsState insetsState =
|
final InsetsState insetsState =
|
||||||
win.getDisplayContent().getInsetsStateController().getRawInsetsState();
|
win.getDisplayContent().getInsetsStateController().getRawInsetsState();
|
||||||
win.mAboveInsetsState = insetsState;
|
win.mAboveInsetsState.set(insetsState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRotation(int rotation, boolean includingWindows) {
|
public void setRotation(int rotation, boolean includingWindows) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.server.wm;
|
|||||||
|
|
||||||
import static android.view.InsetsState.ITYPE_IME;
|
import static android.view.InsetsState.ITYPE_IME;
|
||||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||||
|
import static android.view.RoundedCorners.NO_ROUNDED_CORNERS;
|
||||||
import static android.view.Surface.ROTATION_0;
|
import static android.view.Surface.ROTATION_0;
|
||||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
@@ -37,6 +38,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
|
|||||||
|
|
||||||
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
|
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
|
||||||
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
|
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
|
||||||
|
import static com.android.server.wm.utils.WmDisplayCutout.NO_CUTOUT;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@@ -300,9 +302,9 @@ public class DisplayPolicyTests extends WindowTestsBase {
|
|||||||
displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
|
displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
|
||||||
mNavBarWindow.getControllableInsetProvider().setServerVisible(true);
|
mNavBarWindow.getControllableInsetProvider().setServerVisible(true);
|
||||||
final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
|
final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
|
||||||
mImeWindow.mAboveInsetsState = state;
|
mImeWindow.mAboveInsetsState.set(state);
|
||||||
mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(),
|
mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(),
|
||||||
state, displayInfo, null /* displayCutout */, null /* roundedCorners*/);
|
state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS);
|
||||||
|
|
||||||
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
|
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
|
||||||
mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
|
mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
|
|||||||
static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
|
static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
|
||||||
boolean withDisplayCutout, boolean isLongEdgeCutout) {
|
boolean withDisplayCutout, boolean isLongEdgeCutout) {
|
||||||
final DisplayInfo info = new DisplayInfo();
|
final DisplayInfo info = new DisplayInfo();
|
||||||
WmDisplayCutout cutout = null;
|
WmDisplayCutout cutout = WmDisplayCutout.NO_CUTOUT;
|
||||||
|
|
||||||
final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
|
final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
|
||||||
info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
|
info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
|
||||||
|
|||||||
@@ -32,13 +32,14 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
|||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||||
import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT;
|
import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT;
|
||||||
|
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Mockito.atLeast;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.clearInvocations;
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@@ -208,7 +209,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
|
|||||||
app.mAboveInsetsState.getSource(ITYPE_IME).setFrame(mImeWindow.getFrame());
|
app.mAboveInsetsState.getSource(ITYPE_IME).setFrame(mImeWindow.getFrame());
|
||||||
|
|
||||||
// Make sure app got notified.
|
// Make sure app got notified.
|
||||||
verify(app, atLeast(1)).notifyInsetsChanged();
|
verify(app, atLeastOnce()).notifyInsetsChanged();
|
||||||
|
|
||||||
// app will get visible IME insets while below IME.
|
// app will get visible IME insets while below IME.
|
||||||
assertTrue(getController().getInsetsForWindow(app).getSource(ITYPE_IME).isVisible());
|
assertTrue(getController().getInsetsForWindow(app).getSource(ITYPE_IME).isVisible());
|
||||||
@@ -336,6 +337,92 @@ public class InsetsStateControllerTest extends WindowTestsBase {
|
|||||||
assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
|
assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAboveInsetsState_provideInsets() {
|
||||||
|
final WindowState app = createTestWindow("app");
|
||||||
|
final WindowState statusBar = createTestWindow("statusBar");
|
||||||
|
final WindowState navBar = createTestWindow("navBar");
|
||||||
|
|
||||||
|
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
|
||||||
|
|
||||||
|
assertNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
assertNull(statusBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
assertNull(navBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
|
||||||
|
getController().updateAboveInsetsState(statusBar, true /* notifyInsetsChange */);
|
||||||
|
|
||||||
|
assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
assertNull(statusBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
assertNull(navBar.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
|
||||||
|
verify(app, atLeastOnce()).notifyInsetsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAboveInsetsState_receiveInsets() {
|
||||||
|
final WindowState app = createTestWindow("app");
|
||||||
|
final WindowState statusBar = createTestWindow("statusBar");
|
||||||
|
final WindowState navBar = createTestWindow("navBar");
|
||||||
|
|
||||||
|
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
|
||||||
|
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
|
||||||
|
|
||||||
|
assertNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
assertNull(app.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR));
|
||||||
|
|
||||||
|
getController().updateAboveInsetsState(app, true /* notifyInsetsChange */);
|
||||||
|
|
||||||
|
assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR));
|
||||||
|
|
||||||
|
verify(app, atLeastOnce()).notifyInsetsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAboveInsetsState_zOrderChanged() {
|
||||||
|
final WindowState ime = createTestWindow("ime");
|
||||||
|
final WindowState app = createTestWindow("app");
|
||||||
|
final WindowState statusBar = createTestWindow("statusBar");
|
||||||
|
final WindowState navBar = createTestWindow("navBar");
|
||||||
|
|
||||||
|
getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
|
||||||
|
getController().getSourceProvider(ITYPE_IME).setClientVisible(true);
|
||||||
|
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
|
||||||
|
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
|
||||||
|
getController().updateAboveInsetsState(ime, false /* notifyInsetsChange */);
|
||||||
|
getController().updateAboveInsetsState(statusBar, false /* notifyInsetsChange */);
|
||||||
|
getController().updateAboveInsetsState(navBar, false /* notifyInsetsChange */);
|
||||||
|
|
||||||
|
// ime is below others.
|
||||||
|
assertNull(app.mAboveInsetsState.peekSource(ITYPE_IME));
|
||||||
|
assertNull(statusBar.mAboveInsetsState.peekSource(ITYPE_IME));
|
||||||
|
assertNull(navBar.mAboveInsetsState.peekSource(ITYPE_IME));
|
||||||
|
assertNotNull(ime.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
assertNotNull(ime.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR));
|
||||||
|
|
||||||
|
ime.getParent().positionChildAt(POSITION_TOP, ime, true /* includingParents */);
|
||||||
|
getController().updateAboveInsetsState(ime, true /* notifyInsetsChange */);
|
||||||
|
|
||||||
|
// ime is above others.
|
||||||
|
assertNotNull(app.mAboveInsetsState.peekSource(ITYPE_IME));
|
||||||
|
assertNotNull(statusBar.mAboveInsetsState.peekSource(ITYPE_IME));
|
||||||
|
assertNotNull(navBar.mAboveInsetsState.peekSource(ITYPE_IME));
|
||||||
|
assertNull(ime.mAboveInsetsState.peekSource(ITYPE_STATUS_BAR));
|
||||||
|
assertNull(ime.mAboveInsetsState.peekSource(ITYPE_NAVIGATION_BAR));
|
||||||
|
|
||||||
|
verify(ime, atLeastOnce()).notifyInsetsChanged();
|
||||||
|
verify(app, atLeastOnce()).notifyInsetsChanged();
|
||||||
|
verify(statusBar, atLeastOnce()).notifyInsetsChanged();
|
||||||
|
verify(navBar, atLeastOnce()).notifyInsetsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private WindowState createTestWindow(String name) {
|
||||||
|
final WindowState win = createWindow(null, TYPE_APPLICATION, name);
|
||||||
|
win.setHasSurface(true);
|
||||||
|
spyOn(win);
|
||||||
|
return win;
|
||||||
|
}
|
||||||
|
|
||||||
private InsetsStateController getController() {
|
private InsetsStateController getController() {
|
||||||
return mDisplayContent.getInsetsStateController();
|
return mDisplayContent.getInsetsStateController();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user