diff options
43 files changed, 1640 insertions, 654 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..b21a9f7c4d05 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,9 +95,12 @@ public interface StatusBarStateController { default void onDozeAmountChanged(float linear, float eased) {} /** - * Callback to be notified when the sysui visibility changes + * Callback to be notified when the fullscreen or immersive state changes. + * + * @param isFullscreen if any of the system bar is hidden by the focused window. + * @param isImmersive if the navigation bar can stay hidden when the display gets tapped. */ - default void onSystemUiVisibilityChanged(int visibility) {} + default void onFullscreenStateChanged(boolean isFullscreen, boolean isImmersive) {} /** * Callback to be notified when the pulsing state changes 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..e81e5cae5bfc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -21,7 +21,6 @@ import android.animation.ValueAnimator; import android.text.format.DateFormat; import android.util.FloatProperty; import android.util.Log; -import android.view.View; import android.view.animation.Interpolator; import com.android.internal.annotations.GuardedBy; @@ -80,9 +79,14 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll private HistoricalState[] mHistoricalRecords = new HistoricalState[HISTORY_SIZE]; /** - * Current SystemUiVisibility + * If any of the system bars is hidden. */ - private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; + private boolean mIsFullscreen = false; + + /** + * If the navigation bar can stay hidden when the display gets tapped. + */ + private boolean mIsImmersive = false; /** * If the device is currently pulsing (AOD2). @@ -320,12 +324,13 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll } @Override - public void setSystemUiVisibility(int visibility) { - if (mSystemUiVisibility != visibility) { - mSystemUiVisibility = visibility; + public void setFullscreenState(boolean isFullscreen, boolean isImmersive) { + if (mIsFullscreen != isFullscreen || mIsImmersive != isImmersive) { + mIsFullscreen = isFullscreen; + mIsImmersive = isImmersive; synchronized (mListeners) { for (RankedListener rl : new ArrayList<>(mListeners)) { - rl.mListener.onSystemUiVisibilityChanged(mSystemUiVisibility); + rl.mListener.onFullscreenStateChanged(isFullscreen, isImmersive); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java index 2ad979ab64e3..07b35502478f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java @@ -111,9 +111,9 @@ public interface SysuiStatusBarStateController extends StatusBarStateController boolean isKeyguardRequested(); /** - * Set systemui visibility + * Set the fullscreen state */ - void setSystemUiVisibility(int visibility); + void setFullscreenState(boolean isFullscreen, boolean isImmersive); /** * Set pulsing 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 ae18833d99b5..4b4a35bae05d 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 8e70d082dbb6..145be4899f8d 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; @@ -428,10 +435,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; @@ -826,10 +836,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); @@ -2230,49 +2252,104 @@ 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; + mStatusBarStateController.setFullscreenState(isFullscreen, isImmersive); } @Override @@ -2303,40 +2380,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, @@ -2392,20 +2439,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) { @@ -4729,8 +4772,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 940e8148444c..aa0b68b9bfc5 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 150e26eefe4e..8877e4c47da7 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..fc51b467c8d4 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,132 @@ 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)); + if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) { + return; + } + 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 +189,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 +205,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 +239,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 2dd6d0aaba5b..e90f3da96409 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 c25a71d71175..b9cf29ad7790 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 @@ -1493,7 +1504,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()); } /** @@ -3351,7 +3363,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); } @@ -3361,8 +3373,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); @@ -3387,6 +3400,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 @@ -4815,7 +4833,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; } @@ -4835,7 +4853,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; } @@ -5319,12 +5337,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 1a4562b69bd4..98d73bacffb3 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", |