Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b16b599 authored by Jorim Jaggi's avatar Jorim Jaggi Committed by Android (Google) Code Review
Browse files

Merge "Fix up new insets dispatch behavior"

parents ae0c9546 6d13bf4a
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -54027,9 +54027,9 @@ package android.view {
  public final class WindowInsets {
    ctor public WindowInsets(android.view.WindowInsets);
    method @NonNull public android.view.WindowInsets consumeDisplayCutout();
    method @NonNull public android.view.WindowInsets consumeStableInsets();
    method @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
    method @Deprecated @NonNull public android.view.WindowInsets consumeDisplayCutout();
    method @Deprecated @NonNull public android.view.WindowInsets consumeStableInsets();
    method @Deprecated @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
    method @Nullable public android.view.DisplayCutout getDisplayCutout();
    method @NonNull public android.graphics.Insets getInsets(int);
    method @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
@@ -54055,6 +54055,7 @@ package android.view {
    method public boolean isVisible(int);
    method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
    method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
    field @NonNull public static final android.view.WindowInsets CONSUMED;
  }
  public static final class WindowInsets.Builder {
@@ -54086,10 +54087,13 @@ package android.view {
  }
  public interface WindowInsetsAnimationCallback {
    method public int getDispatchMode();
    method public default void onFinish(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
    method public default void onPrepare(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation);
    method @NonNull public android.view.WindowInsets onProgress(@NonNull android.view.WindowInsets);
    method @NonNull public default android.view.WindowInsetsAnimationCallback.AnimationBounds onStart(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds);
    field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1
    field public static final int DISPATCH_MODE_STOP = 0; // 0x0
  }
  public static final class WindowInsetsAnimationCallback.AnimationBounds {
+14 −17
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LO
import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP;
import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowInsetsAnimationCallback.DISPATCH_MODE_CONTINUE_ON_SUBTREE;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
import static java.lang.Math.max;
@@ -111,6 +112,7 @@ import android.view.AccessibilityIterators.WordTextSegmentIterator;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
import android.view.WindowInsetsAnimationCallback.DispatchMode;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
@@ -949,22 +951,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    private static boolean sAcceptZeroSizeDragShadow;
    /**
     * Prior to Q, {@link #dispatchApplyWindowInsets} had some issues:
     * <ul>
     *     <li>The modified insets changed by {@link #onApplyWindowInsets} were passed to the
     * Prior to R, {@link #dispatchApplyWindowInsets} had an issue:
     * <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the
     * entire view hierarchy in prefix order, including siblings as well as siblings of parents
     * further down the hierarchy. This violates the basic concepts of the view hierarchy, and
     *     thus, the hierarchical dispatching mechanism was hard to use for apps.</li>
     *
     *     <li>Dispatch was stopped after the insets were fully consumed. This is somewhat confusing
     *     for developers, but more importantly, by adding more granular information to
     *     {@link WindowInsets} it becomes really cumbersome to define what consumed actually means
     *     </li>
     * </ul>
     *
     * thus, the hierarchical dispatching mechanism was hard to use for apps.
     * <p>
     * In order to make window inset dispatching work properly, we dispatch window insets
     * in the view hierarchy in a proper hierarchical manner and don't stop dispatching if the
     * insets are consumed if this flag is set to {@code false}.
     * in the view hierarchy in a proper hierarchical manner if this flag is set to {@code false}.
     */
    static boolean sBrokenInsetsDispatch;
@@ -5231,7 +5225,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P;
            sBrokenInsetsDispatch = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
                    || targetSdkVersion < Build.VERSION_CODES.Q;
                    || targetSdkVersion < Build.VERSION_CODES.R;
            sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q;
@@ -11100,7 +11094,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    /**
     * Sets a {@link WindowInsetsAnimationCallback} to be notified about animations of windows that
     * cause insets.
     *
     * <p>
     * When setting a listener, it's {@link WindowInsetsAnimationCallback#getDispatchMode() dispatch
     * mode} will be retrieved and recorded until another listener will be set.
     * </p>
     * @param listener The listener to set.
     */
    public void setWindowInsetsAnimationCallback(@Nullable WindowInsetsAnimationCallback listener) {
+41 −8
Original line number Diff line number Diff line
@@ -17,11 +17,14 @@
package android.view;

import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import static android.view.WindowInsetsAnimationCallback.DISPATCH_MODE_CONTINUE_ON_SUBTREE;
import static android.view.WindowInsetsAnimationCallback.DISPATCH_MODE_STOP;

import android.animation.LayoutTransition;
import android.annotation.CallSuper;
import android.annotation.IdRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UiThread;
import android.compat.annotation.UnsupportedAppUsage;
@@ -45,6 +48,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pools;
@@ -52,6 +56,7 @@ import android.util.Pools.SynchronizedPool;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
import android.view.WindowInsetsAnimationCallback.DispatchMode;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -606,6 +611,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
     */
    int mChildUnhandledKeyListeners = 0;

    /**
     * Current dispatch mode of animation events
     *
     * @see WindowInsetsAnimationCallback#getDispatchMode()
     */
    private @DispatchMode int mInsetsAnimationDispatchMode = DISPATCH_MODE_CONTINUE_ON_SUBTREE;

    /**
     * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
     *
@@ -7170,6 +7182,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    @Override
    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
        insets = super.dispatchApplyWindowInsets(insets);
        if (insets.isConsumed()) {
            return insets;
        }
        if (View.sBrokenInsetsDispatch) {
            return brokenDispatchApplyWindowInsets(insets);
        } else {
@@ -7178,7 +7193,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    }

    private WindowInsets brokenDispatchApplyWindowInsets(WindowInsets insets) {
        if (!insets.isConsumed()) {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            insets = getChildAt(i).dispatchApplyWindowInsets(insets);
@@ -7186,7 +7200,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                break;
            }
        }
        }
        return insets;
    }

@@ -7198,10 +7211,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        return insets;
    }

    @Override
    public void setWindowInsetsAnimationCallback(@Nullable WindowInsetsAnimationCallback listener) {
        super.setWindowInsetsAnimationCallback(listener);
        mInsetsAnimationDispatchMode = listener != null
                ? listener.getDispatchMode()
                : DISPATCH_MODE_CONTINUE_ON_SUBTREE;
    }

    @Override
    public void dispatchWindowInsetsAnimationPrepare(
            @NonNull InsetsAnimation animation) {
        super.dispatchWindowInsetsAnimationPrepare(animation);
        if (mInsetsAnimationDispatchMode == DISPATCH_MODE_STOP) {
            return;
        }
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).dispatchWindowInsetsAnimationPrepare(animation);
@@ -7212,7 +7236,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    @NonNull
    public AnimationBounds dispatchWindowInsetsAnimationStart(
            @NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) {
        super.dispatchWindowInsetsAnimationStart(animation, bounds);
        bounds = super.dispatchWindowInsetsAnimationStart(animation, bounds);
        if (mInsetsAnimationDispatchMode == DISPATCH_MODE_STOP) {
            return bounds;
        }
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).dispatchWindowInsetsAnimationStart(animation, bounds);
@@ -7224,6 +7251,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    @NonNull
    public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets) {
        insets = super.dispatchWindowInsetsAnimationProgress(insets);
        if (mInsetsAnimationDispatchMode == DISPATCH_MODE_STOP) {
            return insets;
        }
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).dispatchWindowInsetsAnimationProgress(insets);
@@ -7234,6 +7264,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    @Override
    public void dispatchWindowInsetsAnimationFinish(@NonNull InsetsAnimation animation) {
        super.dispatchWindowInsetsAnimationFinish(animation);
        if (mInsetsAnimationDispatchMode == DISPATCH_MODE_STOP) {
            return;
        }
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).dispatchWindowInsetsAnimationFinish(animation);
+26 −6
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.content.Intent;
import android.graphics.Insets;
import android.graphics.Rect;
import android.util.SparseArray;
import android.view.View.OnApplyWindowInsetsListener;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.inputmethod.EditorInfo;
@@ -96,13 +97,20 @@ public final class WindowInsets {
    private final boolean mCompatIgnoreVisibility;

    /**
     * Since new insets may be added in the future that existing apps couldn't
     * know about, this fully empty constant shouldn't be made available to apps
     * since it would allow them to inadvertently consume unknown insets by returning it.
     * @hide
     * A {@link WindowInsets} instance for which {@link #isConsumed()} returns {@code true}.
     * <p>
     * This can be used during insets dispatch in the view hierarchy by returning this value from
     * {@link View#onApplyWindowInsets(WindowInsets)} or
     * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets)} to stop dispatch
     * the insets to its children to avoid traversing the entire view hierarchy.
     * <p>
     * The application should return this instance once it has taken care of all insets on a certain
     * level in the view hierarchy, and doesn't need to dispatch to its children anymore for better
     * performance.
     *
     * @see #isConsumed()
     */
    @UnsupportedAppUsage
    public static final WindowInsets CONSUMED;
    public static final @NonNull WindowInsets CONSUMED;

    static {
        CONSUMED = new WindowInsets((Rect) null, null, false, false, null);
@@ -456,7 +464,11 @@ public final class WindowInsets {
     * Returns a copy of this WindowInsets with the cutout fully consumed.
     *
     * @return A modified copy of this WindowInsets
     * @deprecated Consuming of different parts individually of a {@link WindowInsets} instance is
     * deprecated, since {@link WindowInsets} contains many different insets. Use {@link #CONSUMED}
     * instead to stop dispatching insets.
     */
    @Deprecated
    @NonNull
    public WindowInsets consumeDisplayCutout() {
        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
@@ -504,7 +516,11 @@ public final class WindowInsets {
     * Returns a copy of this WindowInsets with the system window insets fully consumed.
     *
     * @return A modified copy of this WindowInsets
     * @deprecated Consuming of different parts individually of a {@link WindowInsets} instance is
     * deprecated, since {@link WindowInsets} contains many different insets. Use {@link #CONSUMED}
     * instead to stop dispatching insets.
     */
    @Deprecated
    @NonNull
    public WindowInsets consumeSystemWindowInsets() {
        return new WindowInsets(null, null,
@@ -754,7 +770,11 @@ public final class WindowInsets {
     * Returns a copy of this WindowInsets with the stable insets fully consumed.
     *
     * @return A modified copy of this WindowInsets
     * @deprecated Consuming of different parts individually of a {@link WindowInsets} instance is
     * deprecated, since {@link WindowInsets} contains many different insets. Use {@link #CONSUMED}
     * instead to stop dispatching insets.
     */
    @Deprecated
    @NonNull
    public WindowInsets consumeStableInsets() {
        return consumeSystemWindowInsets();
+57 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.view;

import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Insets;
@@ -24,12 +25,61 @@ import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.animation.Interpolator;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Interface that allows the application to listen to animation events for windows that cause
 * insets.
 */
public interface WindowInsetsAnimationCallback {

    /**
     * Return value for {@link #getDispatchMode()}: Dispatching of animation events should
     * stop at this level in the view hierarchy, and no animation events should be dispatch to the
     * subtree of the view hierarchy.
     */
    int DISPATCH_MODE_STOP = 0;

    /**
     * Return value for {@link #getDispatchMode()}: Dispatching of animation events should
     * continue in the view hierarchy.
     */
    int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1;

    /** @hide */
    @IntDef(prefix = { "DISPATCH_MODE_" }, value = {
            DISPATCH_MODE_STOP,
            DISPATCH_MODE_CONTINUE_ON_SUBTREE
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface DispatchMode {}

    /**
     * Retrieves the dispatch mode of this listener. Dispatch of the all animation events is
     * hierarchical: It will starts at the root of the view hierarchy and then traverse it and
     * invoke the callback of the specific {@link View} that is being traversed.
     * The method may return either {@link #DISPATCH_MODE_CONTINUE_ON_SUBTREE} to indicate that
     * animation events should be propagated to the subtree of the view hierarchy, or
     * {@link #DISPATCH_MODE_STOP} to stop dispatching. In that case, all animation callbacks
     * related to the animation passed in will be stopped from propagating to the subtree of the
     * hierarchy.
     * <p>
     * Note that this method will only be invoked once when
     * {@link View#setWindowInsetsAnimationCallback setting the listener} and then the framework
     * will use the recorded result.
     * <p>
     * Also note that returning {@link #DISPATCH_MODE_STOP} here behaves the same way as returning
     * {@link WindowInsets#CONSUMED} during the regular insets dispatch in
     * {@link View#onApplyWindowInsets}.
     *
     * @return Either {@link #DISPATCH_MODE_CONTINUE_ON_SUBTREE} to indicate that dispatching of
     *         animation events will continue to the subtree of the view hierarchy, or
     *         {@link #DISPATCH_MODE_STOP} to indicate that animation events will stop dispatching.
     */
    @DispatchMode
    int getDispatchMode();

    /**
     * Called when an insets animation is about to start and before the views have been laid out in
     * the end state of the animation. The ordering of events during an insets animation is the
@@ -75,10 +125,11 @@ public interface WindowInsetsAnimationCallback {
     * <p>
     * Note that, like {@link #onProgress}, dispatch of the animation start event is hierarchical:
     * It will starts at the root of the view hierarchy and then traverse it and invoke the callback
     * of the specific {@link View} that is being traversed. The method my return a modified
     * of the specific {@link View} that is being traversed. The method may return a modified
     * instance of the bounds by calling {@link AnimationBounds#inset} to indicate that a part of
     * the insets have been used to offset or clip its children, and the children shouldn't worry
     * about that part anymore.
     * about that part anymore. Furthermore, if {@link #getDispatchMode()} returns
     * {@link #DISPATCH_MODE_STOP}, children of this view will not receive the callback anymore.
     *
     * @param animation The animation that is about to start.
     * @param bounds The bounds in which animation happens.
@@ -102,7 +153,9 @@ public interface WindowInsetsAnimationCallback {
     * The method may return a modified instance by calling
     * {@link WindowInsets#inset(int, int, int, int)} to indicate that a part of the insets have
     * been used to offset or clip its children, and the children shouldn't worry about that part
     * anymore.
     * anymore. Furthermore, if {@link #getDispatchMode()} returns
     * {@link #DISPATCH_MODE_STOP}, children of this view will not receive the callback anymore.
     *
     * TODO: Introduce a way to map (type -> InsetAnimation) so app developer can query animation
     *  for a given type e.g. callback.getAnimation(type) OR controller.getAnimation(type).
     *  Or on the controller directly?
@@ -237,6 +290,7 @@ public interface WindowInsetsAnimationCallback {
     * Class representing the range of an {@link InsetsAnimation}
     */
    final class AnimationBounds {

        private final Insets mLowerBound;
        private final Insets mUpperBound;

Loading