Replace OnContentApplyWindowInsetsListener with simple boolean
The concept will move into the support library (androidx), so in
the framework we only need a simple boolean to toggle the default
behavior.
Also remove redundant methods on WIC to control IME.
Bug: 143556682
Bug: 118118435
Test: WindowTest CTS
Change-Id: I30fbffdfbe79a57b0f4166f0657c78370c7bcf02
diff --git a/api/current.txt b/api/current.txt
index 1306bfa..d5a0ba4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -54811,7 +54811,6 @@
method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener);
method public boolean requestFeature(int);
method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
- method public void resetOnContentApplyWindowInsetsListener();
method public abstract void restoreHierarchyState(android.os.Bundle);
method public abstract android.os.Bundle saveHierarchyState();
method public void setAllowEnterTransitionOverlap(boolean);
@@ -54829,6 +54828,7 @@
method public abstract void setContentView(android.view.View);
method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public abstract void setDecorCaptionShade(int);
+ method public void setDecorFitsSystemWindows(boolean);
method protected void setDefaultWindowFormat(int);
method public void setDimAmount(float);
method public void setElevation(float);
@@ -54850,7 +54850,6 @@
method public abstract void setNavigationBarColor(@ColorInt int);
method public void setNavigationBarContrastEnforced(boolean);
method public void setNavigationBarDividerColor(@ColorInt int);
- method public void setOnContentApplyWindowInsetsListener(@Nullable android.view.Window.OnContentApplyWindowInsetsListener);
method public void setPreferMinimalPostProcessing(boolean);
method public void setReenterTransition(android.transition.Transition);
method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
@@ -54945,10 +54944,6 @@
method @Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
}
- public static interface Window.OnContentApplyWindowInsetsListener {
- method @NonNull public android.util.Pair<android.graphics.Insets,android.view.WindowInsets> onContentApplyWindowInsets(@NonNull android.view.WindowInsets);
- }
-
public static interface Window.OnFrameMetricsAvailableListener {
method public void onFrameMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
}
@@ -55099,16 +55094,13 @@
}
public interface WindowInsetsController {
- method public default void controlInputMethodAnimation(long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
method public void controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
method public int getSystemBarsAppearance();
method public int getSystemBarsBehavior();
method public void hide(int);
- method public default void hideInputMethod();
method public void setSystemBarsAppearance(int, int);
method public void setSystemBarsBehavior(int);
method public void show(int);
- method public default void showInputMethod();
field public static final int APPEARANCE_LIGHT_NAVIGATION_BARS = 16; // 0x10
field public static final int APPEARANCE_LIGHT_STATUS_BARS = 8; // 0x8
field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d70bf22f..ee7f6fb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3654,8 +3654,7 @@
*
* @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with
* {@link Type#navigationBars()}. For non-floating windows that fill the screen, call
- * {@link Window#setOnContentApplyWindowInsetsListener} with {@code null} or a listener that
- * doesn't fit the navigation bar on the window content level.
+ * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}.
*/
public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;
@@ -3683,8 +3682,7 @@
*
* @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with
* {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call
- * {@link Window#setOnContentApplyWindowInsetsListener} with {@code null} or a listener that
- * doesn't fit the status bar on the window content level.
+ * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}.
*/
@Deprecated
public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;
@@ -4673,7 +4671,7 @@
private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners;
- private WindowInsetsAnimationCallback mWindowInsetsAnimationCallback;
+ WindowInsetsAnimationCallback mWindowInsetsAnimationCallback;
/**
* This lives here since it's only valid for interactive views.
@@ -11537,7 +11535,7 @@
}
/**
- * @see #PFLAG4_OPTIONAL_FITS_SYSTEM_WINDOWS
+ * @see #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS
* @hide
*/
public void makeFrameworkOptionalFitsSystemWindows() {
@@ -11545,6 +11543,13 @@
}
/**
+ * @hide
+ */
+ public boolean isFrameworkOptionalFitsSystemWindows() {
+ return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0;
+ }
+
+ /**
* Returns the visibility status for this view.
*
* @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4f03ca1..d416d42 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7239,6 +7239,18 @@
public void dispatchWindowInsetsAnimationPrepare(
@NonNull InsetsAnimation animation) {
super.dispatchWindowInsetsAnimationPrepare(animation);
+
+ // If we are root-level content view that fits insets, set dispatch mode to stop to imitate
+ // consume behavior.
+ boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0
+ || isFrameworkOptionalFitsSystemWindows();
+ if (isOptionalFitSystemWindows && mAttachInfo != null
+ && getListenerInfo().mWindowInsetsAnimationCallback == null
+ && mAttachInfo.mContentOnApplyWindowInsetsListener != null) {
+ mInsetsAnimationDispatchMode = DISPATCH_MODE_STOP;
+ return;
+ }
+
if (mInsetsAnimationDispatchMode == DISPATCH_MODE_STOP) {
return;
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 0ef4e33..4b284db 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -697,12 +697,10 @@
}
/**
- * Listener for applying window insets on the content of a window in a custom way.
+ * Listener for applying window insets on the content of a window. Used only by the framework to
+ * fit content according to legacy SystemUI flags.
*
- * <p>Apps may choose to implement this interface if they want to apply custom policy
- * to the way that window insets are treated for fitting root-level content views.
- *
- * @see Window#setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener)
+ * @hide
*/
public interface OnContentApplyWindowInsetsListener {
@@ -716,13 +714,15 @@
*
* @param insets The root level insets that are about to be dispatched
* @return A pair, with the first element containing the insets to apply as margin to the
- * root-level content views, and the second element determining what should be
- * dispatched to the content view.
+ * root-level content views, and the second element determining what should be
+ * dispatched to the content view.
*/
- @NonNull Pair<Insets, WindowInsets> onContentApplyWindowInsets(
+ @NonNull
+ Pair<Insets, WindowInsets> onContentApplyWindowInsets(
@NonNull WindowInsets insets);
}
+
public Window(Context context) {
mContext = context;
mFeatures = mLocalFeatures = getDefaultFeatures(context);
@@ -1311,33 +1311,21 @@
}
/**
- * Sets the listener to be invoked when fitting root-level content views.
+ * Sets whether the decor view should fit root-level content views for {@link WindowInsets}.
* <p>
- * By default, a listener that inspects the now deprecated {@link View#SYSTEM_UI_LAYOUT_FLAGS}
- * as well the {@link WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} flag is installed and
- * fits content according to these flags.
+ * If set to {@code true}, the framework will inspect the now deprecated
+ * {@link View#SYSTEM_UI_LAYOUT_FLAGS} as well the
+ * {@link WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} flag and fits content according
+ * to these flags.
* </p>
- * @param contentOnApplyWindowInsetsListener The listener to use for fitting root-level content
- * views, or {@code null} to disable any kind of
- * content fitting on the window level and letting the
- * {@link WindowInsets} pass through to the content
- * view.
- * @see OnContentApplyWindowInsetsListener
- */
- public void setOnContentApplyWindowInsetsListener(
- @Nullable OnContentApplyWindowInsetsListener contentOnApplyWindowInsetsListener) {
- }
-
- /**
- * Resets the listener set via {@link #setOnContentApplyWindowInsetsListener} to the default
- * state.
* <p>
- * By default, a listener that inspects the now deprecated {@link View#SYSTEM_UI_LAYOUT_FLAGS}
- * as well the {@link WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} flag is installed and
- * fits content according to these flags.
+ * If set to {@code false}, the framework will not fit the content view to the insets and will
+ * just pass through the {@link WindowInsets} to the content view.
* </p>
+ * @param decorFitsSystemWindows Whether the decor view should fit root-level content views for
+ * insets.
*/
- public void resetOnContentApplyWindowInsetsListener() {
+ public void setDecorFitsSystemWindows(boolean decorFitsSystemWindows) {
}
/**
diff --git a/core/java/android/view/WindowInsetsAnimationCallback.java b/core/java/android/view/WindowInsetsAnimationCallback.java
index 1e04d02..4c8463b3 100644
--- a/core/java/android/view/WindowInsetsAnimationCallback.java
+++ b/core/java/android/view/WindowInsetsAnimationCallback.java
@@ -86,9 +86,9 @@
* following:
* <p>
* <ul>
- * <li>Application calls {@link WindowInsetsController#hideInputMethod()},
- * {@link WindowInsetsController#showInputMethod()},
- * {@link WindowInsetsController#controlInputMethodAnimation}</li>
+ * <li>Application calls {@link WindowInsetsController#hide(int)},
+ * {@link WindowInsetsController#show(int)},
+ * {@link WindowInsetsController#controlWindowInsetsAnimation}</li>
* <li>onPrepare is called on the view hierarchy listeners</li>
* <li>{@link View#onApplyWindowInsets} will be called with the end state of the
* animation</li>
@@ -106,12 +106,12 @@
* related methods.
* <p>
* Note: If the animation is application controlled by using
- * {@link WindowInsetsController#controlInputMethodAnimation}, the end state of the animation
+ * {@link WindowInsetsController#controlWindowInsetsAnimation}, the end state of the animation
* is undefined as the application may decide on the end state only by passing in the
* {@code shown} parameter when calling {@link WindowInsetsAnimationController#finish}. In this
* situation, the system will dispatch the insets in the opposite visibility state before the
* animation starts. Example: When controlling the input method with
- * {@link WindowInsetsController#controlInputMethodAnimation} and the input method is currently
+ * {@link WindowInsetsController#controlWindowInsetsAnimation} and the input method is currently
* showing, {@link View#onApplyWindowInsets} will receive a {@link WindowInsets} instance for
* which {@link WindowInsets#isVisible} will return {@code false} for {@link Type#ime}.
*
@@ -246,7 +246,7 @@
* be the same as the application passed into
* {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)},
* interpolated with the interpolator passed into
- * {@link WindowInsetsController#controlInputMethodAnimation}.
+ * {@link WindowInsetsController#controlWindowInsetsAnimation}.
* </p>
* <p>
* Note: For system-initiated animations, this will always return a valid value between 0
diff --git a/core/java/android/view/WindowInsetsAnimationControlListener.java b/core/java/android/view/WindowInsetsAnimationControlListener.java
index f91254d..701bd31 100644
--- a/core/java/android/view/WindowInsetsAnimationControlListener.java
+++ b/core/java/android/view/WindowInsetsAnimationControlListener.java
@@ -39,7 +39,7 @@
* @param controller The controller to control the inset animation.
* @param types The {@link InsetsType}s it was able to gain control over. Note that this may be
* different than the types passed into
- * {@link WindowInsetsController#controlInputMethodAnimation} in case the window
+ * {@link WindowInsetsController#controlWindowInsetsAnimation} in case the window
* wasn't able to gain the controls because it wasn't the IME target or not
* currently the window that's controlling the system bars.
*/
diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java
index 2bf0d27..4a864be 100644
--- a/core/java/android/view/WindowInsetsAnimationController.java
+++ b/core/java/android/view/WindowInsetsAnimationController.java
@@ -23,6 +23,7 @@
import android.graphics.Insets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
+import android.view.animation.Interpolator;
/**
* Controller for app-driven animation of system windows.
@@ -32,7 +33,7 @@
* synchronized, such that changes the system windows and the app's current frame
* are rendered at the same time.
* <p>
- * Control is obtained through {@link WindowInsetsController#controlInputMethodAnimation}.
+ * Control is obtained through {@link WindowInsetsController#controlWindowInsetsAnimation}.
*/
@SuppressLint("NotClosable")
public interface WindowInsetsAnimationController {
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index 02323cf..f501de9 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -167,62 +167,6 @@
@NonNull WindowInsetsAnimationControlListener listener);
/**
- * Lets the application control the animation for showing the IME in a frame-by-frame manner by
- * modifying the position of the IME when it's causing insets.
- *
- * @param durationMillis Duration of the animation in
- * {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or -1 if the
- * animation doesn't have a predetermined duration. This value will be
- * passed to {@link InsetsAnimation#getDurationMillis()}
- * @param interpolator The interpolator used for this animation, or {@code null} if this
- * animation doesn't follow an interpolation curve. This value will be
- * passed to {@link InsetsAnimation#getInterpolator()} and used to calculate
- * {@link InsetsAnimation#getInterpolatedFraction()}.
- * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
- * IME are ready to be controlled, among other callbacks.
- *
- * @see InsetsAnimation#getFraction()
- * @see InsetsAnimation#getInterpolatedFraction()
- * @see InsetsAnimation#getInterpolator()
- * @see InsetsAnimation#getDurationMillis()
- */
- default void controlInputMethodAnimation(long durationMillis,
- @Nullable Interpolator interpolator,
- @NonNull WindowInsetsAnimationControlListener listener) {
- controlWindowInsetsAnimation(ime(), durationMillis, interpolator, listener);
- }
-
- /**
- * Makes the IME appear on screen.
- * <p>
- * Note that if the window currently doesn't have control over the IME, because it doesn't have
- * focus, it will apply the change as soon as the window gains control. The app can listen to
- * the event by observing {@link View#onApplyWindowInsets} and checking visibility with
- * {@link WindowInsets#isVisible}.
- *
- * @see #controlInputMethodAnimation
- * @see #hideInputMethod()
- */
- default void showInputMethod() {
- show(ime());
- }
-
- /**
- * Makes the IME disappear on screen.
- * <p>
- * Note that if the window currently doesn't have control over IME, because it doesn't have
- * focus, it will apply the change as soon as the window gains control. The app can listen to
- * the event by observing {@link View#onApplyWindowInsets} and checking visibility with
- * {@link WindowInsets#isVisible}.
- *
- * @see #controlInputMethodAnimation
- * @see #showInputMethod()
- */
- default void hideInputMethod() {
- hide(ime());
- }
-
- /**
* Controls the appearance of system bars.
* <p>
* For example, the following statement adds {@link #APPEARANCE_LIGHT_STATUS_BARS}:
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index a6450a1..dad7671 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -80,6 +80,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import android.view.View.OnApplyWindowInsetsListener;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type;
@@ -2193,8 +2194,9 @@
* value for {@link #softInputMode} will be ignored; the window will
* not resize, but will stay fullscreen.
*
- * @deprecated Use {@link Window#setOnContentApplyWindowInsetsListener} instead with a
- * listener that fits {@link Type#ime()} instead.
+ * @deprecated Call {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false} and
+ * install an {@link OnApplyWindowInsetsListener} on your root content view that fits insets
+ * of type {@link Type#ime()}.
*/
@Deprecated
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index f13a638..5e69a5f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -320,7 +320,8 @@
/** @see ViewRootImpl#mActivityConfigCallback */
private ActivityConfigCallback mActivityConfigCallback;
- private OnContentApplyWindowInsetsListener mPendingOnContentApplyWindowInsetsListener;
+ private OnContentApplyWindowInsetsListener mPendingOnContentApplyWindowInsetsListener
+ = createDefaultContentWindowInsetsListener();
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -2109,14 +2110,9 @@
/** Notify when decor view is attached to window and {@link ViewRootImpl} is available. */
void onViewRootImplSet(ViewRootImpl viewRoot) {
viewRoot.setActivityConfigCallback(mActivityConfigCallback);
- if (mPendingOnContentApplyWindowInsetsListener != null) {
- viewRoot.setOnContentApplyWindowInsetsListener(
- mPendingOnContentApplyWindowInsetsListener);
- mPendingOnContentApplyWindowInsetsListener = null;
- } else {
- viewRoot.setOnContentApplyWindowInsetsListener(
- createDefaultContentWindowInsetsListener());
- }
+ viewRoot.setOnContentApplyWindowInsetsListener(
+ mPendingOnContentApplyWindowInsetsListener);
+ mPendingOnContentApplyWindowInsetsListener = null;
}
private OnContentApplyWindowInsetsListener createDefaultContentWindowInsetsListener() {
@@ -3902,17 +3898,15 @@
}
@Override
- public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
+ public void setDecorFitsSystemWindows(boolean decorFitsSystemWindows) {
ViewRootImpl impl = getViewRootImpl();
+ OnContentApplyWindowInsetsListener listener = decorFitsSystemWindows
+ ? createDefaultContentWindowInsetsListener()
+ : null;
if (impl != null) {
impl.setOnContentApplyWindowInsetsListener(listener);
} else {
mPendingOnContentApplyWindowInsetsListener = listener;
}
}
-
- @Override
- public void resetOnContentApplyWindowInsetsListener() {
- setOnContentApplyWindowInsetsListener(createDefaultContentWindowInsetsListener());
- }
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index e68c4b8..576e04f 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -432,7 +432,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener listener =
mock(WindowInsetsAnimationControlListener.class);
- mController.controlInputMethodAnimation(0, new LinearInterpolator(), listener);
+ mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener);
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -456,7 +456,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener listener =
mock(WindowInsetsAnimationControlListener.class);
- mController.controlInputMethodAnimation(0, new LinearInterpolator(), listener);
+ mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener);
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -476,7 +476,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener listener =
mock(WindowInsetsAnimationControlListener.class);
- mController.controlInputMethodAnimation(0, new LinearInterpolator(), listener);
+ mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener);
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();