diff options
author | Jorim Jaggi <jjaggi@google.com> | 2019-01-07 14:49:14 +0100 |
---|---|---|
committer | Tiger Huang <tigerhuang@google.com> | 2019-10-17 01:41:34 +0800 |
commit | cb1b848084be47118342c4893ede2298067c3d0f (patch) | |
tree | e6bf17927dec58d35abe74744240f679181019a2 | |
parent | 2ff65cd6853ab492dadf1c08b0564538e0633f0e (diff) |
Window Manager Flag Migration (4/n)
Wire up the appearance and the transient state of system bars between
WMS and System UI. The derived classes of CommandQueue.Callbacks no
longer listen to setSystemUiVisibility, but listen to showTransient,
abortTransient, and onSystemBarAppearanceChanged instead.
Bug: 118118435
Test: atest InsetsSourceProviderTest InsetsStateControllerTest
InsetsPolicyTest WindowStateTests CommandQueueTest
RegisterStatusBarResultTest InsetsFlagsTest
LightBarControllerTest
Change-Id: I1dcaff47ae57ccee91146fdc042cde5e26fc0b3f
43 files changed, 1617 insertions, 665 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 35cfe9e591cf..7f717a72b0f9 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -306,6 +306,11 @@ interface IWindowManager oneway void statusBarVisibilityChanged(int displayId, int visibility); /** + * Called by System UI to notify Window Manager to hide transient bars. + */ + oneway void hideTransientBars(int displayId); + + /** * When set to {@code true} the system bars will always be shown. This is true even if an app * requests to be fullscreen by setting the system ui visibility flags. The * functionality was added for the automotive case as a way to guarantee required content stays diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index e4deffadc966..0fb1c33df2ab 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -146,20 +146,11 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll } final Insets offset = Insets.subtract(mShownInsets, mPendingInsets); ArrayList<SurfaceParams> params = new ArrayList<>(); - if (offset.left != 0) { - updateLeashesForSide(INSET_SIDE_LEFT, offset.left, mPendingInsets.left, params, state); - } - if (offset.top != 0) { - updateLeashesForSide(INSET_SIDE_TOP, offset.top, mPendingInsets.top, params, state); - } - if (offset.right != 0) { - updateLeashesForSide(INSET_SIDE_RIGHT, offset.right, mPendingInsets.right, params, - state); - } - if (offset.bottom != 0) { - updateLeashesForSide(INSET_SIDE_BOTTOM, offset.bottom, mPendingInsets.bottom, params, - state); - } + updateLeashesForSide(INSET_SIDE_LEFT, offset.left, mPendingInsets.left, params, state); + updateLeashesForSide(INSET_SIDE_TOP, offset.top, mPendingInsets.top, params, state); + updateLeashesForSide(INSET_SIDE_RIGHT, offset.right, mPendingInsets.right, params, state); + updateLeashesForSide(INSET_SIDE_BOTTOM, offset.bottom, mPendingInsets.bottom, params, + state); SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get(); applier.scheduleApply(params.toArray(new SurfaceParams[params.size()])); mCurrentInsets = mPendingInsets; @@ -224,6 +215,9 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll private void updateLeashesForSide(@InsetSide int side, int offset, int inset, ArrayList<SurfaceParams> surfaceParams, InsetsState state) { ArraySet<InsetsSourceConsumer> items = mSideSourceMap.get(side); + if (items == null) { + return; + } // TODO: Implement behavior when inset spans over multiple types for (int i = items.size() - 1; i >= 0; i--) { final InsetsSourceConsumer consumer = items.valueAt(i); @@ -274,9 +268,15 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll SparseSetArray<InsetsSourceConsumer> sideSourcesMap, SparseArray<InsetsSourceConsumer> consumers) { for (int i = typeSideMap.size() - 1; i >= 0; i--) { - int type = typeSideMap.keyAt(i); - int side = typeSideMap.valueAt(i); - sideSourcesMap.add(side, consumers.get(type)); + final int type = typeSideMap.keyAt(i); + final int side = typeSideMap.valueAt(i); + final InsetsSourceConsumer consumer = consumers.get(type); + if (consumer == null) { + // If the types that we are controlling are less than the types that the system has, + // there can be some null consumers. + continue; + } + sideSourcesMap.add(side, consumer); } } } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 5bb4f63d62c8..eca6dcb1daac 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -67,9 +67,9 @@ public class InsetsController implements WindowInsetsController { * Translation animation evaluator. */ private static TypeEvaluator<Insets> sEvaluator = (fraction, startValue, endValue) -> Insets.of( - 0, + (int) (startValue.left + fraction * (endValue.left - startValue.left)), (int) (startValue.top + fraction * (endValue.top - startValue.top)), - 0, + (int) (startValue.right + fraction * (endValue.right - startValue.right)), (int) (startValue.bottom + fraction * (endValue.bottom - startValue.bottom))); /** diff --git a/core/java/android/view/InsetsFlags.java b/core/java/android/view/InsetsFlags.java index 276e80a772f3..6e459b22e657 100644 --- a/core/java/android/view/InsetsFlags.java +++ b/core/java/android/view/InsetsFlags.java @@ -16,10 +16,18 @@ package android.view; +import static android.view.View.NAVIGATION_BAR_TRANSLUCENT; +import static android.view.View.NAVIGATION_BAR_TRANSPARENT; +import static android.view.View.STATUS_BAR_TRANSLUCENT; +import static android.view.View.STATUS_BAR_TRANSPARENT; +import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; +import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; +import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_SIDE_BARS; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_TOP_BAR; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; -import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_BARS; +import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_SIDE_BARS; +import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_TOP_BAR; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; @@ -35,9 +43,13 @@ public class InsetsFlags { @ViewDebug.ExportedProperty(flagMapping = { @ViewDebug.FlagToString( - mask = APPEARANCE_OPAQUE_BARS, - equals = APPEARANCE_OPAQUE_BARS, - name = "OPAQUE_BARS"), + mask = APPEARANCE_OPAQUE_TOP_BAR, + equals = APPEARANCE_OPAQUE_TOP_BAR, + name = "OPAQUE_TOP_BAR"), + @ViewDebug.FlagToString( + mask = APPEARANCE_OPAQUE_SIDE_BARS, + equals = APPEARANCE_OPAQUE_SIDE_BARS, + name = "OPAQUE_SIDE_BARS"), @ViewDebug.FlagToString( mask = APPEARANCE_LOW_PROFILE_BARS, equals = APPEARANCE_LOW_PROFILE_BARS, @@ -64,4 +76,44 @@ public class InsetsFlags { name = "SHOW_TRANSIENT_BARS_BY_SWIPE") }) public @Behavior int behavior; + + /** + * Converts system UI visibility to appearance. + * + * @param systemUiVisibility the system UI visibility to be converted. + * @return the outcome {@link Appearance} + */ + public static @Appearance int getAppearance(int systemUiVisibility) { + int appearance = 0; + appearance |= convertFlag(systemUiVisibility, SYSTEM_UI_FLAG_LOW_PROFILE, + APPEARANCE_LOW_PROFILE_BARS); + appearance |= convertFlag(systemUiVisibility, SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, + APPEARANCE_LIGHT_TOP_BAR); + appearance |= convertFlag(systemUiVisibility, SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, + APPEARANCE_LIGHT_SIDE_BARS); + appearance |= convertNoFlag(systemUiVisibility, + STATUS_BAR_TRANSLUCENT | STATUS_BAR_TRANSPARENT, APPEARANCE_OPAQUE_TOP_BAR); + appearance |= convertNoFlag(systemUiVisibility, + NAVIGATION_BAR_TRANSLUCENT | NAVIGATION_BAR_TRANSPARENT, + APPEARANCE_OPAQUE_SIDE_BARS); + return appearance; + } + + /** + * Converts the system UI visibility into an appearance flag if the given visibility contains + * the given system UI flag. + */ + private static @Appearance int convertFlag(int systemUiVisibility, int systemUiFlag, + @Appearance int appearance) { + return (systemUiVisibility & systemUiFlag) != 0 ? appearance : 0; + } + + /** + * Converts the system UI visibility into an appearance flag if the given visibility doesn't + * contains the given system UI flag. + */ + private static @Appearance int convertNoFlag(int systemUiVisibility, int systemUiFlag, + @Appearance int appearance) { + return (systemUiVisibility & systemUiFlag) == 0 ? appearance : 0; + } } diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index a04c39b63c85..99502a6c1d72 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -270,10 +270,23 @@ public class InsetsState implements Parcelable { * * @param type The {@link InternalInsetType} of the source to remove */ - public void removeSource(int type) { + public void removeSource(@InternalInsetType int type) { mSources.remove(type); } + /** + * A shortcut for setting the visibility of the source. + * + * @param type The {@link InternalInsetType} of the source to set the visibility + * @param visible {@code true} for visible + */ + public void setSourceVisible(@InternalInsetType int type, boolean visible) { + InsetsSource source = mSources.get(type); + if (source != null) { + source.setVisible(visible); + } + } + public void set(InsetsState other) { set(other, false /* copySources */); } @@ -357,6 +370,19 @@ public class InsetsState implements Parcelable { } } + public static boolean containsType(@InternalInsetType int[] types, + @InternalInsetType int type) { + if (types == null) { + return false; + } + for (int t : types) { + if (t == type) { + return true; + } + } + return false; + } + public void dump(String prefix, PrintWriter pw) { pw.println(prefix + "InsetsState"); for (int i = mSources.size() - 1; i >= 0; i--) { @@ -364,7 +390,7 @@ public class InsetsState implements Parcelable { } } - public static String typeToString(int type) { + public static String typeToString(@InternalInsetType int type) { switch (type) { case TYPE_TOP_BAR: return "TYPE_TOP_BAR"; diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java index 396422ef5c57..b41531988518 100644 --- a/core/java/android/view/WindowInsetsController.java +++ b/core/java/android/view/WindowInsetsController.java @@ -35,33 +35,39 @@ import java.lang.annotation.RetentionPolicy; public interface WindowInsetsController { /** - * Makes system bars become opaque with solid dark background and light foreground. + * Makes the top bars become opaque with solid dark background and light foreground. * @hide */ - int APPEARANCE_OPAQUE_BARS = 1; + int APPEARANCE_OPAQUE_TOP_BAR = 1; + + /** + * Makes the side bars become opaque with solid dark background and light foreground. + * @hide + */ + int APPEARANCE_OPAQUE_SIDE_BARS = 1 << 1; /** * Makes items on system bars become less noticeable without changing the layout of the bars. * @hide */ - int APPEARANCE_LOW_PROFILE_BARS = 1 << 1; + int APPEARANCE_LOW_PROFILE_BARS = 1 << 2; /** * Changes the foreground color for the light top bar so that the items on the bar can be read * clearly. */ - int APPEARANCE_LIGHT_TOP_BAR = 1 << 2; + int APPEARANCE_LIGHT_TOP_BAR = 1 << 3; /** * Changes the foreground color for the light side bars so that the items on the bar can be read * clearly. */ - int APPEARANCE_LIGHT_SIDE_BARS = 1 << 3; + int APPEARANCE_LIGHT_SIDE_BARS = 1 << 4; /** Determines the appearance of system bars. */ @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, value = {APPEARANCE_OPAQUE_BARS, APPEARANCE_LOW_PROFILE_BARS, - APPEARANCE_LIGHT_TOP_BAR, APPEARANCE_LIGHT_SIDE_BARS}) + @IntDef(flag = true, value = {APPEARANCE_OPAQUE_TOP_BAR, APPEARANCE_OPAQUE_SIDE_BARS, + APPEARANCE_LOW_PROFILE_BARS, APPEARANCE_LIGHT_TOP_BAR, APPEARANCE_LIGHT_SIDE_BARS}) @interface Appearance { } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index c8ba52a63151..d9e2ba3e0975 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -23,6 +23,7 @@ import android.os.Bundle; import android.service.notification.StatusBarNotification; import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.view.AppearanceRegion; /** @hide */ oneway interface IStatusBar @@ -56,7 +57,7 @@ oneway interface IStatusBar int mask, in Rect fullscreenBounds, in Rect dockedBounds, boolean navbarColorManagedByIme); - void topAppWindowChanged(int displayId, boolean menuVisible); + void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive); void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition, boolean showImeSwitcher, boolean isMultiClientImeEnabled); void setWindowState(int display, int window, int state); @@ -172,4 +173,38 @@ oneway interface IStatusBar * Notifies System UI whether the recents animation is running or not. */ void onRecentsAnimationStateChanged(boolean running); + + /** + * Notifies System UI side of system bar appearance change on the specified display. + * + * @param displayId the ID of the display to notify + * @param appearance the appearance of the focused window. The light top bar appearance is not + * controlled here, but primaryAppearance and secondaryAppearance. + * @param appearanceRegions a set of appearances which will be only applied in their own bounds. + * This is for system bars which across multiple stack, e.g., status + * bar, that the bar can have partial appearances in corresponding + * stacks. + * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME. + */ + void onSystemBarAppearanceChanged(int displayId, int appearance, + in AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme); + + /** + * Notifies System UI to show transient bars. The transient bars are system bars, e.g., status + * bar and navigation bar which are temporarily visible to the user. + * + * @param displayId the ID of the display to notify. + * @param types the internal insets types of the bars are about to show transiently. + */ + void showTransient(int displayId, in int[] types); + + /** + * Notifies System UI to abort the transient state of system bars, which prevents the bars being + * hidden automatically. This is usually called when the app wants to show the permanent system + * bars again. + * + * @param displayId the ID of the display to notify. + * @param types the internal insets types of the bars are about to abort the transient state. + */ + void abortTransient(int displayId, in int[] types); } diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java index 6b0f8b2f5dc9..4c3f04b10892 100644 --- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java +++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java @@ -29,7 +29,6 @@ public final class RegisterStatusBarResult implements Parcelable { public final ArrayMap<String, StatusBarIcon> mIcons; public final int mDisabledFlags1; // switch[0] public final int mSystemUiVisibility; // switch[1] - public final boolean mMenuVisible; // switch[2] public final int mImeWindowVis; // switch[3] public final int mImeBackDisposition; // switch[4] public final boolean mShowImeSwitcher; // switch[5] @@ -40,16 +39,18 @@ public final class RegisterStatusBarResult implements Parcelable { public final Rect mFullscreenStackBounds; public final Rect mDockedStackBounds; public final boolean mNavbarColorManagedByIme; + public final boolean mAppFullscreen; + public final boolean mAppImmersive; public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1, - int systemUiVisibility, boolean menuVisible, int imeWindowVis, int imeBackDisposition, + int systemUiVisibility, int imeWindowVis, int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, int fullscreenStackSysUiVisibility, int dockedStackSysUiVisibility, IBinder imeToken, Rect fullscreenStackBounds, - Rect dockedStackBounds, boolean navbarColorManagedByIme) { + Rect dockedStackBounds, boolean navbarColorManagedByIme, boolean appFullscreen, + boolean appImmersive) { mIcons = new ArrayMap<>(icons); mDisabledFlags1 = disabledFlags1; mSystemUiVisibility = systemUiVisibility; - mMenuVisible = menuVisible; mImeWindowVis = imeWindowVis; mImeBackDisposition = imeBackDisposition; mShowImeSwitcher = showImeSwitcher; @@ -60,6 +61,8 @@ public final class RegisterStatusBarResult implements Parcelable { mFullscreenStackBounds = fullscreenStackBounds; mDockedStackBounds = dockedStackBounds; mNavbarColorManagedByIme = navbarColorManagedByIme; + mAppFullscreen = appFullscreen; + mAppImmersive = appImmersive; } @Override @@ -72,7 +75,6 @@ public final class RegisterStatusBarResult implements Parcelable { dest.writeTypedArrayMap(mIcons, flags); dest.writeInt(mDisabledFlags1); dest.writeInt(mSystemUiVisibility); - dest.writeBoolean(mMenuVisible); dest.writeInt(mImeWindowVis); dest.writeInt(mImeBackDisposition); dest.writeBoolean(mShowImeSwitcher); @@ -83,6 +85,8 @@ public final class RegisterStatusBarResult implements Parcelable { dest.writeTypedObject(mFullscreenStackBounds, flags); dest.writeTypedObject(mDockedStackBounds, flags); dest.writeBoolean(mNavbarColorManagedByIme); + dest.writeBoolean(mAppFullscreen); + dest.writeBoolean(mAppImmersive); } /** @@ -96,7 +100,6 @@ public final class RegisterStatusBarResult implements Parcelable { source.createTypedArrayMap(StatusBarIcon.CREATOR); final int disabledFlags1 = source.readInt(); final int systemUiVisibility = source.readInt(); - final boolean menuVisible = source.readBoolean(); final int imeWindowVis = source.readInt(); final int imeBackDisposition = source.readInt(); final boolean showImeSwitcher = source.readBoolean(); @@ -107,11 +110,13 @@ public final class RegisterStatusBarResult implements Parcelable { final Rect fullscreenStackBounds = source.readTypedObject(Rect.CREATOR); final Rect dockedStackBounds = source.readTypedObject(Rect.CREATOR); final boolean navbarColorManagedByIme = source.readBoolean(); + final boolean appFullscreen = source.readBoolean(); + final boolean appImmersive = source.readBoolean(); return new RegisterStatusBarResult(icons, disabledFlags1, systemUiVisibility, - menuVisible, imeWindowVis, imeBackDisposition, showImeSwitcher, - disabledFlags2, fullscreenStackSysUiVisibility, - dockedStackSysUiVisibility, imeToken, fullscreenStackBounds, - dockedStackBounds, navbarColorManagedByIme); + imeWindowVis, imeBackDisposition, showImeSwitcher, disabledFlags2, + fullscreenStackSysUiVisibility, dockedStackSysUiVisibility, imeToken, + fullscreenStackBounds, dockedStackBounds, navbarColorManagedByIme, + appFullscreen, appImmersive); } @Override diff --git a/core/java/com/android/internal/view/AppearanceRegion.aidl b/core/java/com/android/internal/view/AppearanceRegion.aidl new file mode 100644 index 000000000000..1638bf5bbfd6 --- /dev/null +++ b/core/java/com/android/internal/view/AppearanceRegion.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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 com.android.internal.view; + +parcelable AppearanceRegion; diff --git a/core/java/com/android/internal/view/AppearanceRegion.java b/core/java/com/android/internal/view/AppearanceRegion.java new file mode 100644 index 000000000000..1a0cb4b0dfbf --- /dev/null +++ b/core/java/com/android/internal/view/AppearanceRegion.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2019 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 com.android.internal.view; + +import android.annotation.NonNull; +import android.graphics.Rect; +import android.os.Parcelable; +import android.view.InsetsFlags; +import android.view.ViewDebug; + +import com.android.internal.util.DataClass; + +/** + * Specifies which region applies which appearance. + */ +@DataClass +public class AppearanceRegion implements Parcelable { + + private int mAppearance; + private @NonNull Rect mBounds; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final AppearanceRegion sa = (AppearanceRegion) o; + return mAppearance == sa.mAppearance && mBounds.equals(sa.mBounds); + } + + @Override + public String toString() { + final String appearanceString = + ViewDebug.flagsToString(InsetsFlags.class, "appearance", mAppearance); + return "AppearanceRegion{" + appearanceString + " bounds=" + mBounds.toShortString() + "}"; + } + + + + // Code below generated by codegen v1.0.7. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/view/AppearanceRegion.java + + + @DataClass.Generated.Member + public AppearanceRegion( + int appearance, + @NonNull Rect bounds) { + this.mAppearance = appearance; + this.mBounds = bounds; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mBounds); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public int getAppearance() { + return mAppearance; + } + + @DataClass.Generated.Member + public @NonNull Rect getBounds() { + return mBounds; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeInt(mAppearance); + dest.writeTypedObject(mBounds, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected AppearanceRegion(android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + int appearance = in.readInt(); + Rect bounds = (Rect) in.readTypedObject(Rect.CREATOR); + + this.mAppearance = appearance; + this.mBounds = bounds; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mBounds); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<AppearanceRegion> CREATOR + = new Parcelable.Creator<AppearanceRegion>() { + @Override + public AppearanceRegion[] newArray(int size) { + return new AppearanceRegion[size]; + } + + @Override + public AppearanceRegion createFromParcel(android.os.Parcel in) { + return new AppearanceRegion(in); + } + }; + + @DataClass.Generated( + time = 1570909617357L, + codegenVersion = "1.0.7", + sourceFile = "frameworks/base/core/java/com/android/internal/view/AppearanceRegion.java", + inputSignatures = "private int mAppearance\nprivate @android.annotation.NonNull android.graphics.Rect mBounds\npublic @java.lang.Override boolean equals(java.lang.Object)\npublic @java.lang.Override java.lang.String toString()\nclass AppearanceRegion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass") + @Deprecated + private void __metadata() {} + +} diff --git a/core/tests/coretests/src/android/view/InsetsFlagsTest.java b/core/tests/coretests/src/android/view/InsetsFlagsTest.java new file mode 100644 index 000000000000..7d4445ba456a --- /dev/null +++ b/core/tests/coretests/src/android/view/InsetsFlagsTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 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.InsetsFlags.getAppearance; +import static android.view.View.NAVIGATION_BAR_TRANSLUCENT; +import static android.view.View.NAVIGATION_BAR_TRANSPARENT; +import static android.view.View.STATUS_BAR_TRANSLUCENT; +import static android.view.View.STATUS_BAR_TRANSPARENT; +import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; +import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; +import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_SIDE_BARS; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_TOP_BAR; +import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; +import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_SIDE_BARS; +import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_TOP_BAR; + +import static org.junit.Assert.assertTrue; + +import android.platform.test.annotations.Presubmit; +import android.view.WindowInsetsController.Appearance; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link InsetsFlags}. + * + * <p>Build/Install/Run: + * atest FrameworksCoreTests:InsetsFlagsTest + * + * <p>This test class is a part of Window Manager Service tests and specified in + * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. + */ +@Presubmit +@RunWith(AndroidJUnit4.class) +public class InsetsFlagsTest { + + @Test + public void testGetAppearance() { + assertContainsAppearance(APPEARANCE_LOW_PROFILE_BARS, SYSTEM_UI_FLAG_LOW_PROFILE); + assertContainsAppearance(APPEARANCE_LIGHT_TOP_BAR, SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + assertContainsAppearance(APPEARANCE_LIGHT_SIDE_BARS, SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); + assertContainsAppearance(APPEARANCE_OPAQUE_TOP_BAR, + 0xffffffff & ~(STATUS_BAR_TRANSLUCENT | STATUS_BAR_TRANSPARENT)); + assertContainsAppearance(APPEARANCE_OPAQUE_SIDE_BARS, + 0xffffffff & ~(NAVIGATION_BAR_TRANSLUCENT | NAVIGATION_BAR_TRANSPARENT)); + } + + void assertContainsAppearance(@Appearance int appearance, int systemUiVisibility) { + assertTrue((getAppearance(systemUiVisibility) & appearance) == appearance); + } +} diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java index b93c3a7a17e2..0be5009f85f0 100644 --- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java +++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java @@ -48,7 +48,6 @@ public class RegisterStatusBarResultTest { final RegisterStatusBarResult original = new RegisterStatusBarResult(iconMap, 0x2 /* disabledFlags1 */, 0x4 /* systemUiVisibility */, - true /* menuVisible */, 0x8 /* imeWindowVis */, 0x10 /* imeBackDisposition */, false /* showImeSwitcher */, @@ -58,7 +57,9 @@ public class RegisterStatusBarResultTest { new Binder() /* imeToken */, new Rect(0x100, 0x200, 0x400, 0x800) /* fullscreenStackBounds */, new Rect(0x1000, 0x2000, 0x4000, 0x8000) /* dockedStackBounds */, - true /* navbarColorManagedByIme */); + true /* navbarColorManagedByIme */, + true /* appFullscreen */, + true /* appImmersive */); final RegisterStatusBarResult copy = clone(original); @@ -69,7 +70,6 @@ public class RegisterStatusBarResultTest { assertThat(copy.mDisabledFlags1).isEqualTo(original.mDisabledFlags1); assertThat(copy.mSystemUiVisibility).isEqualTo(original.mSystemUiVisibility); - assertThat(copy.mMenuVisible).isEqualTo(original.mMenuVisible); assertThat(copy.mImeWindowVis).isEqualTo(original.mImeWindowVis); assertThat(copy.mImeBackDisposition).isEqualTo(original.mImeBackDisposition); assertThat(copy.mShowImeSwitcher).isEqualTo(original.mShowImeSwitcher); @@ -82,6 +82,8 @@ public class RegisterStatusBarResultTest { assertThat(copy.mFullscreenStackBounds).isEqualTo(original.mFullscreenStackBounds); assertThat(copy.mDockedStackBounds).isEqualTo(original.mDockedStackBounds); assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme); + assertThat(copy.mAppFullscreen).isEqualTo(original.mAppFullscreen); + assertThat(copy.mAppImmersive).isEqualTo(original.mAppImmersive); } private RegisterStatusBarResult clone(RegisterStatusBarResult original) { diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java index fe547a0a16fa..208d3b62d7b2 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java @@ -95,11 +95,6 @@ public interface StatusBarStateController { default void onDozeAmountChanged(float linear, float eased) {} /** - * Callback to be notified when the sysui visibility changes - */ - default void onSystemUiVisibilityChanged(int visibility) {} - - /** * Callback to be notified when the pulsing state changes */ default void onPulsingChanged(boolean pulsing) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index d6a8f906197d..c9dc08e78afb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -22,6 +22,8 @@ import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEF import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; +import static android.view.InsetsState.TYPE_NAVIGATION_BAR; +import static android.view.InsetsState.TYPE_TOP_BAR; import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS; @@ -43,12 +45,17 @@ import android.os.Looper; import android.os.Message; import android.util.Pair; import android.util.SparseArray; +import android.view.InsetsFlags; +import android.view.InsetsState.InternalInsetType; +import android.view.View; +import android.view.WindowInsetsController.Appearance; import androidx.annotation.VisibleForTesting; import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.view.AppearanceRegion; import com.android.systemui.SystemUI; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.policy.CallbackController; @@ -76,7 +83,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< private static final int MSG_EXPAND_NOTIFICATIONS = 3 << MSG_SHIFT; private static final int MSG_COLLAPSE_PANELS = 4 << MSG_SHIFT; private static final int MSG_EXPAND_SETTINGS = 5 << MSG_SHIFT; - private static final int MSG_SET_SYSTEMUI_VISIBILITY = 6 << MSG_SHIFT; + private static final int MSG_SYSTEM_BAR_APPEARANCE_CHANGED = 6 << MSG_SHIFT; private static final int MSG_DISPLAY_READY = 7 << MSG_SHIFT; private static final int MSG_SHOW_IME_BUTTON = 8 << MSG_SHIFT; private static final int MSG_TOGGLE_RECENT_APPS = 9 << MSG_SHIFT; @@ -115,6 +122,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< private static final int MSG_SHOW_PINNING_TOAST_ENTER_EXIT = 45 << MSG_SHIFT; private static final int MSG_SHOW_PINNING_TOAST_ESCAPE = 46 << MSG_SHIFT; private static final int MSG_RECENTS_ANIMATION_STATE_CHANGED = 47 << MSG_SHIFT; + private static final int MSG_SHOW_TRANSIENT = 48 << MSG_SHIFT; + private static final int MSG_ABORT_TRANSIENT = 49 << MSG_SHIFT; + private static final int MSG_TOP_APP_WINDOW_CHANGED = 50 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -160,28 +170,6 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< default void animateExpandSettingsPanel(String obj) { } /** - * Called to notify visibility flag changes. - * @see IStatusBar#setSystemUiVisibility(int, int, int, int, int, Rect, Rect). - * - * @param displayId The id of the display to notify. - * @param vis The visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will - * be reported separately in fullscreenStackVis and dockedStackVis. - * @param fullscreenStackVis The flags which only apply in the region of the fullscreen - * stack, which is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR. - * @param dockedStackVis The flags that only apply in the region of the docked stack, which - * is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR. - * @param mask Which flags to change. - * @param fullscreenStackBounds The current bounds of the fullscreen stack, in screen - * coordinates. - * @param dockedStackBounds The current bounds of the docked stack, in screen coordinates. - * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME. - */ - default void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, - boolean navbarColorManagedByIme) { - } - - /** * Called to notify IME window status changes. * * @param displayId The id of the display to notify. @@ -292,6 +280,28 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< * @see IStatusBar#onRecentsAnimationStateChanged(boolean) */ default void onRecentsAnimationStateChanged(boolean running) { } + + /** + * @see IStatusBar#onSystemBarAppearanceChanged(int, int, AppearanceRegion[], boolean). + */ + default void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance, + AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { } + + /** + * @see IStatusBar#showTransient(int, int[]). + */ + default void showTransient(int displayId, @InternalInsetType int[] types) { } + + /** + * @see IStatusBar#abortTransient(int, int[]). + */ + default void abortTransient(int displayId, @InternalInsetType int[] types) { } + + /** + * @see IStatusBar#topAppWindowChanged(int, boolean, boolean). + */ + default void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) { + } } @VisibleForTesting @@ -456,28 +466,53 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } } + // TODO(b/118118435): Remove this function after migration @Override public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean navbarColorManagedByIme) { synchronized (mLock) { - // Don't coalesce these, since it might have one time flags set such as - // STATUS_BAR_UNHIDE which might get lost. + final boolean hasDockedStack = !dockedStackBounds.isEmpty(); + final boolean transientStatus = (vis & View.STATUS_BAR_TRANSIENT) != 0; + final boolean transientNavigation = (vis & View.NAVIGATION_BAR_TRANSIENT) != 0; + if (transientStatus && transientNavigation) { + showTransient(displayId, new int[]{TYPE_TOP_BAR, TYPE_NAVIGATION_BAR}); + } else if (transientStatus) { + showTransient(displayId, new int[]{TYPE_TOP_BAR}); + abortTransient(displayId, new int[]{TYPE_NAVIGATION_BAR}); + } else if (transientNavigation) { + showTransient(displayId, new int[]{TYPE_NAVIGATION_BAR}); + abortTransient(displayId, new int[]{TYPE_TOP_BAR}); + } else { + abortTransient(displayId, new int[]{TYPE_TOP_BAR, TYPE_NAVIGATION_BAR}); + } SomeArgs args = SomeArgs.obtain(); args.argi1 = displayId; - args.argi2 = vis; - args.argi3 = fullscreenStackVis; - args.argi4 = dockedStackVis; - args.argi5 = mask; - args.argi6 = navbarColorManagedByIme ? 1 : 0; - args.arg1 = fullscreenStackBounds; - args.arg2 = dockedStackBounds; - mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget(); + args.argi2 = InsetsFlags.getAppearance(vis); + args.argi3 = navbarColorManagedByIme ? 1 : 0; + final int fullscreenAppearance = InsetsFlags.getAppearance(fullscreenStackVis); + final int dockedAppearance = InsetsFlags.getAppearance(dockedStackVis); + args.arg1 = hasDockedStack + ? new AppearanceRegion[]{ + new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds), + new AppearanceRegion(dockedAppearance, dockedStackBounds)} + : new AppearanceRegion[]{ + new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds)}; + mHandler.obtainMessage(MSG_SYSTEM_BAR_APPEARANCE_CHANGED, args).sendToTarget(); } } @Override - public void topAppWindowChanged(int displayId, boolean menuVisible) { } + public void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) { + synchronized (mLock) { + SomeArgs args = SomeArgs.obtain(); + args.argi1 = displayId; + args.argi2 = isFullscreen ? 1 : 0; + args.argi3 = isImmersive ? 1 : 0; + mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, args).sendToTarget(); + } + + } @Override public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, @@ -827,6 +862,33 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } } + @Override + public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance, + AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { + synchronized (mLock) { + SomeArgs args = SomeArgs.obtain(); + args.argi1 = displayId; + args.argi2 = appearance; + args.argi3 = navbarColorManagedByIme ? 1 : 0; + args.arg1 = appearanceRegions; + mHandler.obtainMessage(MSG_SYSTEM_BAR_APPEARANCE_CHANGED, args).sendToTarget(); + } + } + + @Override + public void showTransient(int displayId, int[] types) { + synchronized (mLock) { + mHandler.obtainMessage(MSG_SHOW_TRANSIENT, displayId, 0, types).sendToTarget(); + } + } + + @Override + public void abortTransient(int displayId, int[] types) { + synchronized (mLock) { + mHandler.obtainMessage(MSG_ABORT_TRANSIENT, displayId, 0, types).sendToTarget(); + } + } + private final class H extends Handler { private H(Looper l) { super(l); @@ -879,15 +941,6 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< mCallbacks.get(i).animateExpandSettingsPanel((String) msg.obj); } break; - case MSG_SET_SYSTEMUI_VISIBILITY: - args = (SomeArgs) msg.obj; - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).setSystemUiVisibility(args.argi1, args.argi2, args.argi3, - args.argi4, args.argi5, (Rect) args.arg1, (Rect) args.arg2, - args.argi6 == 1); - } - args.recycle(); - break; case MSG_SHOW_IME_BUTTON: args = (SomeArgs) msg.obj; handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */, @@ -1094,6 +1147,39 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< mCallbacks.get(i).onRecentsAnimationStateChanged(msg.arg1 > 0); } break; + case MSG_SYSTEM_BAR_APPEARANCE_CHANGED: + args = (SomeArgs) msg.obj; + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).onSystemBarAppearanceChanged(args.argi1, args.argi2, + (AppearanceRegion[]) args.arg1, args.argi3 == 1); + } + args.recycle(); + break; + case MSG_SHOW_TRANSIENT: { + final int displayId = msg.arg1; + final int[] types = (int[]) msg.obj; + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).showTransient(displayId, types); + } + break; + } + case MSG_ABORT_TRANSIENT: { + final int displayId = msg.arg1; + final int[] types = (int[]) msg.obj; + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).abortTransient(displayId, types); + } + break; + } + case MSG_TOP_APP_WINDOW_CHANGED: { + args = (SomeArgs) msg.obj; + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).topAppWindowChanged( + args.argi1, args.argi2 != 0, args.argi3 != 0); + } + args.recycle(); + break; + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java index 5144a95a0a51..275475d6d72c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java @@ -156,7 +156,7 @@ public class NavigationBarController implements Callbacks { Dependency.get(NotificationRemoteInputManager.class), Dependency.get(IWindowManager.class)); navBar.setAutoHideController(autoHideController); - navBar.restoreSystemUiVisibilityState(); + navBar.restoreAppearanceAndTransientState(); mNavigationBars.append(displayId, navBar); if (result != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 8b9268e1888a..46a12330f6d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -320,18 +320,6 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll } @Override - public void setSystemUiVisibility(int visibility) { - if (mSystemUiVisibility != visibility) { - mSystemUiVisibility = visibility; - synchronized (mListeners) { - for (RankedListener rl : new ArrayList<>(mListeners)) { - rl.mListener.onSystemUiVisibilityChanged(mSystemUiVisibility); - } - } - } - } - - @Override public void setPulsing(boolean pulsing) { if (mPulsing != pulsing) { mPulsing = pulsing; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java index 2ad979ab64e3..50ab8a8abe16 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java @@ -111,11 +111,6 @@ public interface SysuiStatusBarStateController extends StatusBarStateController boolean isKeyguardRequested(); /** - * Set systemui visibility - */ - void setSystemUiVisibility(int visibility); - - /** * Set pulsing */ void setPulsing(boolean visibility); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java index 175d072e4c8b..008464e543a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java @@ -17,52 +17,39 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.Dependency.MAIN_HANDLER_NAME; -import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; import android.content.Context; -import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; import android.util.Log; import android.view.IWindowManager; import android.view.MotionEvent; -import android.view.View; -import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.SysUiServiceProvider; -import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationRemoteInputManager; import javax.inject.Inject; import javax.inject.Named; /** A controller to control all auto-hide things. */ -public class AutoHideController implements CommandQueue.Callbacks { +public class AutoHideController { private static final String TAG = "AutoHideController"; private final IWindowManager mWindowManagerService; private final Handler mHandler; private final NotificationRemoteInputManager mRemoteInputManager; - private final CommandQueue mCommandQueue; private StatusBar mStatusBar; private NavigationBarFragment mNavigationBar; - @VisibleForTesting - int mDisplayId; - @VisibleForTesting - int mSystemUiVisibility; - // last value sent to window manager - private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE; + private int mDisplayId; private boolean mAutoHideSuspended; - private static final long AUTOHIDE_TIMEOUT_MS = 2250; + private static final long AUTO_HIDE_TIMEOUT_MS = 2250; private final Runnable mAutoHide = () -> { - int requested = mSystemUiVisibility & ~getTransientMask(); - if (mSystemUiVisibility != requested) { - notifySystemUiVisibilityChanged(requested); + if (isAnyTransientBarShown()) { + hideTransientBars(); } }; @@ -70,8 +57,6 @@ public class AutoHideController implements CommandQueue.Callbacks { public AutoHideController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler, NotificationRemoteInputManager notificationRemoteInputManager, IWindowManager iWindowManager) { - mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class); - mCommandQueue.addCallback(this); mHandler = handler; mRemoteInputManager = notificationRemoteInputManager; mWindowManagerService = iWindowManager; @@ -79,13 +64,6 @@ public class AutoHideController implements CommandQueue.Callbacks { mDisplayId = context.getDisplayId(); } - @Override - public void onDisplayRemoved(int displayId) { - if (displayId == mDisplayId) { - mCommandQueue.removeCallback(this); - } - } - void setStatusBar(StatusBar statusBar) { mStatusBar = statusBar; } @@ -94,50 +72,18 @@ public class AutoHideController implements CommandQueue.Callbacks { mNavigationBar = navigationBar; } - @Override - public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, - boolean navbarColorManagedByIme) { - if (displayId != mDisplayId) { - return; - } - int oldVal = mSystemUiVisibility; - int newVal = (oldVal & ~mask) | (vis & mask); - int diff = newVal ^ oldVal; - - if (diff != 0) { - mSystemUiVisibility = newVal; - - // ready to unhide - if (hasStatusBar() && (vis & View.STATUS_BAR_UNHIDE) != 0) { - mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE; - } - - if (hasNavigationBar() && (vis & View.NAVIGATION_BAR_UNHIDE) != 0) { - mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; - } - - // Re-send setSystemUiVisibility to update un-hide status. - if (mSystemUiVisibility != newVal) { - mCommandQueue.setSystemUiVisibility(mDisplayId, mSystemUiVisibility, - fullscreenStackVis, dockedStackVis, mask, fullscreenStackBounds, - dockedStackBounds, navbarColorManagedByIme); - } - - notifySystemUiVisibilityChanged(mSystemUiVisibility); - } - } - - @VisibleForTesting - void notifySystemUiVisibilityChanged(int vis) { + private void hideTransientBars() { try { - if (mLastDispatchedSystemUiVisibility != vis) { - mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis); - mLastDispatchedSystemUiVisibility = vis; - } + mWindowManagerService.hideTransientBars(mDisplayId); } catch (RemoteException ex) { Log.w(TAG, "Cannot get WindowManager"); } + if (mStatusBar != null) { + mStatusBar.clearTransient(); + } + if (mNavigationBar != null) { + mNavigationBar.clearTransient(); + } } void resumeSuspendedAutoHide() { @@ -156,13 +102,12 @@ public class AutoHideController implements CommandQueue.Callbacks { if (checkBarModesRunnable != null) { mHandler.removeCallbacks(checkBarModesRunnable); } - mAutoHideSuspended = (mSystemUiVisibility & getTransientMask()) != 0; + mAutoHideSuspended = isAnyTransientBarShown(); } void touchAutoHide() { // update transient bar auto hide - if ((hasStatusBar() && mStatusBar.getStatusBarMode() == MODE_SEMI_TRANSPARENT) - || hasNavigationBar() && mNavigationBar.isSemiTransparent()) { + if (isAnyTransientBarShown()) { scheduleAutoHide(); } else { cancelAutoHide(); @@ -170,9 +115,9 @@ public class AutoHideController implements CommandQueue.Callbacks { } private Runnable getCheckBarModesRunnable() { - if (hasStatusBar()) { + if (mStatusBar != null) { return () -> mStatusBar.checkBarModes(); - } else if (hasNavigationBar()) { + } else if (mNavigationBar != null) { return () -> mNavigationBar.checkNavBarModes(); } else { return null; @@ -186,15 +131,14 @@ public class AutoHideController implements CommandQueue.Callbacks { private void scheduleAutoHide() { cancelAutoHide(); - mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS); + mHandler.postDelayed(mAutoHide, AUTO_HIDE_TIMEOUT_MS); } void checkUserAutoHide(MotionEvent event) { - boolean shouldAutoHide = - (mSystemUiVisibility & getTransientMask()) != 0 // a transient bar is revealed. + boolean shouldAutoHide = isAnyTransientBarShown() && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar. && event.getX() == 0 && event.getY() == 0; - if (hasStatusBar()) { + if (mStatusBar != null) { // a touch outside both bars shouldAutoHide &= !mRemoteInputManager.getController().isRemoteInputActive(); } @@ -208,23 +152,8 @@ public class AutoHideController implements CommandQueue.Callbacks { mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear } - private int getTransientMask() { - int mask = 0; - if (hasStatusBar()) { - mask |= View.STATUS_BAR_TRANSIENT; - } - if (hasNavigationBar()) { - mask |= View.NAVIGATION_BAR_TRANSIENT; - } - return mask; - } - - boolean hasNavigationBar() { - return mNavigationBar != null; - } - - @VisibleForTesting - boolean hasStatusBar() { - return mStatusBar != null; + private boolean isAnyTransientBarShown() { + return (mStatusBar != null && mStatusBar.isTransientShown()) + || mNavigationBar != null && mNavigationBar.isTransientShown(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java index 211a40a91101..e6731e6b8a34 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java @@ -44,11 +44,11 @@ public class BarTransitions { private static final boolean DEBUG = false; private static final boolean DEBUG_COLORS = false; - public static final int MODE_OPAQUE = 0; + public static final int MODE_TRANSPARENT = 0; public static final int MODE_SEMI_TRANSPARENT = 1; public static final int MODE_TRANSLUCENT = 2; public static final int MODE_LIGHTS_OUT = 3; - public static final int MODE_TRANSPARENT = 4; + public static final int MODE_OPAQUE = 4; public static final int MODE_WARNING = 5; public static final int MODE_LIGHTS_OUT_TRANSPARENT = 6; @@ -72,7 +72,7 @@ public class BarTransitions { private final View mView; protected final BarBackgroundDrawable mBarBackground; - private int mMode; + private @TransitionMode int mMode; private boolean mAlwaysOpaque = false; public BarTransitions(View view, int gradientResourceId) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index 442c08991581..c9c38a0ef5f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -16,8 +16,6 @@ package com.android.systemui.statusbar.phone; import static android.view.Display.INVALID_DISPLAY; -import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; -import static android.view.View.NAVIGATION_BAR_TRANSIENT; import android.content.Context; import android.content.res.Resources; @@ -133,7 +131,7 @@ public class EdgeBackGestureHandler implements DisplayListener { private boolean mIsAttached; private boolean mIsGesturalModeEnabled; private boolean mIsEnabled; - private boolean mIsInTransientImmersiveStickyState; + private boolean mIsNavBarShownTransiently; private InputMonitor mInputMonitor; private InputEventReceiver mInputEventReceiver; @@ -198,10 +196,8 @@ public class EdgeBackGestureHandler implements DisplayListener { updateCurrentUserResources(currentUserContext.getResources()); } - public void onSystemUiVisibilityChanged(int systemUiVisibility) { - mIsInTransientImmersiveStickyState = - (systemUiVisibility & SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0 - && (systemUiVisibility & NAVIGATION_BAR_TRANSIENT) != 0; + public void onNavBarTransientStateChanged(boolean isTransient) { + mIsNavBarShownTransiently = isTransient; } private void disposeInputChannel() { @@ -316,7 +312,7 @@ public class EdgeBackGestureHandler implements DisplayListener { } // Always allow if the user is in a transient sticky immersive state - if (mIsInTransientImmersiveStickyState) { + if (mIsNavBarShownTransiently) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index b0b656a1a951..2e776e39b54c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -16,15 +16,20 @@ package com.android.systemui.statusbar.phone; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_SIDE_BARS; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_TOP_BAR; + import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; import android.content.Context; import android.graphics.Color; -import android.graphics.Rect; -import android.view.View; +import android.view.InsetsFlags; +import android.view.ViewDebug; +import android.view.WindowInsetsController.Appearance; import com.android.internal.colorextraction.ColorExtractor.GradientColors; +import com.android.internal.view.AppearanceRegion; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.plugins.DarkIconDispatcher; @@ -49,13 +54,10 @@ public class LightBarController implements BatteryController.BatteryStateChangeC private BiometricUnlockController mBiometricUnlockController; private LightBarTransitionsController mNavigationBarController; - private int mSystemUiVisibility; - private int mFullscreenStackVisibility; - private int mDockedStackVisibility; - private boolean mFullscreenLight; - private boolean mDockedLight; - private int mLastStatusBarMode; - private int mLastNavigationBarMode; + private @Appearance int mAppearance; + private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0]; + private int mStatusBarMode; + private int mNavigationBarMode; private final Color mDarkModeColor; /** @@ -75,8 +77,6 @@ public class LightBarController implements BatteryController.BatteryStateChangeC */ private boolean mForceDarkForScrim; - private final Rect mLastFullscreenBounds = new Rect(); - private final Rect mLastDockedBounds = new Rect(); private boolean mQsCustomizing; private boolean mDirectReplying; @@ -101,45 +101,32 @@ public class LightBarController implements BatteryController.BatteryStateChangeC mBiometricUnlockController = biometricUnlockController; } - public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis, - int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged, + void onStatusBarAppearanceChanged(AppearanceRegion[] appearanceRegions, boolean sbModeChanged, int statusBarMode, boolean navbarColorManagedByIme) { - int oldFullscreen = mFullscreenStackVisibility; - int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask); - int diffFullscreen = newFullscreen ^ oldFullscreen; - int oldDocked = mDockedStackVisibility; - int newDocked = (oldDocked & ~mask) | (dockedStackVis & mask); - int diffDocked = newDocked ^ oldDocked; - if ((diffFullscreen & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 - || (diffDocked & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 - || sbModeChanged - || !mLastFullscreenBounds.equals(fullscreenStackBounds) - || !mLastDockedBounds.equals(dockedStackBounds)) { - - mFullscreenLight = isLight(newFullscreen, statusBarMode, - View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); - mDockedLight = isLight(newDocked, statusBarMode, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); - updateStatus(fullscreenStackBounds, dockedStackBounds); + final int numStacks = appearanceRegions.length; + boolean stackAppearancesChanged = mAppearanceRegions.length != numStacks; + for (int i = 0; i < numStacks && !stackAppearancesChanged; i++) { + stackAppearancesChanged |= !appearanceRegions[i].equals(mAppearanceRegions[i]); + } + if (stackAppearancesChanged || sbModeChanged) { + mAppearanceRegions = appearanceRegions; + onStatusBarModeChanged(statusBarMode); } - - mFullscreenStackVisibility = newFullscreen; - mDockedStackVisibility = newDocked; - mLastStatusBarMode = statusBarMode; mNavbarColorManagedByIme = navbarColorManagedByIme; - mLastFullscreenBounds.set(fullscreenStackBounds); - mLastDockedBounds.set(dockedStackBounds); } - public void onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged, + void onStatusBarModeChanged(int newBarMode) { + mStatusBarMode = newBarMode; + updateStatus(); + } + + void onNavigationBarAppearanceChanged(@Appearance int appearance, boolean nbModeChanged, int navigationBarMode, boolean navbarColorManagedByIme) { - int oldVis = mSystemUiVisibility; - int newVis = (oldVis & ~mask) | (vis & mask); - int diffVis = newVis ^ oldVis; - if ((diffVis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0 - || nbModeChanged) { - boolean last = mNavigationLight; - mHasLightNavigationBar = isLight(vis, navigationBarMode, - View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); + int diff = appearance ^ mAppearance; + if ((diff & APPEARANCE_LIGHT_SIDE_BARS) != 0 || nbModeChanged) { + final boolean last = mNavigationLight; + mHasLightNavigationBar = isLight(appearance, navigationBarMode, + APPEARANCE_LIGHT_SIDE_BARS); mNavigationLight = mHasLightNavigationBar && (mDirectReplying && mNavbarColorManagedByIme || !mForceDarkForScrim) && !mQsCustomizing; @@ -147,17 +134,20 @@ public class LightBarController implements BatteryController.BatteryStateChangeC updateNavigation(); } } - mSystemUiVisibility = newVis; - mLastNavigationBarMode = navigationBarMode; + mAppearance = appearance; + mNavigationBarMode = navigationBarMode; mNavbarColorManagedByIme = navbarColorManagedByIme; } + void onNavigationBarModeChanged(int newBarMode) { + mHasLightNavigationBar = isLight(mAppearance, newBarMode, APPEARANCE_LIGHT_SIDE_BARS); + } + private void reevaluate() { - onSystemUiVisibilityChanged(mFullscreenStackVisibility, - mDockedStackVisibility, 0 /* mask */, mLastFullscreenBounds, mLastDockedBounds, - true /* sbModeChange*/, mLastStatusBarMode, mNavbarColorManagedByIme); - onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, true /* nbModeChanged */, - mLastNavigationBarMode, mNavbarColorManagedByIme); + onStatusBarAppearanceChanged(mAppearanceRegions, true /* sbModeChange */, mStatusBarMode, + mNavbarColorManagedByIme); + onNavigationBarAppearanceChanged(mAppearance, true /* nbModeChanged */, + mNavigationBarMode, mNavbarColorManagedByIme); } public void setQsCustomizing(boolean customizing) { @@ -191,10 +181,10 @@ public class LightBarController implements BatteryController.BatteryStateChangeC } } - private boolean isLight(int vis, int barMode, int flag) { - boolean isTransparentBar = (barMode == MODE_TRANSPARENT + private static boolean isLight(int appearance, int barMode, int flag) { + final boolean isTransparentBar = (barMode == MODE_TRANSPARENT || barMode == MODE_LIGHTS_OUT_TRANSPARENT); - boolean light = (vis & flag) != 0; + final boolean light = (appearance & flag) != 0; return isTransparentBar && light; } @@ -207,49 +197,49 @@ public class LightBarController implements BatteryController.BatteryStateChangeC && unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK; } - private void updateStatus(Rect fullscreenStackBounds, Rect dockedStackBounds) { - boolean hasDockedStack = !dockedStackBounds.isEmpty(); + private void updateStatus() { + final int numStacks = mAppearanceRegions.length; + int numLightStacks = 0; + + // We can only have maximum one light stack. + int indexLightStack = -1; - // If both are light or fullscreen is light and there is no docked stack, all icons get - // dark. - if ((mFullscreenLight && mDockedLight) || (mFullscreenLight && !hasDockedStack)) { + for (int i = 0; i < numStacks; i++) { + if (isLight(mAppearanceRegions[i].getAppearance(), mStatusBarMode, + APPEARANCE_LIGHT_TOP_BAR)) { + numLightStacks++; + indexLightStack = i; + } + } + + // If all stacks are light, all icons get dark. + if (numLightStacks == numStacks) { mStatusBarIconController.setIconsDarkArea(null); mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange()); } - // If no one is light or the fullscreen is not light and there is no docked stack, - // all icons become white. - else if ((!mFullscreenLight && !mDockedLight) || (!mFullscreenLight && !hasDockedStack)) { + // If no one is light, all icons become white. + else if (numLightStacks == 0) { mStatusBarIconController.getTransitionsController().setIconsDark( false, animateChange()); } // Not the same for every stack, magic! else { - Rect bounds = mFullscreenLight ? fullscreenStackBounds : dockedStackBounds; - if (bounds.isEmpty()) { - mStatusBarIconController.setIconsDarkArea(null); - } else { - mStatusBarIconController.setIconsDarkArea(bounds); - } + mStatusBarIconController.setIconsDarkArea( + mAppearanceRegions[indexLightStack].getBounds()); mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange()); } } private void updateNavigation() { if (mNavigationBarController != null) { - mNavigationBarController.setIconsDark( - mNavigationLight, animateChange()); + mNavigationBarController.setIconsDark(mNavigationLight, animateChange()); } } @Override - public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { - - } - - @Override public void onPowerSaveChanged(boolean isPowerSave) { reevaluate(); } @@ -257,24 +247,21 @@ public class LightBarController implements BatteryController.BatteryStateChangeC @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("LightBarController: "); - pw.print(" mSystemUiVisibility=0x"); pw.print( - Integer.toHexString(mSystemUiVisibility)); - pw.print(" mFullscreenStackVisibility=0x"); pw.print( - Integer.toHexString(mFullscreenStackVisibility)); - pw.print(" mDockedStackVisibility=0x"); pw.println( - Integer.toHexString(mDockedStackVisibility)); - - pw.print(" mFullscreenLight="); pw.print(mFullscreenLight); - pw.print(" mDockedLight="); pw.println(mDockedLight); - - pw.print(" mLastFullscreenBounds="); pw.print(mLastFullscreenBounds); - pw.print(" mLastDockedBounds="); pw.println(mLastDockedBounds); + pw.print(" mAppearance=0x"); pw.println(ViewDebug.flagsToString( + InsetsFlags.class, "appearance", mAppearance)); + final int numStacks = mAppearanceRegions.length; + for (int i = 0; i < numStacks; i++) { + final boolean isLight = isLight(mAppearanceRegions[i].getAppearance(), mStatusBarMode, + APPEARANCE_LIGHT_TOP_BAR); + pw.print(" stack #"); pw.print(i); pw.print(": "); + pw.print(mAppearanceRegions[i].toString()); pw.print(" isLight="); pw.println(isLight); + } pw.print(" mNavigationLight="); pw.print(mNavigationLight); pw.print(" mHasLightNavigationBar="); pw.println(mHasLightNavigationBar); - pw.print(" mLastStatusBarMode="); pw.print(mLastStatusBarMode); - pw.print(" mLastNavigationBarMode="); pw.println(mLastNavigationBarMode); + pw.print(" mStatusBarMode="); pw.print(mStatusBarMode); + pw.print(" mNavigationBarMode="); pw.println(mNavigationBarMode); pw.print(" mForceDarkForScrim="); pw.print(mForceDarkForScrim); pw.print(" mQsCustomizing="); pw.print(mQsCustomizing); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 38dc5ea4dcd5..7030dfc4c33b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -21,6 +21,10 @@ import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.WindowType; import static android.app.StatusBarManager.WindowVisibleState; import static android.app.StatusBarManager.windowStateToString; +import static android.view.InsetsState.TYPE_NAVIGATION_BAR; +import static android.view.InsetsState.containsType; +import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; +import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_SIDE_BARS; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; @@ -31,7 +35,6 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OU import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; -import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE; @@ -52,7 +55,6 @@ import android.content.IntentFilter; import android.content.res.Configuration; import android.database.ContentObserver; import android.graphics.PixelFormat; -import android.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.net.Uri; import android.os.Binder; @@ -67,12 +69,14 @@ import android.telecom.TelecomManager; import android.text.TextUtils; import android.util.Log; import android.view.Display; +import android.view.InsetsState.InternalInsetType; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewGroup; +import android.view.WindowInsetsController.Appearance; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityEvent; @@ -84,6 +88,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.LatencyTracker; +import com.android.internal.view.AppearanceRegion; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; @@ -128,7 +133,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private static final boolean DEBUG = false; private static final String EXTRA_DISABLE_STATE = "disabled_state"; private static final String EXTRA_DISABLE2_STATE = "disabled2_state"; - private static final String EXTRA_SYSTEM_UI_VISIBILITY = "system_ui_visibility"; + private static final String EXTRA_APPEARANCE = "appearance"; + private static final String EXTRA_TRANSIENT_STATE = "transient_state"; /** Allow some time inbetween the long press for back and recents. */ private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; @@ -165,7 +171,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private Locale mLocale; private int mLayoutDirection; - private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; + /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */ + private @Appearance int mAppearance; + + private boolean mTransientShown; private int mNavBarMode = NAV_BAR_MODE_3BUTTON; private LightBarController mLightBarController; private AutoHideController mAutoHideController; @@ -295,7 +304,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback if (savedInstanceState != null) { mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0); mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0); - mSystemUiVisibility = savedInstanceState.getInt(EXTRA_SYSTEM_UI_VISIBILITY, 0); + mAppearance = savedInstanceState.getInt(EXTRA_APPEARANCE, 0); + mTransientShown = savedInstanceState.getBoolean(EXTRA_TRANSIENT_STATE, false); } mAccessibilityManagerWrapper.addCallback(mAccessibilityListener); @@ -397,7 +407,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback super.onSaveInstanceState(outState); outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1); outState.putInt(EXTRA_DISABLE2_STATE, mDisabledFlags2); - outState.putInt(EXTRA_SYSTEM_UI_VISIBILITY, mSystemUiVisibility); + outState.putInt(EXTRA_APPEARANCE, mAppearance); + outState.putBoolean(EXTRA_TRANSIENT_STATE, mTransientShown); if (mNavigationBarView != null) { mNavigationBarView.getLightTransitionsController().saveState(outState); } @@ -518,80 +529,107 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback rotationButtonController.onRotationProposal(rotation, winRotation, isValid); } - /** Restores the System UI flags saved state to {@link NavigationBarFragment}. */ - public void restoreSystemUiVisibilityState() { - final int barMode = computeBarMode(0, mSystemUiVisibility); - if (barMode != -1) { - mNavigationBarMode = barMode; - } + /** Restores the appearance and the transient saved state to {@link NavigationBarFragment}. */ + public void restoreAppearanceAndTransientState() { + final int barMode = barMode(mTransientShown, mAppearance); + mNavigationBarMode = barMode; checkNavBarModes(); mAutoHideController.touchAutoHide(); - mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, - true /* nbModeChanged */, mNavigationBarMode, false /* navbarColorManagedByIme */); + mLightBarController.onNavigationBarAppearanceChanged(mAppearance, true /* nbModeChanged */, + barMode, false /* navbarColorManagedByIme */); } @Override - public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, - boolean navbarColorManagedByIme) { + public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance, + AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { if (displayId != mDisplayId) { return; } - final int oldVal = mSystemUiVisibility; - final int newVal = (oldVal & ~mask) | (vis & mask); - final int diff = newVal ^ oldVal; boolean nbModeChanged = false; - if (diff != 0) { - mSystemUiVisibility = newVal; - - // update navigation bar mode - final int nbMode = getView() == null - ? -1 : computeBarMode(oldVal, newVal); - nbModeChanged = nbMode != -1; - if (nbModeChanged) { - if (mNavigationBarMode != nbMode) { - if (mNavigationBarMode == MODE_TRANSPARENT - || mNavigationBarMode == MODE_LIGHTS_OUT_TRANSPARENT) { - mNavigationBarView.hideRecentsOnboarding(); - } - mNavigationBarMode = nbMode; - checkNavBarModes(); - } - mAutoHideController.touchAutoHide(); - } - if (mNavigationBarView != null) { - mNavigationBarView.onSystemUiVisibilityChanged(mSystemUiVisibility); + if (mAppearance != appearance) { + mAppearance = appearance; + if (getView() == null) { + return; } + nbModeChanged = updateBarMode(barMode(mTransientShown, appearance)); + } + mLightBarController.onNavigationBarAppearanceChanged(appearance, nbModeChanged, + mNavigationBarMode, navbarColorManagedByIme); + } + + @Override + public void showTransient(int displayId, @InternalInsetType int[] types) { + if (displayId != mDisplayId) { + return; + } + if (!containsType(types, TYPE_NAVIGATION_BAR)) { + return; + } + if (!mTransientShown) { + mTransientShown = true; + handleTransientChanged(); + } + } + + @Override + public void abortTransient(int displayId, @InternalInsetType int[] types) { + if (displayId != mDisplayId) { + return; + } + if (!containsType(types, TYPE_NAVIGATION_BAR)) { + return; + } + clearTransient(); + } + + void clearTransient() { + if (mTransientShown) { + mTransientShown = false; + handleTransientChanged(); } - mLightBarController.onNavigationVisibilityChanged( - vis, mask, nbModeChanged, mNavigationBarMode, navbarColorManagedByIme); } - private @TransitionMode int computeBarMode(int oldVis, int newVis) { - final int oldMode = barMode(oldVis); - final int newMode = barMode(newVis); - if (oldMode == newMode) { - return -1; // no mode change + private void handleTransientChanged() { + if (getView() == null) { + return; + } + if (mNavigationBarView != null) { + mNavigationBarView.onTransientStateChanged(mTransientShown); + } + final int barMode = barMode(mTransientShown, mAppearance); + if (updateBarMode(barMode)) { + mLightBarController.onNavigationBarModeChanged(barMode); } - return newMode; } - private @TransitionMode int barMode(int vis) { - final int lightsOutTransparent = - View.SYSTEM_UI_FLAG_LOW_PROFILE | View.NAVIGATION_BAR_TRANSIENT; - if ((vis & View.NAVIGATION_BAR_TRANSIENT) != 0) { + // Returns true if the bar mode is changed. + private boolean updateBarMode(int barMode) { + if (mNavigationBarMode != barMode) { + if (mNavigationBarMode == MODE_TRANSPARENT + || mNavigationBarMode == MODE_LIGHTS_OUT_TRANSPARENT) { + mNavigationBarView.hideRecentsOnboarding(); + } + mNavigationBarMode = barMode; + checkNavBarModes(); + mAutoHideController.touchAutoHide(); + return true; + } + return false; + } + + private static @TransitionMode int barMode(boolean isTransient, int appearance) { + final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_SIDE_BARS; + if (isTransient) { return MODE_SEMI_TRANSPARENT; - } else if ((vis & View.NAVIGATION_BAR_TRANSLUCENT) != 0) { - return MODE_TRANSLUCENT; - } else if ((vis & lightsOutTransparent) == lightsOutTransparent) { - return MODE_LIGHTS_OUT_TRANSPARENT; - } else if ((vis & View.NAVIGATION_BAR_TRANSPARENT) != 0) { - return MODE_TRANSPARENT; - } else if ((vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { + } else if ((appearance & lightsOutOpaque) == lightsOutOpaque) { return MODE_LIGHTS_OUT; - } else { + } else if ((appearance & APPEARANCE_LOW_PROFILE_BARS) != 0) { + return MODE_LIGHTS_OUT_TRANSPARENT; + } else if ((appearance & APPEARANCE_OPAQUE_SIDE_BARS) != 0) { return MODE_OPAQUE; + } else { + return MODE_TRANSPARENT; } } @@ -990,8 +1028,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mAutoHideController.setNavigationBar(this); } - public boolean isSemiTransparent() { - return mNavigationBarMode == MODE_SEMI_TRANSPARENT; + boolean isTransientShown() { + return mTransientShown; } private void checkBarModes() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 9804f9ff4698..fe951a7cc28d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -366,8 +366,8 @@ public class NavigationBarView extends FrameLayout implements return super.onTouchEvent(event); } - void onSystemUiVisibilityChanged(int systemUiVisibility) { - mEdgeBackGestureHandler.onSystemUiVisibilityChanged(systemUiVisibility); + void onTransientStateChanged(boolean isTransient) { + mEdgeBackGestureHandler.onNavBarTransientStateChanged(isTransient); } void onBarTransition(int newMode) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index d1fe46e9cefe..d2fa77594798 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -24,6 +24,11 @@ import static android.app.StatusBarManager.WindowType; import static android.app.StatusBarManager.WindowVisibleState; import static android.app.StatusBarManager.windowStateToString; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; +import static android.view.InsetsFlags.getAppearance; +import static android.view.InsetsState.TYPE_TOP_BAR; +import static android.view.InsetsState.containsType; +import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; +import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_TOP_BAR; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; import static com.android.systemui.Dependency.BG_HANDLER; @@ -75,7 +80,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; -import android.graphics.Rect; import android.media.AudioAttributes; import android.metrics.LogMaker; import android.net.Uri; @@ -104,6 +108,7 @@ import android.util.Log; import android.util.Slog; import android.view.Display; import android.view.IWindowManager; +import android.view.InsetsState.InternalInsetType; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -112,6 +117,7 @@ import android.view.ThreadedRenderer; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.view.WindowInsetsController.Appearance; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; @@ -124,6 +130,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.RegisterStatusBarResult; +import com.android.internal.view.AppearanceRegion; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; @@ -424,10 +431,13 @@ public class StatusBar extends SystemUI implements DemoMode, private int mDisabled1 = 0; private int mDisabled2 = 0; - // tracking calls to View.setSystemUiVisibility() - private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; - private final Rect mLastFullscreenStackBounds = new Rect(); - private final Rect mLastDockedStackBounds = new Rect(); + /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */ + private @Appearance int mAppearance; + + private boolean mTransientShown; + + private boolean mAppFullscreen; + private boolean mAppImmersive; private final DisplayMetrics mDisplayMetrics; @@ -819,10 +829,22 @@ public class StatusBar extends SystemUI implements DemoMode, // Set up the initial notification state. This needs to happen before CommandQueue.disable() setUpPresenter(); - setSystemUiVisibility(mDisplayId, result.mSystemUiVisibility, - result.mFullscreenStackSysUiVisibility, result.mDockedStackSysUiVisibility, - 0xffffffff, result.mFullscreenStackBounds, result.mDockedStackBounds, - result.mNavbarColorManagedByIme); + if ((result.mSystemUiVisibility & View.STATUS_BAR_TRANSIENT) != 0) { + showTransientUnchecked(); + } + final int fullscreenAppearance = getAppearance(result.mFullscreenStackSysUiVisibility); + final int dockedAppearance = getAppearance(result.mDockedStackSysUiVisibility); + final AppearanceRegion[] appearanceRegions = result.mDockedStackBounds.isEmpty() + ? new AppearanceRegion[]{ + new AppearanceRegion(fullscreenAppearance, result.mFullscreenStackBounds)} + : new AppearanceRegion[]{ + new AppearanceRegion(fullscreenAppearance, result.mFullscreenStackBounds), + new AppearanceRegion(dockedAppearance, result.mDockedStackBounds)}; + onSystemBarAppearanceChanged(mDisplayId, getAppearance(result.mSystemUiVisibility), + appearanceRegions, result.mNavbarColorManagedByIme); + mAppFullscreen = result.mAppFullscreen; + mAppImmersive = result.mAppImmersive; + // StatusBarManagerService has a back up of IME token and it's restored here. setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis, result.mImeBackDisposition, result.mShowImeSwitcher); @@ -2222,49 +2244,103 @@ public class StatusBar extends SystemUI implements DemoMode, } } - @Override // CommandQueue - public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, - boolean navbarColorManagedByIme) { + @Override + public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance, + AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { if (displayId != mDisplayId) { return; } - final int oldVal = mSystemUiVisibility; - final int newVal = (oldVal&~mask) | (vis&mask); - final int diff = newVal ^ oldVal; - if (DEBUG) Log.d(TAG, String.format( - "setSystemUiVisibility displayId=%d vis=%s mask=%s oldVal=%s newVal=%s diff=%s", - displayId, Integer.toHexString(vis), Integer.toHexString(mask), - Integer.toHexString(oldVal), Integer.toHexString(newVal), - Integer.toHexString(diff))); - boolean sbModeChanged = false; - if (diff != 0) { - mSystemUiVisibility = newVal; + boolean barModeChanged = false; + final int diff = mAppearance ^ appearance; + if (mAppearance != appearance) { + mAppearance = appearance; // update low profile - if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { + if ((diff & APPEARANCE_LOW_PROFILE_BARS) != 0) { updateAreThereNotifications(); } + barModeChanged = updateBarMode(barMode(mTransientShown, appearance)); + } + mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged, + mStatusBarMode, navbarColorManagedByIme); + } - // ready to unhide - if ((vis & View.STATUS_BAR_UNHIDE) != 0) { - mNoAnimationOnNextBarModeChange = true; - } + @Override + public void showTransient(int displayId, @InternalInsetType int[] types) { + if (displayId != mDisplayId) { + return; + } + if (!containsType(types, TYPE_TOP_BAR)) { + return; + } + showTransientUnchecked(); + } + + private void showTransientUnchecked() { + if (!mTransientShown) { + mTransientShown = true; + mNoAnimationOnNextBarModeChange = true; + handleTransientChanged(); + } + } + + @Override + public void abortTransient(int displayId, @InternalInsetType int[] types) { + if (displayId != mDisplayId) { + return; + } + if (!containsType(types, TYPE_TOP_BAR)) { + return; + } + clearTransient(); + } + + void clearTransient() { + if (mTransientShown) { + mTransientShown = false; + handleTransientChanged(); + } + } - // update status bar mode - final int sbMode = computeStatusBarMode(oldVal, newVal); + private void handleTransientChanged() { + final int barMode = barMode(mTransientShown, mAppearance); + if (updateBarMode(barMode)) { + mLightBarController.onStatusBarModeChanged(barMode); + } + } - sbModeChanged = sbMode != -1; - if (sbModeChanged && sbMode != mStatusBarMode) { - mStatusBarMode = sbMode; - checkBarModes(); - mAutoHideController.touchAutoHide(); - } - mStatusBarStateController.setSystemUiVisibility(mSystemUiVisibility); + private boolean updateBarMode(int barMode) { + if (mStatusBarMode != barMode) { + mStatusBarMode = barMode; + checkBarModes(); + mAutoHideController.touchAutoHide(); + return true; + } + return false; + } + + private static @TransitionMode int barMode(boolean isTransient, int appearance) { + final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_TOP_BAR; + if (isTransient) { + return MODE_SEMI_TRANSPARENT; + } else if ((appearance & lightsOutOpaque) == lightsOutOpaque) { + return MODE_LIGHTS_OUT; + } else if ((appearance & APPEARANCE_LOW_PROFILE_BARS) != 0) { + return MODE_LIGHTS_OUT_TRANSPARENT; + } else if ((appearance & APPEARANCE_OPAQUE_TOP_BAR) != 0) { + return MODE_OPAQUE; + } else { + return MODE_TRANSPARENT; + } + } + + @Override + public void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) { + if (displayId != mDisplayId) { + return; } - mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis, - mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode, - navbarColorManagedByIme); + mAppFullscreen = isFullscreen; + mAppImmersive = isImmersive; } @Override @@ -2295,40 +2371,10 @@ public class StatusBar extends SystemUI implements DemoMode, setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running); } - protected @TransitionMode int computeStatusBarMode(int oldVal, int newVal) { - return computeBarMode(oldVal, newVal); - } - protected BarTransitions getStatusBarTransitions() { return mStatusBarView.getBarTransitions(); } - protected @TransitionMode int computeBarMode(int oldVis, int newVis) { - final int oldMode = barMode(oldVis); - final int newMode = barMode(newVis); - if (oldMode == newMode) { - return -1; // no mode change - } - return newMode; - } - - private @TransitionMode int barMode(int vis) { - int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | View.STATUS_BAR_TRANSPARENT; - if ((vis & View.STATUS_BAR_TRANSIENT) != 0) { - return MODE_SEMI_TRANSPARENT; - } else if ((vis & View.STATUS_BAR_TRANSLUCENT) != 0) { - return MODE_TRANSLUCENT; - } else if ((vis & lightsOutTransparent) == lightsOutTransparent) { - return MODE_LIGHTS_OUT_TRANSPARENT; - } else if ((vis & View.STATUS_BAR_TRANSPARENT) != 0) { - return MODE_TRANSPARENT; - } else if ((vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { - return MODE_LIGHTS_OUT; - } else { - return MODE_OPAQUE; - } - } - void checkBarModes() { if (mDemoMode) return; if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState, @@ -2384,20 +2430,16 @@ public class StatusBar extends SystemUI implements DemoMode, /** Returns whether the top activity is in fullscreen mode. */ public boolean inFullscreenMode() { - return 0 - != (mSystemUiVisibility - & (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)); + return mAppFullscreen; } /** Returns whether the top activity is in immersive mode. */ public boolean inImmersiveMode() { - return 0 - != (mSystemUiVisibility - & (View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)); + return mAppImmersive; } private boolean areLightsOn() { - return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); + return 0 == (mAppearance & APPEARANCE_LOW_PROFILE_BARS); } public static String viewInfo(View v) { @@ -4722,8 +4764,8 @@ public class StatusBar extends SystemUI implements DemoMode, void createStatusBar(StatusBar statusbar); } - public @TransitionMode int getStatusBarMode() { - return mStatusBarMode; + boolean isTransientShown() { + return mTransientShown; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index d04c7bd38320..6b513919e912 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.graphics.Insets; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -42,6 +43,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.Window; +import android.view.WindowInsets; import android.view.WindowInsetsController; import android.widget.FrameLayout; @@ -74,7 +76,8 @@ public class StatusBarWindowView extends FrameLayout { } @Override - protected boolean fitSystemWindows(Rect insets) { + public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) { + final Insets insets = windowInsets.getMaxInsets(WindowInsets.Type.systemBars()); if (getFitsSystemWindows()) { boolean paddingChanged = insets.top != getPaddingTop() || insets.bottom != getPaddingBottom(); @@ -100,9 +103,6 @@ public class StatusBarWindowView extends FrameLayout { if (paddingChanged) { setPadding(0, 0, 0, 0); } - insets.left = 0; - insets.top = 0; - insets.right = 0; } else { if (mRightInset != 0 || mLeftInset != 0) { mRightInset = 0; @@ -116,9 +116,8 @@ public class StatusBarWindowView extends FrameLayout { if (changed) { setPadding(0, 0, 0, 0); } - insets.top = 0; } - return false; + return windowInsets; } private void applyMargins() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 1bd01e166ddb..eb198c6ad4f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -15,6 +15,8 @@ package com.android.systemui.statusbar; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.InsetsState.TYPE_NAVIGATION_BAR; +import static android.view.InsetsState.TYPE_TOP_BAR; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Matchers.eq; @@ -25,10 +27,12 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.content.ComponentName; import android.graphics.Rect; import android.os.Bundle; +import android.view.WindowInsetsController.Appearance; import androidx.test.filters.SmallTest; import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.view.AppearanceRegion; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.CommandQueue.Callbacks; @@ -110,21 +114,56 @@ public class CommandQueueTest extends SysuiTestCase { } @Test - public void testSetSystemUiVisibility() { - Rect r = new Rect(); - mCommandQueue.setSystemUiVisibility(DEFAULT_DISPLAY, 1, 2, 3, 4, null, r, false); + public void testOnSystemBarAppearanceChanged() { + doTestOnSystemBarAppearanceChanged(DEFAULT_DISPLAY, 1, + new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false); + } + + @Test + public void testOnSystemBarAppearanceChangedForSecondaryDisplay() { + doTestOnSystemBarAppearanceChanged(SECONDARY_DISPLAY, 1, + new AppearanceRegion[]{new AppearanceRegion(2, new Rect())}, false); + } + + private void doTestOnSystemBarAppearanceChanged(int displayId, @Appearance int appearance, + AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { + mCommandQueue.onSystemBarAppearanceChanged(displayId, appearance, appearanceRegions, + navbarColorManagedByIme); + waitForIdleSync(); + verify(mCallbacks).onSystemBarAppearanceChanged(eq(displayId), eq(appearance), + eq(appearanceRegions), eq(navbarColorManagedByIme)); + } + + @Test + public void testShowTransient() { + int[] types = new int[]{ TYPE_TOP_BAR, TYPE_NAVIGATION_BAR }; + mCommandQueue.showTransient(DEFAULT_DISPLAY, types); + waitForIdleSync(); + verify(mCallbacks).showTransient(eq(DEFAULT_DISPLAY), eq(types)); + } + + @Test + public void testShowTransientForSecondaryDisplay() { + int[] types = new int[]{ TYPE_TOP_BAR, TYPE_NAVIGATION_BAR }; + mCommandQueue.showTransient(SECONDARY_DISPLAY, types); + waitForIdleSync(); + verify(mCallbacks).showTransient(eq(SECONDARY_DISPLAY), eq(types)); + } + + @Test + public void testAbortTransient() { + int[] types = new int[]{ TYPE_TOP_BAR, TYPE_NAVIGATION_BAR }; + mCommandQueue.abortTransient(DEFAULT_DISPLAY, types); waitForIdleSync(); - verify(mCallbacks).setSystemUiVisibility(eq(DEFAULT_DISPLAY), eq(1), eq(2), eq(3), eq(4), - eq(null), eq(r), eq(false)); + verify(mCallbacks).abortTransient(eq(DEFAULT_DISPLAY), eq(types)); } @Test - public void testSetSystemUiVisibilityForSecondaryDisplay() { - Rect r = new Rect(); - mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r, false); + public void testAbortTransientForSecondaryDisplay() { + int[] types = new int[]{ TYPE_TOP_BAR, TYPE_NAVIGATION_BAR }; + mCommandQueue.abortTransient(SECONDARY_DISPLAY, types); waitForIdleSync(); - verify(mCallbacks).setSystemUiVisibility(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(3), eq(4), - eq(null), eq(r), eq(false)); + verify(mCallbacks).abortTransient(eq(SECONDARY_DISPLAY), eq(types)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java deleted file mode 100644 index 16f02d9dd661..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.systemui.statusbar.phone; - -import static android.view.Display.DEFAULT_DISPLAY; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.graphics.Rect; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper.RunWithLooper; -import android.view.IWindowManager; -import android.view.View; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.Dependency; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.NotificationRemoteInputManager; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** atest AutoHideControllerTest */ -@RunWith(AndroidTestingRunner.class) -@RunWithLooper -@SmallTest -public class AutoHideControllerTest extends SysuiTestCase { - - private AutoHideController mAutoHideController; - - private static final int FULL_MASK = 0xffffffff; - - @Before - public void setUp() { - mContext.putComponent(CommandQueue.class, mock(CommandQueue.class)); - mAutoHideController = - spy(new AutoHideController(mContext, Dependency.get(Dependency.MAIN_HANDLER), - mock(NotificationRemoteInputManager.class), mock(IWindowManager.class))); - mAutoHideController.mDisplayId = DEFAULT_DISPLAY; - mAutoHideController.mSystemUiVisibility = View.VISIBLE; - } - - @After - public void tearDown() { - mAutoHideController = null; - } - - @Test - public void testSetSystemUiVisibilityEarlyReturnWithDifferentDisplay() { - mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect(), false); - - verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt()); - } - - @Test - public void testSetSystemUiVisibilityEarlyReturnWithSameVisibility() { - mAutoHideController - .setSystemUiVisibility( - DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect(), false); - - verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt()); - } - - // Test if status bar unhide status doesn't change without status bar. - @Test - public void testSetSystemUiVisibilityWithoutStatusBar() { - doReturn(false).when(mAutoHideController).hasStatusBar(); - int expectedStatus = View.STATUS_BAR_UNHIDE; - mAutoHideController.mSystemUiVisibility = - View.SYSTEM_UI_FLAG_FULLSCREEN | View.STATUS_BAR_UNHIDE; - - mAutoHideController.setSystemUiVisibility( - DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect(), false); - - assertEquals("System UI visibility should not be changed", - expectedStatus, mAutoHideController.mSystemUiVisibility); - verify(mAutoHideController, times(1)).notifySystemUiVisibilityChanged(eq(expectedStatus)); - } - - @Test - public void testSetSystemUiVisibilityWithVisChanged() { - doReturn(true).when(mAutoHideController).hasStatusBar(); - doReturn(true).when(mAutoHideController).hasNavigationBar(); - mAutoHideController.mSystemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN - | View.STATUS_BAR_UNHIDE - | View.NAVIGATION_BAR_UNHIDE; - - mAutoHideController.setSystemUiVisibility( - DEFAULT_DISPLAY, View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE, - 2, 3, FULL_MASK, null, new Rect(), false); - - int expectedStatus = View.VISIBLE; - assertEquals(expectedStatus, mAutoHideController.mSystemUiVisibility); - verify(mAutoHideController).notifySystemUiVisibilityChanged(eq(expectedStatus)); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java new file mode 100644 index 000000000000..6260d531a290 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2019 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 com.android.systemui.statusbar.phone; + +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_TOP_BAR; + +import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.graphics.Rect; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.internal.view.AppearanceRegion; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.policy.BatteryController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class LightBarControllerTest extends SysuiTestCase { + + private LightBarTransitionsController mLightBarTransitionsController; + private SysuiDarkIconDispatcher mStatusBarIconController; + private LightBarController mLightBarController; + + @Before + public void setup() { + mStatusBarIconController = mock(SysuiDarkIconDispatcher.class); + mLightBarTransitionsController = mock(LightBarTransitionsController.class); + when(mStatusBarIconController.getTransitionsController()).thenReturn( + mLightBarTransitionsController); + mLightBarController = new LightBarController(mContext, mStatusBarIconController, + mock(BatteryController.class)); + } + + @Test + public void testOnStatusBarAppearanceChanged_multipleStacks_allStacksLight() { + final Rect firstBounds = new Rect(0, 0, 1, 1); + final Rect secondBounds = new Rect(1, 0, 2, 1); + final AppearanceRegion[] appearanceRegions = new AppearanceRegion[]{ + new AppearanceRegion(APPEARANCE_LIGHT_TOP_BAR, firstBounds), + new AppearanceRegion(APPEARANCE_LIGHT_TOP_BAR, secondBounds) + }; + mLightBarController.onStatusBarAppearanceChanged( + appearanceRegions, true /* sbModeChanged */, MODE_TRANSPARENT, + false /* navbarColorManagedByIme */); + verify(mStatusBarIconController).setIconsDarkArea(eq(null)); + verify(mLightBarTransitionsController).setIconsDark(eq(true), anyBoolean()); + } + + @Test + public void testOnStatusBarAppearanceChanged_multipleStacks_oneStackLightOneStackDark() { + final Rect firstBounds = new Rect(0, 0, 1, 1); + final Rect secondBounds = new Rect(1, 0, 2, 1); + final AppearanceRegion[] appearanceRegions = new AppearanceRegion[]{ + new AppearanceRegion(APPEARANCE_LIGHT_TOP_BAR, firstBounds), + new AppearanceRegion(0 /* appearance */, secondBounds) + }; + mLightBarController.onStatusBarAppearanceChanged( + appearanceRegions, true /* sbModeChanged */, MODE_TRANSPARENT, + false /* navbarColorManagedByIme */); + verify(mStatusBarIconController).setIconsDarkArea(eq(firstBounds)); + verify(mLightBarTransitionsController).setIconsDark(eq(true), anyBoolean()); + } + + @Test + public void testOnStatusBarAppearanceChanged_multipleStacks_oneStackDarkOneStackLight() { + final Rect firstBounds = new Rect(0, 0, 1, 1); + final Rect secondBounds = new Rect(1, 0, 2, 1); + final AppearanceRegion[] appearanceRegions = new AppearanceRegion[]{ + new AppearanceRegion(0 /* appearance */, firstBounds), + new AppearanceRegion(APPEARANCE_LIGHT_TOP_BAR, secondBounds) + }; + mLightBarController.onStatusBarAppearanceChanged( + appearanceRegions, true /* sbModeChanged */, MODE_TRANSPARENT, + false /* navbarColorManagedByIme */); + verify(mStatusBarIconController).setIconsDarkArea(eq(secondBounds)); + verify(mLightBarTransitionsController).setIconsDark(eq(true), anyBoolean()); + } + + @Test + public void testOnStatusBarAppearanceChanged_multipleStacks_allStacksDark() { + final Rect firstBounds = new Rect(0, 0, 1, 1); + final Rect secondBounds = new Rect(1, 0, 2, 1); + final AppearanceRegion[] appearanceRegions = new AppearanceRegion[]{ + new AppearanceRegion(0 /* appearance */, firstBounds), + new AppearanceRegion(0 /* appearance */, secondBounds) + }; + mLightBarController.onStatusBarAppearanceChanged( + appearanceRegions, true /* sbModeChanged */, MODE_TRANSPARENT, + false /* navbarColorManagedByIme */); + verify(mLightBarTransitionsController).setIconsDark(eq(false), anyBoolean()); + } + + @Test + public void testOnStatusBarAppearanceChanged_singleStack_light() { + final AppearanceRegion[] appearanceRegions = new AppearanceRegion[]{ + new AppearanceRegion(APPEARANCE_LIGHT_TOP_BAR, new Rect(0, 0, 1, 1)) + }; + mLightBarController.onStatusBarAppearanceChanged( + appearanceRegions, true /* sbModeChanged */, MODE_TRANSPARENT, + false /* navbarColorManagedByIme */); + verify(mStatusBarIconController).setIconsDarkArea(eq(null)); + verify(mLightBarTransitionsController).setIconsDark(eq(true), anyBoolean()); + } + + @Test + public void testOnStatusBarAppearanceChanged_singleStack_dark() { + final AppearanceRegion[] appearanceRegions = new AppearanceRegion[]{ + new AppearanceRegion(0, new Rect(0, 0, 1, 1)) + }; + mLightBarController.onStatusBarAppearanceChanged( + appearanceRegions, true /* sbModeChanged */, MODE_TRANSPARENT, + false /* navbarColorManagedByIme */); + verify(mLightBarTransitionsController).setIconsDark(eq(false), anyBoolean()); + } +} diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index a93d2b8b6fb9..ec64ee6d52de 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -18,7 +18,10 @@ package com.android.server.statusbar; import android.graphics.Rect; import android.os.Bundle; +import android.view.InsetsState.InternalInsetType; +import android.view.WindowInsetsController.Appearance; +import com.android.internal.view.AppearanceRegion; import com.android.server.notification.NotificationDelegate; public interface StatusBarManagerInternal { @@ -75,7 +78,7 @@ public interface StatusBarManagerInternal { void startAssist(Bundle args); void onCameraLaunchGestureDetected(int source); - void topAppWindowChanged(int displayId, boolean menuVisible); + void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive); void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, boolean isNavbarColorManagedByIme, String cause); @@ -113,4 +116,14 @@ public interface StatusBarManagerInternal { * Notifies System UI whether the recents animation is running. */ void onRecentsAnimationStateChanged(boolean running); + + /** @see com.android.internal.statusbar.IStatusBar#onSystemBarAppearanceChanged */ + void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance, + AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme); + + /** @see com.android.internal.statusbar.IStatusBar#showTransient */ + void showTransient(int displayId, @InternalInsetType int[] types); + + /** @see com.android.internal.statusbar.IStatusBar#abortTransient */ + void abortTransient(int displayId, @InternalInsetType int[] types); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 65bb2342d504..3c1a6afccda1 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -47,6 +47,7 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.view.WindowInsetsController.Appearance; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -56,6 +57,7 @@ import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.RegisterStatusBarResult; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.util.DumpUtils; +import com.android.internal.view.AppearanceRegion; import com.android.server.LocalServices; import com.android.server.notification.NotificationDelegate; import com.android.server.policy.GlobalActionsProvider; @@ -256,8 +258,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public void topAppWindowChanged(int displayId, boolean menuVisible) { - StatusBarManagerService.this.topAppWindowChanged(displayId, menuVisible); + public void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) { + StatusBarManagerService.this.topAppWindowChanged(displayId, isFullscreen, isImmersive); } @Override @@ -467,6 +469,36 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } } + + @Override + public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance, + AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { + // TODO (b/118118435): save the information to UiState + if (mBar != null) { + try { + mBar.onSystemBarAppearanceChanged(displayId, appearance, appearanceRegions, + navbarColorManagedByIme); + } catch (RemoteException ex) { } + } + } + + @Override + public void showTransient(int displayId, int[] types) { + if (mBar != null) { + try { + mBar.showTransient(displayId, types); + } catch (RemoteException ex) { } + } + } + + @Override + public void abortTransient(int displayId, int[] types) { + if (mBar != null) { + try { + mBar.abortTransient(displayId, types); + } catch (RemoteException ex) { } + } + } }; private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() { @@ -817,23 +849,19 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } /** - * Hide or show the on-screen Menu key. Only call this from the window manager, typically in - * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set - * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}. + * Enables System UI to know whether the top app is fullscreen or not, and whether this app is + * in immersive mode or not. */ - private void topAppWindowChanged(int displayId, final boolean menuVisible) { + private void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) { enforceStatusBar(); - if (SPEW) { - Slog.d(TAG, "display#" + displayId + ": " - + (menuVisible ? "showing" : "hiding") + " MENU key"); - } synchronized(mLock) { - getUiState(displayId).setMenuVisible(menuVisible); + getUiState(displayId).setFullscreen(isFullscreen); + getUiState(displayId).setImmersive(isImmersive); mHandler.post(() -> { if (mBar != null) { try { - mBar.topAppWindowChanged(displayId, menuVisible); + mBar.topAppWindowChanged(displayId, isFullscreen, isImmersive); } catch (RemoteException ex) { } } @@ -942,7 +970,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D private int mDockedStackSysUiVisibility = 0; private final Rect mFullscreenStackBounds = new Rect(); private final Rect mDockedStackBounds = new Rect(); - private boolean mMenuVisible = false; + private boolean mFullscreen = false; + private boolean mImmersive = false; private int mDisabled1 = 0; private int mDisabled2 = 0; private int mImeWindowVis = 0; @@ -964,12 +993,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D mDisabled2 = disabled2; } - private boolean isMenuVisible() { - return mMenuVisible; + private void setFullscreen(boolean isFullscreen) { + mFullscreen = isFullscreen; } - private void setMenuVisible(boolean menuVisible) { - mMenuVisible = menuVisible; + private void setImmersive(boolean immersive) { + mImmersive = immersive; } private boolean disableEquals(int disabled1, int disabled2) { @@ -1056,12 +1085,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // Make it aware of multi-display if needed. final UiState state = mDisplayUiState.get(DEFAULT_DISPLAY); return new RegisterStatusBarResult(icons, gatherDisableActionsLocked(mCurrentUserId, 1), - state.mSystemUiVisibility, state.mMenuVisible, state.mImeWindowVis, + state.mSystemUiVisibility, state.mImeWindowVis, state.mImeBackDisposition, state.mShowImeSwitcher, gatherDisableActionsLocked(mCurrentUserId, 2), state.mFullscreenStackSysUiVisibility, state.mDockedStackSysUiVisibility, state.mImeToken, state.mFullscreenStackBounds, state.mDockedStackBounds, - state.mNavbarColorManagedByIme); + state.mNavbarColorManagedByIme, state.mFullscreen, state.mImmersive); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 4c3611e971b4..8af33731376f 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3450,6 +3450,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return win != null; } + void hideTransientBars() { + // TODO(b/118118435): Remove this after migration + final int transientFlags = View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT; + statusBarVisibilityChanged(mLastStatusBarVisibility & ~transientFlags); + + getInsetsPolicy().hideTransient(); + } + void statusBarVisibilityChanged(int visibility) { mLastStatusBarVisibility = visibility; visibility = getDisplayPolicy().adjustSystemUiVisibilityLw(visibility); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 60e9819ecbcf..f41a34a45d83 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -30,7 +30,11 @@ import static android.view.InsetsState.TYPE_TOP_GESTURES; import static android.view.InsetsState.TYPE_TOP_TAPPABLE_ELEMENT; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_TOP_BAR; +import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE; +import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; @@ -129,6 +133,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.util.ArraySet; +import android.util.IntArray; import android.util.Pair; import android.util.PrintWriterPrinter; import android.util.Slog; @@ -145,6 +150,7 @@ import android.view.PointerIcon; import android.view.Surface; import android.view.View; import android.view.ViewRootImpl; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; @@ -158,6 +164,7 @@ import com.android.internal.policy.ScreenDecorationsUtils; import com.android.internal.util.ScreenShapeHelper; import com.android.internal.util.ScreenshotHelper; import com.android.internal.util.function.TriConsumer; +import com.android.internal.view.AppearanceRegion; import com.android.internal.widget.PointerLocationView; import com.android.server.LocalServices; import com.android.server.UiThread; @@ -235,7 +242,7 @@ public class DisplayPolicy { @Px private int mSideGestureInset; - private StatusBarManagerInternal getStatusBarManagerInternal() { + StatusBarManagerInternal getStatusBarManagerInternal() { synchronized (mServiceAcquireLock) { if (mStatusBarManagerInternal == null) { mStatusBarManagerInternal = @@ -327,14 +334,18 @@ public class DisplayPolicy { private int mForceClearedSystemUiFlags = 0; private int mLastFullscreenStackSysUiFlags; private int mLastDockedStackSysUiFlags; + private int mLastAppearance; + private int mLastFullscreenAppearance; + private int mLastDockedAppearance; private final Rect mNonDockedStackBounds = new Rect(); private final Rect mDockedStackBounds = new Rect(); private final Rect mLastNonDockedStackBounds = new Rect(); private final Rect mLastDockedStackBounds = new Rect(); - // What we last reported to system UI about whether the compatibility - // menu needs to be displayed. - private boolean mLastFocusNeedsMenu = false; + // What we last reported to system UI about whether the focused window is fullscreen/immersive. + private boolean mLastFocusIsFullscreen = false; + private boolean mLastFocusIsImmersive = false; + // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending. private long mPendingPanicGestureUptime; @@ -3045,19 +3056,38 @@ public class DisplayPolicy { // Swipe-up for navigation bar is disabled during setup return; } - boolean sb = mStatusBarController.checkShowTransientBarLw(); - boolean nb = mNavigationBarController.checkShowTransientBarLw() - && !isNavBarEmpty(mLastSystemUiFlags); - if (sb || nb) { - // Don't show status bar when swiping on already visible navigation bar - if (!nb && swipeTarget == mNavigationBar) { - if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target"); + if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) { + if (swipeTarget == mNavigationBar + && !getInsetsPolicy().isHidden(InsetsState.TYPE_NAVIGATION_BAR)) { + // Don't show status bar when swiping on already visible navigation bar + return; + } + final InsetsControlTarget controlTarget = + swipeTarget.getControllableInsetProvider().getControlTarget(); + if (controlTarget == null) { return; } - if (sb) mStatusBarController.showTransient(); - if (nb) mNavigationBarController.showTransient(); + if (controlTarget.canShowTransient()) { + mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap( + new int[]{TYPE_TOP_BAR, InsetsState.TYPE_NAVIGATION_BAR})); + } else { + controlTarget.showInsets(WindowInsets.Type.systemBars(), false); + } + } else { + boolean sb = mStatusBarController.checkShowTransientBarLw(); + boolean nb = mNavigationBarController.checkShowTransientBarLw() + && !isNavBarEmpty(mLastSystemUiFlags); + if (sb || nb) { + // Don't show status bar when swiping on already visible navigation bar + if (!nb && swipeTarget == mNavigationBar) { + if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target"); + return; + } + if (sb) mStatusBarController.showTransient(); + if (nb) mNavigationBarController.showTransient(); + updateSystemUiVisibilityLw(); + } mImmersiveModeConfirmation.confirmCurrentPrompt(); - updateSystemUiVisibilityLw(); } } } @@ -3078,6 +3108,10 @@ public class DisplayPolicy { return mService.mPolicy.isKeyguardOccluded(); } + InsetsPolicy getInsetsPolicy() { + return mDisplayContent.getInsetsPolicy(); + } + void resetSystemUiVisibilityLw() { mLastSystemUiFlags = 0; updateSystemUiVisibilityLw(); @@ -3129,14 +3163,20 @@ public class DisplayPolicy { &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS); } + final int appearance = win.mAttrs.insetsFlags.appearance; final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */, mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState); final int dockedVisibility = updateLightStatusBarLw(0 /* vis */, mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState); + final int fullscreenAppearance = updateLightStatusBarAppearanceLw(0 /* vis */, + mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState); + final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */, + mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState); mService.getStackBounds( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds); - mService.getStackBounds(mDockedStackBounds.isEmpty() - ? WINDOWING_MODE_FULLSCREEN : WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, + final boolean inSplitScreen = !mDockedStackBounds.isEmpty(); + mService.getStackBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY + : WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_UNDEFINED, mNonDockedStackBounds); final Pair<Integer, Boolean> result = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility); @@ -3144,8 +3184,24 @@ public class DisplayPolicy { final int diff = visibility ^ mLastSystemUiFlags; final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags; final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags; - final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState); - if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu + final InsetsPolicy insetsPolicy = getInsetsPolicy(); + final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) != 0 + || (PolicyControl.getWindowFlags(win, win.mAttrs) & FLAG_FULLSCREEN) != 0 + || (mStatusBar != null && insetsPolicy.isHidden(TYPE_TOP_BAR)) + || (mNavigationBar != null && insetsPolicy.isHidden( + InsetsState.TYPE_NAVIGATION_BAR)); + final int behavior = win.mAttrs.insetsFlags.behavior; + final boolean isImmersive = (visibility & (View.SYSTEM_UI_FLAG_IMMERSIVE + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)) != 0 + || behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE + || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; + if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 + && mLastAppearance == appearance + && mLastFullscreenAppearance == fullscreenAppearance + && mLastDockedAppearance == dockedAppearance + && mLastFocusIsFullscreen == isFullscreen + && mLastFocusIsImmersive == isImmersive && mFocusedApp == win.getAppToken() && mLastNonDockedStackBounds.equals(mNonDockedStackBounds) && mLastDockedStackBounds.equals(mDockedStackBounds)) { @@ -3154,21 +3210,39 @@ public class DisplayPolicy { mLastSystemUiFlags = visibility; mLastFullscreenStackSysUiFlags = fullscreenVisibility; mLastDockedStackSysUiFlags = dockedVisibility; - mLastFocusNeedsMenu = needsMenu; + mLastAppearance = appearance; + mLastFullscreenAppearance = fullscreenAppearance; + mLastDockedAppearance = dockedAppearance; + mLastFocusIsFullscreen = isFullscreen; + mLastFocusIsImmersive = isImmersive; mFocusedApp = win.getAppToken(); mLastNonDockedStackBounds.set(mNonDockedStackBounds); mLastDockedStackBounds.set(mDockedStackBounds); final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds); final Rect dockedStackBounds = new Rect(mDockedStackBounds); + final AppearanceRegion[] appearanceRegions = inSplitScreen + ? new AppearanceRegion[]{ + new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds), + new AppearanceRegion(dockedAppearance, dockedStackBounds)} + : new AppearanceRegion[]{ + new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds)}; final boolean isNavbarColorManagedByIme = result.second; mHandler.post(() -> { StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); if (statusBar != null) { final int displayId = getDisplayId(); + // TODO(b/118118435): disabled flags only statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility, dockedVisibility, 0xffffffff, fullscreenStackBounds, dockedStackBounds, isNavbarColorManagedByIme, win.toString()); - statusBar.topAppWindowChanged(displayId, needsMenu); + if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) { + statusBar.onSystemBarAppearanceChanged(displayId, appearance, + appearanceRegions, isNavbarColorManagedByIme); + } + statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive); + + // TODO(b/118118435): Remove this after removing system UI visibilities. + mDisplayContent.statusBarVisibilityChanged(visibility); } }); return diff; @@ -3190,6 +3264,22 @@ public class DisplayPolicy { return vis; } + private int updateLightStatusBarAppearanceLw(int appearance, WindowState opaque, + WindowState opaqueOrDimming) { + final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded(); + final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming; + if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) { + // If the top fullscreen-or-dimming window is also the top fullscreen, respect + // its light flag. + appearance &= ~APPEARANCE_LIGHT_TOP_BAR; + appearance |= statusColorWin.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_TOP_BAR; + } else if (statusColorWin != null && statusColorWin.isDimming()) { + // Otherwise if it's dimming, clear the light flag. + appearance &= ~APPEARANCE_LIGHT_TOP_BAR; + } + return appearance; + } + @VisibleForTesting @Nullable static WindowState chooseNavigationColorWindowLw(WindowState opaque, @@ -3511,6 +3601,8 @@ public class DisplayPolicy { mPendingPanicGestureUptime = SystemClock.uptimeMillis(); if (!isNavBarEmpty(mLastSystemUiFlags)) { mNavigationBarController.showTransient(); + mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap( + new int[] {InsetsState.TYPE_NAVIGATION_BAR})); } } } @@ -3588,9 +3680,6 @@ public class DisplayPolicy { pw.print(" mForceClearedSystemUiFlags=0x"); pw.println(Integer.toHexString(mForceClearedSystemUiFlags)); } - if (mLastFocusNeedsMenu) { - pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu); - } pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream); pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen); pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken); diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java index 22ba82ace865..c8ce53d444d5 100644 --- a/services/core/java/com/android/server/wm/InsetsControlTarget.java +++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java @@ -42,4 +42,11 @@ interface InsetsControlTarget { */ default void hideInsets(@InsetType int types, boolean fromIme) { } + + /** + * Returns {@code true} if the control target allows the system to show transient windows. + */ + default boolean canShowTransient() { + return false; + } } diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 2dc50d86eaea..e8e530a73451 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -16,13 +16,22 @@ package com.android.server.wm; +import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; +import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.view.InsetsState.TYPE_NAVIGATION_BAR; +import static android.view.InsetsState.TYPE_TOP_BAR; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION; import android.annotation.Nullable; +import android.app.StatusBarManager; +import android.util.IntArray; +import android.view.InsetsState; +import android.view.InsetsState.InternalInsetType; +import android.view.ViewRootImpl; /** * Policy that implements who gets control over the windows generating insets. @@ -32,6 +41,12 @@ class InsetsPolicy { private final InsetsStateController mStateController; private final DisplayContent mDisplayContent; private final DisplayPolicy mPolicy; + private final TransientControlTarget mTransientControlTarget = new TransientControlTarget(); + private final IntArray mShowingTransientTypes = new IntArray(); + + private WindowState mFocusedWin; + private BarWindow mTopBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR); + private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR); InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) { mStateController = stateController; @@ -41,11 +56,129 @@ class InsetsPolicy { /** Updates the target which can control system bars. */ void updateBarControlTarget(@Nullable WindowState focusedWin) { + mFocusedWin = focusedWin; mStateController.onBarControlTargetChanged(getTopControlTarget(focusedWin), - getNavControlTarget(focusedWin)); + getFakeTopControlTarget(focusedWin), + getNavControlTarget(focusedWin), + getFakeNavControlTarget(focusedWin)); + mTopBar.setVisible(focusedWin == null + || focusedWin != getTopControlTarget(focusedWin) + || focusedWin.getClientInsetsState().getSource(TYPE_TOP_BAR).isVisible()); + mNavBar.setVisible(focusedWin == null + || focusedWin != getNavControlTarget(focusedWin) + || focusedWin.getClientInsetsState().getSource(TYPE_NAVIGATION_BAR).isVisible()); + } + + boolean isHidden(@InternalInsetType int type) { + final InsetsSourceProvider provider = mStateController.peekSourceProvider(type); + return provider != null && provider.hasWindow() && !provider.getSource().isVisible(); + } + + void showTransient(IntArray types) { + boolean changed = false; + for (int i = types.size() - 1; i >= 0; i--) { + final int type = types.get(i); + if (mShowingTransientTypes.indexOf(type) != -1) { + continue; + } + if (!isHidden(type)) { + continue; + } + mShowingTransientTypes.add(type); + changed = true; + } + if (changed) { + updateBarControlTarget(mFocusedWin); + mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(), + mShowingTransientTypes.toArray()); + mStateController.notifyInsetsChanged(); + // TODO(b/118118435): Animation + } + } + + void hideTransient() { + if (mShowingTransientTypes.size() == 0) { + return; + } + + // TODO(b/118118435): Animation + mShowingTransientTypes.clear(); + updateBarControlTarget(mFocusedWin); + mStateController.notifyInsetsChanged(); + } + + /** + * @see InsetsStateController#getInsetsForDispatch + */ + InsetsState getInsetsForDispatch(WindowState target) { + InsetsState state = mStateController.getInsetsForDispatch(target); + if (mShowingTransientTypes.size() == 0) { + return state; + } + for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { + state.setSourceVisible(mShowingTransientTypes.get(i), false); + } + return state; + } + + void onInsetsModified(WindowState windowState, InsetsState state) { + mStateController.onInsetsModified(windowState, state); + checkAbortTransient(windowState, state); + if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) { + return; + } + if (windowState == getTopControlTarget(mFocusedWin)) { + mTopBar.setVisible(state.getSource(TYPE_TOP_BAR).isVisible()); + } + if (windowState == getNavControlTarget(mFocusedWin)) { + mNavBar.setVisible(state.getSource(TYPE_NAVIGATION_BAR).isVisible()); + } + } + + /** + * Called when a window modified the insets state. If the window set a insets source to visible + * while it is shown transiently, we need to abort the transient state. + * + * @param windowState who changed the insets state. + * @param state the modified insets state. + */ + private void checkAbortTransient(WindowState windowState, InsetsState state) { + if (mShowingTransientTypes.size() != 0) { + IntArray abortTypes = new IntArray(); + for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { + final int type = mShowingTransientTypes.get(i); + if (mStateController.isFakeTarget(type, windowState) + && state.getSource(type).isVisible()) { + mShowingTransientTypes.remove(i); + abortTypes.add(type); + } + } + if (abortTypes.size() > 0) { + mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(), + abortTypes.toArray()); + updateBarControlTarget(mFocusedWin); + } + } + } + + private @Nullable InsetsControlTarget getFakeTopControlTarget(@Nullable WindowState focused) { + if (mShowingTransientTypes.indexOf(TYPE_TOP_BAR) != -1) { + return focused; + } + return null; + } + + private @Nullable InsetsControlTarget getFakeNavControlTarget(@Nullable WindowState focused) { + if (mShowingTransientTypes.indexOf(TYPE_NAVIGATION_BAR) != -1) { + return focused; + } + return null; } private @Nullable InsetsControlTarget getTopControlTarget(@Nullable WindowState focusedWin) { + if (mShowingTransientTypes.indexOf(TYPE_TOP_BAR) != -1) { + return mTransientControlTarget; + } if (areSystemBarsForciblyVisible() || isStatusBarForciblyVisible()) { return null; } @@ -53,6 +186,9 @@ class InsetsPolicy { } private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) { + if (mShowingTransientTypes.indexOf(TYPE_NAVIGATION_BAR) != -1) { + return mTransientControlTarget; + } if (areSystemBarsForciblyVisible() || isNavBarForciblyVisible()) { return null; } @@ -66,7 +202,7 @@ class InsetsPolicy { } final int privateFlags = statusBar.mAttrs.privateFlags; - // TODO: Pretend to the app that it's still able to control it? + // TODO(b/118118435): Pretend to the app that it's still able to control it? if ((privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) { return true; } @@ -100,4 +236,31 @@ class InsetsPolicy { return isDockedStackVisible || isFreeformStackVisible || isResizing; } + private class BarWindow { + + private final int mId; + private @StatusBarManager.WindowVisibleState int mState = + StatusBarManager.WINDOW_STATE_SHOWING; + + BarWindow(int id) { + mId = id; + } + + private void setVisible(boolean visible) { + final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN; + if (mState != state) { + mState = state; + mPolicy.getStatusBarManagerInternal().setWindowState( + mDisplayContent.getDisplayId(), mId, state); + } + } + } + + // TODO(b/118118435): Implement animations for it (with SurfaceAnimator) + private class TransientControlTarget implements InsetsControlTarget { + + @Override + public void notifyInsetsControlChanged() { + } + } } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 3731d3f38800..a7724a11eec2 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -111,7 +111,9 @@ class InsetsSourceProvider { void setWindow(@Nullable WindowState win, @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) { if (mWin != null) { - mWin.setInsetProvider(null); + if (mControllable) { + mWin.setControllableInsetProvider(null); + } // The window may be animating such that we can hand out the leash to the control // target. Revoke the leash by cancelling the animation to correct the state. // TODO: Ideally, we should wait for the animation to finish so previous window can @@ -123,8 +125,8 @@ class InsetsSourceProvider { if (win == null) { setServerVisible(false); mSource.setFrame(new Rect()); - } else { - mWin.setInsetProvider(this); + } else if (mControllable) { + mWin.setControllableInsetProvider(this); if (mControlTarget != null) { updateControlForTarget(mControlTarget, true /* force */); } @@ -132,6 +134,13 @@ class InsetsSourceProvider { } /** + * @return Whether there is a window which backs this source. + */ + boolean hasWindow() { + return mWin != null; + } + + /** * Called when a layout pass has occurred. */ void onPostLayout() { @@ -225,6 +234,10 @@ class InsetsSourceProvider { return null; } + InsetsControlTarget getControlTarget() { + return mControlTarget; + } + boolean isClientVisible() { return sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible; } @@ -241,9 +254,13 @@ class InsetsSourceProvider { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, OnAnimationFinishedCallback finishCallback) { - // TODO: use 0 alpha and remove t.hide() once b/138459974 is fixed. - t.setAlpha(animationLeash, 1 /* alpha */); - t.hide(animationLeash); + // TODO(b/118118435): We can remove the type check when implementing the transient bar + // animation. + if (mSource.getType() == TYPE_IME) { + // TODO: use 0 alpha and remove t.hide() once b/138459974 is fixed. + t.setAlpha(animationLeash, 1 /* alpha */); + t.hide(animationLeash); + } mCapturedLeash = animationLeash; final Rect frame = mWin.getWindowFrames().mFrame; diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index b0410335c5cd..e0554242fb29 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.view.InsetsState.InternalInsetType; import static android.view.InsetsState.TYPE_IME; import static android.view.InsetsState.TYPE_NAVIGATION_BAR; import static android.view.InsetsState.TYPE_TOP_BAR; @@ -31,6 +30,7 @@ import android.util.SparseArray; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; +import android.view.InsetsState.InternalInsetType; import java.io.PrintWriter; import java.util.ArrayList; @@ -73,7 +73,7 @@ class InsetsStateController { * @return The state stripped of the necessary information. */ InsetsState getInsetsForDispatch(WindowState target) { - final InsetsSourceProvider provider = target.getInsetProvider(); + final InsetsSourceProvider provider = target.getControllableInsetProvider(); if (provider == null) { return mState; } @@ -123,6 +123,13 @@ class InsetsStateController { } /** + * @return The provider of a specific type or null if we don't have it. + */ + @Nullable InsetsSourceProvider peekSourceProvider(@InternalInsetType int type) { + return mProviders.get(type); + } + + /** * Called when a layout pass has occurred. */ void onPostLayout() { @@ -152,6 +159,10 @@ class InsetsStateController { } } + boolean isFakeTarget(@InternalInsetType int type, InsetsControlTarget target) { + return mTypeFakeControlTargetMap.get(type) == target; + } + void onImeTargetChanged(@Nullable InsetsControlTarget imeTarget) { onControlChanged(TYPE_IME, imeTarget); notifyPendingInsetsControlChanged(); @@ -166,9 +177,13 @@ class InsetsStateController { * and visibility. */ void onBarControlTargetChanged(@Nullable InsetsControlTarget topControlling, - @Nullable InsetsControlTarget navControlling) { + @Nullable InsetsControlTarget fakeTopControlling, + @Nullable InsetsControlTarget navControlling, + @Nullable InsetsControlTarget fakeNavControlling) { onControlChanged(TYPE_TOP_BAR, topControlling); onControlChanged(TYPE_NAVIGATION_BAR, navControlling); + onControlFakeTargetChanged(TYPE_TOP_BAR, fakeTopControlling); + onControlFakeTargetChanged(TYPE_NAVIGATION_BAR, fakeNavControlling); notifyPendingInsetsControlChanged(); } @@ -279,7 +294,7 @@ class InsetsStateController { }); } - private void notifyInsetsChanged() { + void notifyInsetsChanged() { mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */); } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index b047d8f8a7b9..06e7d665bb42 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -465,7 +465,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { final WindowState windowState = mService.windowForClientLocked(this, window, false /* throwOnError */); if (windowState != null) { - windowState.getDisplayContent().getInsetsStateController().onInsetsModified( + windowState.setClientInsetsState(state); + windowState.getDisplayContent().getInsetsPolicy().onInsetsModified( windowState, state); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c48528042348..56ff064494fa 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1663,7 +1663,7 @@ public class WindowManagerService extends IWindowManager.Stub outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) { res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS; } - outInsetsState.set(displayContent.getInsetsStateController().getInsetsForDispatch(win)); + outInsetsState.set(displayContent.getInsetsPolicy().getInsetsForDispatch(win)); if (mInTouchMode) { res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; @@ -2356,7 +2356,7 @@ public class WindowManagerService extends IWindowManager.Stub outStableInsets, outOutsets); outCutout.set(win.getWmDisplayCutout().getDisplayCutout()); outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw())); - outInsetsState.set(displayContent.getInsetsStateController().getInsetsForDispatch(win)); + outInsetsState.set(displayContent.getInsetsPolicy().getInsetsForDispatch(win)); if (DEBUG) { Slog.v(TAG_WM, "Relayout given client " + client.asBinder() + ", requestedWidth=" + requestedWidth @@ -5574,6 +5574,20 @@ public class WindowManagerService extends IWindowManager.Stub } @Override + public void hideTransientBars(int displayId) { + mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR, + "hideTransientBars()"); + synchronized (mGlobalLock) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent != null) { + displayContent.hideTransientBars(); + } else { + Slog.w(TAG, "hideTransientBars with invalid displayId=" + displayId); + } + } + } + + @Override public void setForceShowSystemBars(boolean show) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) != PackageManager.PERMISSION_GRANTED) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 7ff9b7057653..3ec949f94783 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -31,6 +31,7 @@ import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_ import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE; +import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; @@ -191,6 +192,7 @@ import android.view.InputChannel; import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.InputWindowHandle; +import android.view.InsetsState; import android.view.Surface.Rotation; import android.view.SurfaceControl; import android.view.SurfaceSession; @@ -633,11 +635,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ private boolean mIsDimming = false; - private @Nullable InsetsSourceProvider mInsetProvider; + private @Nullable InsetsSourceProvider mControllableInsetProvider; + private InsetsState mClientInsetsState = new InsetsState(); private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f; private KeyInterceptionInfo mKeyInterceptionInfo; + InsetsState getClientInsetsState() { + return mClientInsetsState; + } + + void setClientInsetsState(InsetsState state) { + mClientInsetsState = state; + } + void seamlesslyRotateIfAllowed(Transaction transaction, @Rotation int oldRotation, @Rotation int rotation, boolean requested) { // Invisible windows and the wallpaper do not participate in the seamless rotation animation @@ -1492,7 +1503,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return wouldBeVisibleIfPolicyIgnored() && isVisibleByPolicy() // If we don't have a provider, this window isn't used as a window generating // insets, so nobody can hide it over the inset APIs. - && (mInsetProvider == null || mInsetProvider.isClientVisible()); + && (mControllableInsetProvider == null + || mControllableInsetProvider.isClientVisible()); } /** @@ -3350,7 +3362,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP void notifyInsetsChanged() { try { mClient.insetsChanged( - getDisplayContent().getInsetsStateController().getInsetsForDispatch(this)); + getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this)); } catch (RemoteException e) { Slog.w(TAG, "Failed to deliver inset state change", e); } @@ -3360,8 +3372,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP public void notifyInsetsControlChanged() { final InsetsStateController stateController = getDisplayContent().getInsetsStateController(); + final InsetsPolicy policy = getDisplayContent().getInsetsPolicy(); try { - mClient.insetsControlChanged(stateController.getInsetsForDispatch(this), + mClient.insetsControlChanged(policy.getInsetsForDispatch(this), stateController.getControlsForDispatch(this)); } catch (RemoteException e) { Slog.w(TAG, "Failed to deliver inset state change", e); @@ -3386,6 +3399,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + @Override + public boolean canShowTransient() { + return (mAttrs.insetsFlags.behavior & BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) != 0; + } + Rect getBackdropFrame(Rect frame) { // When the task is docked, we send fullscreen sized backDropFrame as soon as resizing // start even if we haven't received the relayout window, so that the client requests @@ -4814,7 +4832,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP void startAnimation(Animation anim) { // If we are an inset provider, all our animations are driven by the inset client. - if (mInsetProvider != null && mInsetProvider.isControllable()) { + if (mControllableInsetProvider != null) { return; } @@ -4834,7 +4852,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private void startMoveAnimation(int left, int top) { // If we are an inset provider, all our animations are driven by the inset client. - if (mInsetProvider != null && mInsetProvider.isControllable()) { + if (mControllableInsetProvider != null) { return; } @@ -5318,12 +5336,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWindowFrames.setContentChanged(false); } - void setInsetProvider(InsetsSourceProvider insetProvider) { - mInsetProvider = insetProvider; + /** + * Set's an {@link InsetsSourceProvider} to be associated with this window, but only if the + * provider itself is controllable, as one window can be the provider of more than one inset + * type (i.e. gesture insets). If this window is controllable, all its animations must be + * controlled by its control target, and the visibility of this window should be taken account + * into the state of the control target. + * + * @param insetProvider the provider which should not be visible to the client. + * @see InsetsStateController#getInsetsForDispatch(WindowState) + */ + void setControllableInsetProvider(InsetsSourceProvider insetProvider) { + mControllableInsetProvider = insetProvider; } - InsetsSourceProvider getInsetProvider() { - return mInsetProvider; + InsetsSourceProvider getControllableInsetProvider() { + return mControllableInsetProvider; } private final class MoveAnimationSpec implements AnimationSpec { diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index f3a8e1a0bd5e..8c2ae5a7659a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.view.InsetsState.TYPE_TOP_BAR; import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; @@ -32,7 +33,9 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import android.platform.test.annotations.Presubmit; +import android.util.IntArray; import android.view.InsetsSourceControl; +import android.view.InsetsState; import android.view.test.InsetsModeSession; import androidx.test.filters.FlakyTest; @@ -151,6 +154,91 @@ public class InsetsPolicyTest extends WindowTestsBase { assertEquals(1, controls.length); } + @Test + public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() { + addWindow(TYPE_STATUS_BAR, "topBar") + .getControllableInsetProvider().getSource().setVisible(false); + addWindow(TYPE_NAVIGATION_BAR, "navBar") + .getControllableInsetProvider().getSource().setVisible(false); + final WindowState app = addWindow(TYPE_APPLICATION, "app"); + + final InsetsPolicy policy = mDisplayContent.getInsetsPolicy(); + policy.updateBarControlTarget(app); + policy.showTransient( + IntArray.wrap(new int[]{TYPE_TOP_BAR, InsetsState.TYPE_NAVIGATION_BAR})); + final InsetsSourceControl[] controls = + mDisplayContent.getInsetsStateController().getControlsForDispatch(app); + + // The app must get both fake controls. + assertEquals(2, controls.length); + for (int i = controls.length - 1; i >= 0; i--) { + assertNull(controls[i].getLeash()); + } + } + + @Test + public void testShowTransientBars_topCanBeTransient_appGetsTopFakeControl() { + addWindow(TYPE_STATUS_BAR, "topBar") + .getControllableInsetProvider().getSource().setVisible(false); + addWindow(TYPE_NAVIGATION_BAR, "navBar") + .getControllableInsetProvider().getSource().setVisible(true); + final WindowState app = addWindow(TYPE_APPLICATION, "app"); + + final InsetsPolicy policy = mDisplayContent.getInsetsPolicy(); + policy.updateBarControlTarget(app); + policy.showTransient( + IntArray.wrap(new int[]{TYPE_TOP_BAR, InsetsState.TYPE_NAVIGATION_BAR})); + final InsetsSourceControl[] controls = + mDisplayContent.getInsetsStateController().getControlsForDispatch(app); + + // The app must get the fake control of the top bar, and must get the real control of the + // navigation bar. + assertEquals(2, controls.length); + for (int i = controls.length - 1; i >= 0; i--) { + final InsetsSourceControl control = controls[i]; + if (control.getType() == TYPE_TOP_BAR) { + assertNull(controls[i].getLeash()); + } else { + assertNotNull(controls[i].getLeash()); + } + } + } + + @Test + public void testAbortTransientBars_bothCanBeAborted_appGetsBothRealControls() { + addWindow(TYPE_STATUS_BAR, "topBar") + .getControllableInsetProvider().getSource().setVisible(false); + addWindow(TYPE_NAVIGATION_BAR, "navBar") + .getControllableInsetProvider().getSource().setVisible(false); + final WindowState app = addWindow(TYPE_APPLICATION, "app"); + + final InsetsPolicy policy = mDisplayContent.getInsetsPolicy(); + policy.updateBarControlTarget(app); + policy.showTransient( + IntArray.wrap(new int[]{TYPE_TOP_BAR, InsetsState.TYPE_NAVIGATION_BAR})); + InsetsSourceControl[] controls = + mDisplayContent.getInsetsStateController().getControlsForDispatch(app); + + // The app must get both fake controls. + assertEquals(2, controls.length); + for (int i = controls.length - 1; i >= 0; i--) { + assertNull(controls[i].getLeash()); + } + + final InsetsState state = policy.getInsetsForDispatch(app); + state.setSourceVisible(TYPE_TOP_BAR, true); + state.setSourceVisible(InsetsState.TYPE_NAVIGATION_BAR, true); + policy.onInsetsModified(app, state); + + controls = mDisplayContent.getInsetsStateController().getControlsForDispatch(app); + + // The app must get both real controls. + assertEquals(2, controls.length); + for (int i = controls.length - 1; i >= 0; i--) { + assertNotNull(controls[i].getLeash()); + } + } + private WindowState addWindow(int type, String name) { final WindowState win = createWindow(null, type, name); mDisplayContent.getDisplayPolicy().addWindowLw(win, win.mAttrs); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 81ea32bb4f73..011161b4f063 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -66,7 +66,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); getController().getSourceProvider(TYPE_TOP_BAR).setWindow(topBar, null); - topBar.setInsetProvider(getController().getSourceProvider(TYPE_TOP_BAR)); + topBar.setControllableInsetProvider(getController().getSourceProvider(TYPE_TOP_BAR)); assertNotNull(getController().getInsetsForDispatch(app).getSource(TYPE_TOP_BAR)); } @@ -75,7 +75,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR) .setWindow(topBar, null); - topBar.setInsetProvider(getController().getSourceProvider(TYPE_TOP_BAR)); + topBar.setControllableInsetProvider(getController().getSourceProvider(TYPE_TOP_BAR)); final InsetsState state = getController().getInsetsForDispatch(topBar); for (int i = state.getSourcesCount() - 1; i >= 0; i--) { final InsetsSource source = state.sourceAt(i); @@ -101,7 +101,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); getController().getSourceProvider(TYPE_TOP_BAR).setWindow(topBar, null); getController().getSourceProvider(TYPE_NAVIGATION_BAR).setWindow(navBar, null); - getController().onBarControlTargetChanged(app, app); + getController().onBarControlTargetChanged(app, null, app, null); InsetsSourceControl[] controls = getController().getControlsForDispatch(app); assertEquals(2, controls.length); } @@ -111,9 +111,9 @@ public class InsetsStateControllerTest extends WindowTestsBase { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); getController().getSourceProvider(TYPE_TOP_BAR).setWindow(topBar, null); - getController().onBarControlTargetChanged(app, null); + getController().onBarControlTargetChanged(app, null, null, null); assertNotNull(getController().getControlsForDispatch(app)); - getController().onBarControlTargetChanged(null, null); + getController().onBarControlTargetChanged(null, null, null, null); assertNull(getController().getControlsForDispatch(app)); } @@ -123,7 +123,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); getController().getSourceProvider(TYPE_TOP_BAR).setWindow(topBar, null); - getController().onBarControlTargetChanged(app, null); + getController().onBarControlTargetChanged(app, null, null, null); assertNotNull(getController().getControlsForDispatch(app)); topBar.cancelAnimation(); assertNull(getController().getControlsForDispatch(app)); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index a09253ab31f0..447880a0f019 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -397,14 +397,15 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testVisibleWithInsetsProvider() throws Exception { + public void testVisibleWithInsetsProvider() { final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); topBar.mHasSurface = true; assertTrue(topBar.isVisible()); mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR) - .setWindow(topBar, null); - mDisplayContent.getInsetsStateController().onBarControlTargetChanged(app, app); + .setWindow(topBar, null /* frameProvider */); + mDisplayContent.getInsetsStateController().onBarControlTargetChanged( + app, null /* fakeTopControlling */, app, null /* fakeNavControlling */); mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR) .onInsetsModified(app, new InsetsSource(TYPE_TOP_BAR)); waitUntilHandlersIdle(); diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java index c9e3404e0f1a..957216e17925 100644 --- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java +++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java @@ -41,6 +41,7 @@ public final class FrameworksTestsFilter extends SelectTest { "android.view.DisplayCutoutTest", "android.view.InsetsAnimationControlImplTest", "android.view.InsetsControllerTest", + "android.view.InsetsFlagsTest", "android.view.InsetsSourceTest", "android.view.InsetsSourceConsumerTest", "android.view.InsetsStateTest", |