Merge "Add PrivacyIndicator APIs to WindowInsets" into sc-dev

This commit is contained in:
Nate Myren
2021-05-22 00:13:34 +00:00
committed by Android (Google) Code Review
14 changed files with 479 additions and 27 deletions

View File

@@ -50267,6 +50267,7 @@ package android.view {
method @NonNull public android.graphics.Insets getInsets(int);
method @NonNull public android.graphics.Insets getInsetsIgnoringVisibility(int);
method @Deprecated @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
method @Nullable public android.graphics.Rect getPrivacyIndicatorBounds();
method @Nullable public android.view.RoundedCorner getRoundedCorner(int);
method @Deprecated public int getStableInsetBottom();
method @Deprecated public int getStableInsetLeft();
@@ -50301,6 +50302,7 @@ package android.view {
method @NonNull public android.view.WindowInsets.Builder setInsets(int, @NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setInsetsIgnoringVisibility(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
method @Deprecated @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setPrivacyIndicatorBounds(@Nullable android.graphics.Rect);
method @NonNull public android.view.WindowInsets.Builder setRoundedCorner(int, @Nullable android.view.RoundedCorner);
method @Deprecated @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
method @Deprecated @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);

View File

@@ -384,6 +384,13 @@ interface IWindowManager
*/
oneway void setRecentsVisibility(boolean visible);
/**
* Called by System UI to indicate the maximum bounds of the system Privacy Indicator, for the
* current orientation, whether the indicator is showing or not. Should be an array of length
* 4, with the bounds for ROTATION_0, 90, 180, and 270, in that order.
*/
oneway void updateStaticPrivacyIndicatorBounds(int displayId, in Rect[] staticBounds);
/**
* Called by System UI to enable or disable haptic feedback on the navigation bar buttons.
*/

View File

@@ -690,6 +690,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
mState.setDisplayFrame(newState.getDisplayFrame());
mState.setDisplayCutout(newState.getDisplayCutout());
mState.setRoundedCorners(newState.getRoundedCorners());
mState.setPrivacyIndicatorBounds(newState.getPrivacyIndicatorBounds());
@InsetsType int disabledUserAnimationTypes = 0;
@InsetsType int[] cancelledUserAnimationTypes = {0};
for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {

View File

@@ -171,6 +171,10 @@ public class InsetsState implements Parcelable {
/** The rounded corners on the display */
private RoundedCorners mRoundedCorners = RoundedCorners.NO_ROUNDED_CORNERS;
/** The bounds of the Privacy Indicator */
private PrivacyIndicatorBounds mPrivacyIndicatorBounds =
new PrivacyIndicatorBounds();
public InsetsState() {
}
@@ -243,8 +247,9 @@ public class InsetsState implements Parcelable {
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
alwaysConsumeSystemBars, calculateRelativeCutout(frame),
calculateRelativeRoundedCorners(frame), compatInsetsTypes,
(legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
calculateRelativeRoundedCorners(frame),
calculateRelativePrivacyIndicatorBounds(frame),
compatInsetsTypes, (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
}
private DisplayCutout calculateRelativeCutout(Rect frame) {
@@ -282,6 +287,20 @@ public class InsetsState implements Parcelable {
return mRoundedCorners.inset(insetLeft, insetTop, insetRight, insetBottom);
}
private PrivacyIndicatorBounds calculateRelativePrivacyIndicatorBounds(Rect frame) {
if (mDisplayFrame.equals(frame)) {
return mPrivacyIndicatorBounds;
}
if (frame == null) {
return null;
}
final int insetLeft = frame.left - mDisplayFrame.left;
final int insetTop = frame.top - mDisplayFrame.top;
final int insetRight = mDisplayFrame.right - frame.right;
final int insetBottom = mDisplayFrame.bottom - frame.bottom;
return mPrivacyIndicatorBounds.inset(insetLeft, insetTop, insetRight, insetBottom);
}
public Rect calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
@@ -471,6 +490,14 @@ public class InsetsState implements Parcelable {
return mRoundedCorners;
}
public void setPrivacyIndicatorBounds(PrivacyIndicatorBounds bounds) {
mPrivacyIndicatorBounds = bounds;
}
public PrivacyIndicatorBounds getPrivacyIndicatorBounds() {
return mPrivacyIndicatorBounds;
}
/**
* Modifies the state of this class to exclude a certain type to make it ready for dispatching
* to the client.
@@ -508,6 +535,7 @@ public class InsetsState implements Parcelable {
mDisplayFrame.scale(scale);
mDisplayCutout.scale(scale);
mRoundedCorners = mRoundedCorners.scale(scale);
mPrivacyIndicatorBounds = mPrivacyIndicatorBounds.scale(scale);
for (int i = 0; i < SIZE; i++) {
final InsetsSource source = mSources[i];
if (source != null) {
@@ -528,6 +556,7 @@ public class InsetsState implements Parcelable {
mDisplayFrame.set(other.mDisplayFrame);
mDisplayCutout.set(other.mDisplayCutout);
mRoundedCorners = other.getRoundedCorners();
mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
if (copySources) {
for (int i = 0; i < SIZE; i++) {
InsetsSource source = other.mSources[i];
@@ -551,6 +580,7 @@ public class InsetsState implements Parcelable {
mDisplayFrame.set(other.mDisplayFrame);
mDisplayCutout.set(other.mDisplayCutout);
mRoundedCorners = other.getRoundedCorners();
mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
final ArraySet<Integer> t = toInternalType(types);
for (int i = t.size() - 1; i >= 0; i--) {
final int type = t.valueAt(i);
@@ -670,6 +700,7 @@ public class InsetsState implements Parcelable {
pw.println(newPrefix + "mDisplayFrame=" + mDisplayFrame);
pw.println(newPrefix + "mDisplayCutout=" + mDisplayCutout.get());
pw.println(newPrefix + "mRoundedCorners=" + mRoundedCorners);
pw.println(newPrefix + "mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds);
for (int i = 0; i < SIZE; i++) {
InsetsSource source = mSources[i];
if (source == null) continue;
@@ -764,7 +795,8 @@ public class InsetsState implements Parcelable {
if (!mDisplayFrame.equals(state.mDisplayFrame)
|| !mDisplayCutout.equals(state.mDisplayCutout)
|| !mRoundedCorners.equals(state.mRoundedCorners)) {
|| !mRoundedCorners.equals(state.mRoundedCorners)
|| !mPrivacyIndicatorBounds.equals(state.mPrivacyIndicatorBounds)) {
return false;
}
for (int i = 0; i < SIZE; i++) {
@@ -789,7 +821,7 @@ public class InsetsState implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mDisplayFrame, mDisplayCutout, Arrays.hashCode(mSources),
mRoundedCorners);
mRoundedCorners, mPrivacyIndicatorBounds);
}
public InsetsState(Parcel in) {
@@ -807,6 +839,7 @@ public class InsetsState implements Parcelable {
mDisplayCutout.writeToParcel(dest, flags);
dest.writeTypedArray(mSources, 0 /* parcelableFlags */);
dest.writeTypedObject(mRoundedCorners, flags);
dest.writeTypedObject(mPrivacyIndicatorBounds, flags);
}
public static final @NonNull Creator<InsetsState> CREATOR = new Creator<InsetsState>() {
@@ -825,6 +858,7 @@ public class InsetsState implements Parcelable {
mDisplayCutout.readFromParcel(in);
in.readTypedArray(mSources, InsetsSource.CREATOR);
mRoundedCorners = in.readTypedObject(RoundedCorners.CREATOR);
mPrivacyIndicatorBounds = in.readTypedObject(PrivacyIndicatorBounds.CREATOR);
}
@Override
@@ -840,6 +874,7 @@ public class InsetsState implements Parcelable {
+ "mDisplayFrame=" + mDisplayFrame
+ ", mDisplayCutout=" + mDisplayCutout
+ ", mRoundedCorners=" + mRoundedCorners
+ ", mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds
+ ", mSources= { " + joiner
+ " }";
}

View File

@@ -0,0 +1,251 @@
/*
* Copyright (C) 2021 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 static android.view.Surface.ROTATION_0;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.Parcelable;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DataClass;
/**
* A class which manages the bounds of the privacy indicator
*
* @hide
*/
@DataClass(
genEqualsHashCode = true,
genConstructor = false,
genAidl = false,
genGetters = false
)
public class PrivacyIndicatorBounds implements Parcelable {
private final @NonNull Rect[] mStaticBounds;
private final int mRotation;
public PrivacyIndicatorBounds() {
mStaticBounds = new Rect[4];
mRotation = ROTATION_0;
}
public PrivacyIndicatorBounds(@NonNull Rect[] staticBounds, @Surface.Rotation int rotation) {
mStaticBounds = staticBounds;
mRotation = rotation;
}
/**
* Return a PrivacyIndicatorBounds with updated static bounds
*/
public PrivacyIndicatorBounds updateStaticBounds(@NonNull Rect[] staticPositions) {
return new PrivacyIndicatorBounds(staticPositions, mRotation);
}
/**
* Update the bounds of the indicator for a specific rotation, or ROTATION_0, if the provided
* rotation integer isn't found
*/
public PrivacyIndicatorBounds updateBoundsForRotation(@Nullable Rect bounds,
@Surface.Rotation int rotation) {
if (rotation >= mStaticBounds.length || rotation < 0) {
return this;
}
Rect[] newBounds = ArrayUtils.cloneOrNull(mStaticBounds);
newBounds[rotation] = bounds;
return updateStaticBounds(newBounds);
}
/**
* Return an inset PrivacyIndicatorBounds
*/
public PrivacyIndicatorBounds inset(int insetLeft, int insetTop, int insetRight,
int insetBottom) {
if (insetLeft == 0 && insetTop == 0 && insetRight == 0 && insetBottom == 0) {
return this;
}
Rect[] insetStaticBounds = new Rect[mStaticBounds.length];
for (int i = 0; i < mStaticBounds.length; i++) {
insetStaticBounds[i] =
insetRect(mStaticBounds[i], insetLeft, insetTop, insetRight, insetBottom);
}
return updateStaticBounds(insetStaticBounds);
}
private static Rect insetRect(Rect orig, int insetLeft, int insetTop, int insetRight,
int insetBottom) {
if (orig == null) {
return null;
}
int left = Math.max(0, orig.left - insetLeft);
int top = Math.max(0, orig.top - insetTop);
int right = Math.max(left, orig.right - insetRight);
int bottom = Math.max(top, orig.bottom - insetBottom);
return new Rect(left, top, right, bottom);
}
/**
* Return a PrivacyIndicatorBounds with the static position rotated.
*/
public PrivacyIndicatorBounds rotate(@Surface.Rotation int rotation) {
if (rotation == ROTATION_0) {
return this;
}
return new PrivacyIndicatorBounds(mStaticBounds, rotation);
}
/**
* Returns a scaled PrivacyIndicatorBounds
*/
public PrivacyIndicatorBounds scale(float scale) {
if (scale == 1f) {
return this;
}
Rect[] scaledStaticPos = new Rect[mStaticBounds.length];
for (int i = 0; i < mStaticBounds.length; i++) {
scaledStaticPos[i] = scaleRect(mStaticBounds[i], scale);
}
return new PrivacyIndicatorBounds(scaledStaticPos, mRotation);
}
private static Rect scaleRect(Rect orig, float scale) {
if (orig == null) {
return null;
}
Rect newRect = new Rect(orig);
newRect.scale(scale);
return newRect;
}
public Rect getStaticPrivacyIndicatorBounds() {
return mStaticBounds[mRotation];
}
@Override
public String toString() {
return "PrivacyIndicatorBounds {static bounds=" + getStaticPrivacyIndicatorBounds()
+ " rotation=" + mRotation + "}";
}
// Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/PrivacyIndicatorBounds.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
@Override
@DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
// You can override field equality logic by defining either of the methods like:
// boolean fieldNameEquals(PrivacyIndicatorBounds other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
PrivacyIndicatorBounds that = (PrivacyIndicatorBounds) o;
//noinspection PointlessBooleanExpression
return true
&& java.util.Arrays.equals(mStaticBounds, that.mStaticBounds)
&& mRotation == that.mRotation;
}
@Override
@DataClass.Generated.Member
public int hashCode() {
// You can override field hashCode logic by defining methods like:
// int fieldNameHashCode() { ... }
int _hash = 1;
_hash = 31 * _hash + java.util.Arrays.hashCode(mStaticBounds);
_hash = 31 * _hash + mRotation;
return _hash;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
dest.writeTypedArray(mStaticBounds, flags);
dest.writeInt(mRotation);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
protected PrivacyIndicatorBounds(@NonNull android.os.Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
Rect[] staticBounds = (Rect[]) in.createTypedArray(Rect.CREATOR);
int rotation = in.readInt();
this.mStaticBounds = staticBounds;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mStaticBounds);
this.mRotation = rotation;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<PrivacyIndicatorBounds> CREATOR
= new Parcelable.Creator<PrivacyIndicatorBounds>() {
@Override
public PrivacyIndicatorBounds[] newArray(int size) {
return new PrivacyIndicatorBounds[size];
}
@Override
public PrivacyIndicatorBounds createFromParcel(@NonNull android.os.Parcel in) {
return new PrivacyIndicatorBounds(in);
}
};
@DataClass.Generated(
time = 1621526273838L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/PrivacyIndicatorBounds.java",
inputSignatures = "private final @android.annotation.NonNull android.graphics.Rect[] mStaticBounds\nprivate final int mRotation\npublic android.view.PrivacyIndicatorBounds updateStaticBounds(android.graphics.Rect[])\npublic android.view.PrivacyIndicatorBounds updateBoundsForRotation(android.graphics.Rect,int)\npublic android.view.PrivacyIndicatorBounds inset(int,int,int,int)\nprivate static android.graphics.Rect insetRect(android.graphics.Rect,int,int,int,int)\npublic android.view.PrivacyIndicatorBounds rotate(int)\npublic android.view.PrivacyIndicatorBounds scale(float)\nprivate static android.graphics.Rect scaleRect(android.graphics.Rect,float)\npublic android.graphics.Rect getStaticPrivacyIndicatorBounds()\npublic @java.lang.Override java.lang.String toString()\nclass PrivacyIndicatorBounds extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genConstructor=false, genAidl=false, genGetters=false)")
@Deprecated
private void __metadata() {}
//@formatter:on
// End of generated code
}

View File

@@ -17,6 +17,7 @@
package android.view;
import static android.view.Surface.ROTATION_0;
import static android.view.WindowInsets.Type.DISPLAY_CUTOUT;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.IME;
@@ -83,6 +84,7 @@ public final class WindowInsets {
private final boolean mIsRound;
@Nullable private final DisplayCutout mDisplayCutout;
@Nullable private final RoundedCorners mRoundedCorners;
@Nullable private final PrivacyIndicatorBounds mPrivacyIndicatorBounds;
/**
* In multi-window we force show the navigation bar. Because we don't want that the surface size
@@ -131,8 +133,8 @@ public final class WindowInsets {
boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
isRound, alwaysConsumeSystemBars, displayCutout, null, systemBars(),
false /* compatIgnoreVisibility */);
isRound, alwaysConsumeSystemBars, displayCutout, null, null,
systemBars(), false /* compatIgnoreVisibility */);
}
/**
@@ -152,8 +154,9 @@ public final class WindowInsets {
boolean[] typeVisibilityMap,
boolean isRound,
boolean alwaysConsumeSystemBars, DisplayCutout displayCutout,
RoundedCorners roundedCorners, @InsetsType int compatInsetsTypes,
boolean compatIgnoreVisibility) {
RoundedCorners roundedCorners,
PrivacyIndicatorBounds privacyIndicatorBounds,
@InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility) {
mSystemWindowInsetsConsumed = typeInsetsMap == null;
mTypeInsetsMap = mSystemWindowInsetsConsumed
? new Insets[SIZE]
@@ -175,6 +178,7 @@ public final class WindowInsets {
? null : displayCutout;
mRoundedCorners = roundedCorners;
mPrivacyIndicatorBounds = privacyIndicatorBounds;
}
/**
@@ -188,6 +192,7 @@ public final class WindowInsets {
src.mTypeVisibilityMap, src.mIsRound,
src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
src.mRoundedCorners,
src.mPrivacyIndicatorBounds,
src.mCompatInsetsTypes,
src.mCompatIgnoreVisibility);
}
@@ -241,7 +246,7 @@ public final class WindowInsets {
@UnsupportedAppUsage
public WindowInsets(Rect systemWindowInsets) {
this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
null, systemBars(), false /* compatIgnoreVisibility */);
null, null, systemBars(), false /* compatIgnoreVisibility */);
}
/**
@@ -509,6 +514,19 @@ public final class WindowInsets {
return mRoundedCorners == null ? null : mRoundedCorners.getRoundedCorner(position);
}
/**
* Returns the {@link Rect} of the maximum bounds of the system privacy indicator, for the
* current orientation, in relative coordinates, or null if the bounds have not been loaded yet.
* The privacy indicator shows over apps when an app uses the microphone or camera permissions,
* while an app is in immersive mode.
*
* @return A rectangle representing the maximum bounds of the indicator
*/
public @Nullable Rect getPrivacyIndicatorBounds() {
return mPrivacyIndicatorBounds == null ? null
: mPrivacyIndicatorBounds.getStaticPrivacyIndicatorBounds();
}
/**
* Returns a copy of this WindowInsets with the cutout fully consumed.
*
@@ -524,7 +542,7 @@ public final class WindowInsets {
mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
null /* displayCutout */, mRoundedCorners,
null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds,
mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -576,7 +594,8 @@ public final class WindowInsets {
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
displayCutoutCopyConstructorArgument(this),
mRoundedCorners, mCompatInsetsTypes, mCompatIgnoreVisibility);
mRoundedCorners, mPrivacyIndicatorBounds, mCompatInsetsTypes,
mCompatIgnoreVisibility);
}
// TODO(b/119190588): replace @code with @link below
@@ -881,6 +900,9 @@ public final class WindowInsets {
result.append("\n ");
result.append(mRoundedCorners != null ? "roundedCorners=" + mRoundedCorners : "");
result.append("\n ");
result.append(mPrivacyIndicatorBounds != null ? "privacyIndicatorBounds="
+ mPrivacyIndicatorBounds : "");
result.append("\n ");
result.append(isRound() ? "round" : "");
result.append("}");
return result.toString();
@@ -975,6 +997,9 @@ public final class WindowInsets {
mRoundedCorners == null
? RoundedCorners.NO_ROUNDED_CORNERS
: mRoundedCorners.inset(left, top, right, bottom),
mPrivacyIndicatorBounds == null
? null
: mPrivacyIndicatorBounds.inset(left, top, right, bottom),
mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -993,7 +1018,8 @@ public final class WindowInsets {
&& Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
&& Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
&& Objects.equals(mDisplayCutout, that.mDisplayCutout)
&& Objects.equals(mRoundedCorners, that.mRoundedCorners);
&& Objects.equals(mRoundedCorners, that.mRoundedCorners)
&& Objects.equals(mPrivacyIndicatorBounds, that.mPrivacyIndicatorBounds);
}
@Override
@@ -1001,7 +1027,7 @@ public final class WindowInsets {
return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mRoundedCorners,
mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
mDisplayCutoutConsumed);
mDisplayCutoutConsumed, mPrivacyIndicatorBounds);
}
@@ -1066,6 +1092,8 @@ public final class WindowInsets {
private boolean mIsRound;
private boolean mAlwaysConsumeSystemBars;
private PrivacyIndicatorBounds mPrivacyIndicatorBounds = new PrivacyIndicatorBounds();
/**
* Creates a builder where all insets are initially consumed.
*/
@@ -1090,6 +1118,7 @@ public final class WindowInsets {
mRoundedCorners = insets.mRoundedCorners;
mIsRound = insets.mIsRound;
mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
mPrivacyIndicatorBounds = insets.mPrivacyIndicatorBounds;
}
/**
@@ -1314,6 +1343,26 @@ public final class WindowInsets {
return this;
}
/** @hide */
@NonNull
public Builder setPrivacyIndicatorBounds(@Nullable PrivacyIndicatorBounds bounds) {
mPrivacyIndicatorBounds = bounds;
return this;
}
/**
* Sets the bounds of the system privacy indicator.
*
* @param bounds The bounds of the system privacy indicator
*/
@NonNull
public Builder setPrivacyIndicatorBounds(@Nullable Rect bounds) {
//TODO 188788786: refactor the indicator bounds
Rect[] boundsArr = { bounds, bounds, bounds, bounds };
mPrivacyIndicatorBounds = new PrivacyIndicatorBounds(boundsArr, ROTATION_0);
return this;
}
/** @hide */
@NonNull
public Builder setRound(boolean round) {
@@ -1338,7 +1387,7 @@ public final class WindowInsets {
return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout, mRoundedCorners,
systemBars(), false /* compatIgnoreVisibility */);
mPrivacyIndicatorBounds, systemBars(), false /* compatIgnoreVisibility */);
}
}

View File

@@ -314,6 +314,51 @@ public class InsetsStateTest {
assertEqualsAndHashCode();
}
@Test
public void testEquals_samePrivacyIndicator() {
Rect one = new Rect(0, 1, 2, 3);
Rect two = new Rect(4, 5, 6, 7);
Rect[] bounds = new Rect[] { one, two, one, two };
mState.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(bounds, 0));
mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(bounds, 0));
assertEqualsAndHashCode();
}
@Test
public void testEquals_differentPrivacyIndicatorStaticBounds() {
Rect one = new Rect(0, 1, 2, 3);
Rect two = new Rect(4, 5, 6, 7);
Rect three = new Rect(8, 9, 10, 11);
Rect[] boundsOne = new Rect[] { one, two, one, two };
Rect[] boundsDifferent = new Rect[] { one, two, three, one };
Rect[] boundsDifferentOrder = new Rect[] { two, one, one, two };
Rect[] boundsDifferentLength = new Rect[] { one, two };
Rect[] boundsNull = new Rect[4];
mState.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsOne, 0));
mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsDifferent, 0));
assertNotEqualsAndHashCode();
mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsDifferentOrder, 0));
assertNotEqualsAndHashCode();
mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsDifferentLength, 0));
assertNotEqualsAndHashCode();
mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsNull, 0));
assertNotEqualsAndHashCode();
}
@Test
public void testEquals_differentPrivacyIndicatorRotation() {
Rect one = new Rect(0, 1, 2, 3);
Rect two = new Rect(4, 5, 6, 7);
Rect[] arr = new Rect[] { one, two, one, two};
mState.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(arr, 0));
mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(arr, 1));
assertNotEqualsAndHashCode();
}
@Test
public void testEquals_excludeInvisibleIme() {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 0, 100, 100));

View File

@@ -61,7 +61,7 @@ public class WindowInsetsTest {
WindowInsets.assignCompatInsets(maxInsets, new Rect(0, 10, 0, 0));
WindowInsets.assignCompatInsets(insets, new Rect(0, 0, 0, 0));
WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, false, null,
null, systemBars(), true /* compatIgnoreVisibility */);
null, null, systemBars(), true /* compatIgnoreVisibility */);
assertEquals(Insets.of(0, 10, 0, 0), windowInsets.getSystemWindowInsets());
}
}

View File

@@ -200,6 +200,7 @@ import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.MagnificationSpec;
import android.view.PrivacyIndicatorBounds;
import android.view.RemoteAnimationDefinition;
import android.view.RoundedCorners;
import android.view.Surface;
@@ -342,6 +343,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
private final RotationCache<RoundedCorners, RoundedCorners> mRoundedCornerCache =
new RotationCache<>(this::calculateRoundedCornersForRotationUncached);
PrivacyIndicatorBounds mCurrentPrivacyIndicatorBounds = new PrivacyIndicatorBounds();
private final RotationCache<PrivacyIndicatorBounds, PrivacyIndicatorBounds>
mPrivacyIndicatorBoundsCache = new
RotationCache<>(this::calculatePrivacyIndicatorBoundsForRotationUncached);
/**
* Overridden display size. Initialized with {@link #mInitialDisplayWidth}
* and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
@@ -996,7 +1002,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mInsetsStateController = new InsetsStateController(this);
mDisplayFrames = new DisplayFrames(mDisplayId, mInsetsStateController.getRawInsetsState(),
mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
calculateRoundedCornersForRotation(mDisplayInfo.rotation));
calculateRoundedCornersForRotation(mDisplayInfo.rotation),
calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation));
initializeDisplayBaseInfo();
mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
@@ -1723,8 +1730,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final DisplayInfo info = computeScreenConfiguration(mTmpConfiguration, rotation);
final WmDisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
final PrivacyIndicatorBounds indicatorBounds =
calculatePrivacyIndicatorBoundsForRotation(rotation);
final DisplayFrames displayFrames = new DisplayFrames(mDisplayId, new InsetsState(), info,
cutout, roundedCorners);
cutout, roundedCorners, indicatorBounds);
token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
}
@@ -2022,6 +2031,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return roundedCorners.rotate(rotation, mInitialDisplayWidth, mInitialDisplayHeight);
}
PrivacyIndicatorBounds calculatePrivacyIndicatorBoundsForRotation(int rotation) {
return mPrivacyIndicatorBoundsCache.getOrCompute(mCurrentPrivacyIndicatorBounds, rotation);
}
private PrivacyIndicatorBounds calculatePrivacyIndicatorBoundsForRotationUncached(
PrivacyIndicatorBounds bounds, int rotation) {
if (bounds == null) {
return new PrivacyIndicatorBounds(new Rect[4], rotation);
}
return bounds.rotate(rotation);
}
/**
* Compute display info and configuration according to the given rotation without changing
* current display.
@@ -2537,14 +2559,30 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
onDisplayChanged(this);
}
void updatePrivacyIndicatorBounds(Rect[] staticBounds) {
PrivacyIndicatorBounds oldBounds = mCurrentPrivacyIndicatorBounds;
mCurrentPrivacyIndicatorBounds =
mCurrentPrivacyIndicatorBounds.updateStaticBounds(staticBounds);
if (!Objects.equals(oldBounds, mCurrentPrivacyIndicatorBounds)) {
final DisplayInfo info = mDisplayInfo;
if (mDisplayFrames.onDisplayInfoUpdated(info,
calculateDisplayCutoutForRotation(info.rotation),
calculateRoundedCornersForRotation(info.rotation),
calculatePrivacyIndicatorBoundsForRotation(info.rotation))) {
mInsetsStateController.onDisplayInfoUpdated(true);
}
}
}
void onDisplayInfoChanged() {
final DisplayInfo info = mDisplayInfo;
if (mDisplayFrames.onDisplayInfoUpdated(info,
calculateDisplayCutoutForRotation(info.rotation),
calculateRoundedCornersForRotation(info.rotation))) {
calculateRoundedCornersForRotation(info.rotation),
calculatePrivacyIndicatorBoundsForRotation(info.rotation))) {
// TODO(b/161810301): Set notifyInsetsChange to true while the server no longer performs
// layout.
mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChange */);
mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChanged */);
}
mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight);
mDisplayPolicy.onDisplayInfoChanged(info);
@@ -2579,6 +2617,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
mInitialDisplayCutout = mDisplayInfo.displayCutout;
mInitialRoundedCorners = mDisplayInfo.roundedCorners;
mCurrentPrivacyIndicatorBounds = new PrivacyIndicatorBounds(new Rect[4],
mDisplayInfo.rotation);
}
/**

View File

@@ -27,6 +27,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.InsetsState;
import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
import com.android.server.wm.utils.WmDisplayCutout;
@@ -59,10 +60,11 @@ public class DisplayFrames {
public int mRotation;
public DisplayFrames(int displayId, InsetsState insetsState, DisplayInfo info,
WmDisplayCutout displayCutout, RoundedCorners roundedCorners) {
WmDisplayCutout displayCutout, RoundedCorners roundedCorners,
PrivacyIndicatorBounds indicatorBounds) {
mDisplayId = displayId;
mInsetsState = insetsState;
onDisplayInfoUpdated(info, displayCutout, roundedCorners);
onDisplayInfoUpdated(info, displayCutout, roundedCorners, indicatorBounds);
}
/**
@@ -74,15 +76,17 @@ public class DisplayFrames {
* @return {@code true} if the insets state has been changed; {@code false} otherwise.
*/
public boolean onDisplayInfoUpdated(DisplayInfo info, @NonNull WmDisplayCutout displayCutout,
@NonNull RoundedCorners roundedCorners) {
@NonNull RoundedCorners roundedCorners,
@NonNull PrivacyIndicatorBounds indicatorBounds) {
mRotation = info.rotation;
final InsetsState state = mInsetsState;
final Rect safe = mDisplayCutoutSafe;
final DisplayCutout cutout = displayCutout.getDisplayCutout();
if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
&& state.getDisplayCutout().equals(cutout)
&& state.getRoundedCorners().equals(roundedCorners)) {
&& state.getDisplayCutout().equals(cutout)
&& state.getRoundedCorners().equals(roundedCorners)
&& state.getPrivacyIndicatorBounds().equals(indicatorBounds)) {
return false;
}
mDisplayWidth = info.logicalWidth;
@@ -93,6 +97,7 @@ public class DisplayFrames {
state.setDisplayFrame(unrestricted);
state.setDisplayCutout(cutout);
state.setRoundedCorners(roundedCorners);
state.setPrivacyIndicatorBounds(indicatorBounds);
if (!cutout.isEmpty()) {
if (cutout.getSafeInsetLeft() > 0) {
safe.left = unrestricted.left + cutout.getSafeInsetLeft();

View File

@@ -5945,6 +5945,20 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
@Override
public void updateStaticPrivacyIndicatorBounds(int displayId,
Rect[] staticBounds) {
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null) {
displayContent.updatePrivacyIndicatorBounds(staticBounds);
} else {
Slog.w(TAG, "updateStaticPrivacyIndicatorBounds with invalid displayId="
+ displayId);
}
}
}
public void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
!= PackageManager.PERMISSION_GRANTED) {

View File

@@ -65,6 +65,7 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsState;
import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
@@ -176,7 +177,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
? mDisplayContent.calculateRoundedCornersForRotation(mRotation)
: RoundedCorners.NO_ROUNDED_CORNERS;
return new DisplayFrames(mDisplayContent.getDisplayId(),
insetsState, info.first, info.second, roundedCorners);
insetsState, info.first, info.second, roundedCorners, new PrivacyIndicatorBounds());
}
@Test

View File

@@ -54,6 +54,7 @@ import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.PrivacyIndicatorBounds;
import android.view.WindowInsets.Side;
import android.view.WindowManager;
@@ -317,7 +318,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
mImeWindow.mAboveInsetsState.set(state);
mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(),
state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS);
state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);

View File

@@ -49,6 +49,7 @@ import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsState;
import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -152,7 +153,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0);
final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
final DisplayFrames displayFrames = new DisplayFrames(dc.getDisplayId(), new InsetsState(),
info, cutout, RoundedCorners.NO_ROUNDED_CORNERS);
info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
wallpaperWindowToken.applyFixedRotationTransform(info, displayFrames, config);
// Check that the wallpaper has the same frame in landscape than in portrait