OSDN Git Service

DO NOT MERGE Refactoring of fitSystemWindows to applyWindowInsets for views
authorAdam Powell <adamp@google.com>
Mon, 3 Feb 2014 18:16:49 +0000 (10:16 -0800)
committerAdam Powell <adamp@google.com>
Tue, 15 Apr 2014 17:30:25 +0000 (10:30 -0700)
Applying insets is now handled by:

* WindowInsets class - Encapsulate system insets and local decor
  insets into a single object, written specifically so that new inset
  categories may be added later. Apps cannot construct their own
  WindowInsets, only clone with optional modifications. This is to
  prevent losing data in the event of new insets added in the future.

* onApplyWindowInsets - Actually perform the application of insets.

* OnApplyWindowInsetsListener - Allow an app to use a separate
  Listener object to apply insets to a View. This allows for things
  like support lib integration in custom views written for older
  versions where the verifier would otherwise complain about the use
  of the new WindowInsets class as a method parameter. It also allows
  for applying insets in a custom way without writing a custom view.

* dispatchApplyWindowInsets - Dispatch the call to self and children
  in turn, if applicable. An OnApplyWindowInsetsListener will override
  the behavior of the view's default onApplyWindowInsets method; a
  listener wishing to call down to the 'superclass' implementation as
  part of its own operation should call view.onApplyWindowInsets. App
  code should generally not override this method and instead override
  onApplyWindowInsets or provide a listener.

Compatibility support with the existing fitSystemWindows method has
been provided in both directions: for code that previously called
fitSystemWindows on arbitrary views and also for code that overrode
the fitSystemWindows method in custom views. A view that supports the
newer onApplyWindowInsets mechanism should not mix that behavior with
other calls to fitSystemWindows or vice versa. Support lib-style code
should take care to consistently use one mechanism or the other at
runtime.

Change-Id: Ie88b96e0382beb5d3c3f6cd013f7043acbc0a105

api/current.txt
core/java/android/view/View.java
core/java/android/view/ViewGroup.java
core/java/android/view/WindowInsets.java [new file with mode: 0644]
core/java/com/android/internal/widget/ActionBarOverlayLayout.java

index ff84764..ee6f3f2 100644 (file)
@@ -27748,6 +27748,7 @@ package android.view {
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo();
     method public void createContextMenu(android.view.ContextMenu);
     method public void destroyDrawingCache();
+    method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
     method public void dispatchConfigurationChanged(android.content.res.Configuration);
     method public void dispatchDisplayHint(int);
     method public boolean dispatchDragEvent(android.view.DragEvent);
@@ -27779,7 +27780,7 @@ package android.view {
     method public final android.view.View findViewById(int);
     method public final android.view.View findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
-    method protected boolean fitSystemWindows(android.graphics.Rect);
+    method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
     method public void forceLayout();
     method public static int generateViewId();
@@ -27961,6 +27962,7 @@ package android.view {
     method public void offsetTopAndBottom(int);
     method protected void onAnimationEnd();
     method protected void onAnimationStart();
+    method public android.view.WindowInsets onApplyWindowInsets(android.view.WindowInsets);
     method protected void onAttachedToWindow();
     method public void onCancelPendingInputEvents();
     method public boolean onCheckIsTextEditor();
@@ -28027,7 +28029,8 @@ package android.view {
     method public boolean removeCallbacks(java.lang.Runnable);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
-    method public void requestFitSystemWindows();
+    method public void requestApplyInsets();
+    method public deprecated void requestFitSystemWindows();
     method public final boolean requestFocus();
     method public final boolean requestFocus(int);
     method public boolean requestFocus(int, android.graphics.Rect);
@@ -28091,6 +28094,7 @@ package android.view {
     method public void setNextFocusLeftId(int);
     method public void setNextFocusRightId(int);
     method public void setNextFocusUpId(int);
+    method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
     method public void setOnClickListener(android.view.View.OnClickListener);
     method public void setOnCreateContextMenuListener(android.view.View.OnCreateContextMenuListener);
     method public void setOnDragListener(android.view.View.OnDragListener);
@@ -28309,6 +28313,10 @@ package android.view {
     field public static final int UNSPECIFIED = 0; // 0x0
   }
 
+  public static abstract interface View.OnApplyWindowInsetsListener {
+    method public abstract android.view.WindowInsets onApplyWindowInsets(android.view.View, android.view.WindowInsets);
+  }
+
   public static abstract interface View.OnAttachStateChangeListener {
     method public abstract void onViewAttachedToWindow(android.view.View);
     method public abstract void onViewDetachedFromWindow(android.view.View);
@@ -28918,6 +28926,27 @@ package android.view {
     method public abstract void onFocusLost(android.view.WindowId);
   }
 
+  public class WindowInsets {
+    ctor public WindowInsets(android.view.WindowInsets);
+    method public android.view.WindowInsets cloneWithSystemWindowInsets(int, int, int, int);
+    method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed();
+    method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed(boolean, boolean, boolean, boolean);
+    method public android.view.WindowInsets cloneWithWindowDecorInsets(int, int, int, int);
+    method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed();
+    method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed(boolean, boolean, boolean, boolean);
+    method public int getSystemWindowInsetBottom();
+    method public int getSystemWindowInsetLeft();
+    method public int getSystemWindowInsetRight();
+    method public int getSystemWindowInsetTop();
+    method public int getWindowDecorInsetBottom();
+    method public int getWindowDecorInsetLeft();
+    method public int getWindowDecorInsetRight();
+    method public int getWindowDecorInsetTop();
+    method public boolean hasInsets();
+    method public boolean hasSystemWindowInsets();
+    method public boolean hasWindowDecorInsets();
+  }
+
   public abstract interface WindowManager implements android.view.ViewManager {
     method public abstract android.view.Display getDefaultDisplay();
     method public abstract void removeViewImmediate(android.view.View);
index 8d69477..e6debc1 100644 (file)
@@ -2269,6 +2269,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     static final int PFLAG3_CALLED_SUPER = 0x10;
 
 
+    /**
+     * Flag indicating that we're in the process of applying window insets.
+     */
+    static final int PFLAG3_APPLYING_INSETS = 0x40;
+
+    /**
+     * Flag indicating that we're in the process of fitting system windows using the old method.
+     */
+    static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x80;
+
     /* End of masks for mPrivateFlags3 */
 
     static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
@@ -3178,6 +3188,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         private OnDragListener mOnDragListener;
 
         private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
+
+        OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
     }
 
     ListenerInfo mListenerInfo;
@@ -5903,8 +5915,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      * @see #getFitsSystemWindows()
      * @see #setFitsSystemWindows(boolean) 
      * @see #setSystemUiVisibility(int)
+     *
+     * @deprecated As of API XX use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply
+     * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use
+     * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)}
+     * to implement handling their own insets.
      */
     protected boolean fitSystemWindows(Rect insets) {
+        if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
+            // If we're not in the process of dispatching the newer apply insets call,
+            // that means we're not in the compatibility path. Dispatch into the newer
+            // apply insets path and take things from there.
+            try {
+                mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
+                return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
+            } finally {
+                mPrivateFlags3 &= PFLAG3_FITTING_SYSTEM_WINDOWS;
+            }
+        } else {
+            // We're being called from the newer apply insets path.
+            // Perform the standard fallback behavior.
+            return fitSystemWindowsInt(insets);
+        }
+    }
+
+    private boolean fitSystemWindowsInt(Rect insets) {
         if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
             mUserPaddingStart = UNDEFINED_PADDING;
             mUserPaddingEnd = UNDEFINED_PADDING;
@@ -5924,6 +5959,97 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     }
 
     /**
+     * Called when the view should apply {@link WindowInsets} according to its internal policy.
+     *
+     * <p>This method should be overridden by views that wish to apply a policy different from or
+     * in addition to the default behavior. Clients that wish to force a view subtree
+     * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p>
+     *
+     * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set
+     * it will be called during dispatch instead of this method. The listener may optionally
+     * call this method from its own implementation if it wishes to apply the view's default
+     * insets policy in addition to its own.</p>
+     *
+     * <p>Implementations of this method should either return the insets parameter unchanged
+     * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed
+     * that this view applied itself. This allows new inset types added in future platform
+     * versions to pass through existing implementations unchanged without being erroneously
+     * consumed.</p>
+     *
+     * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows}
+     * property is set then the view will consume the system window insets and apply them
+     * as padding for the view.</p>
+     *
+     * @param insets Insets to apply
+     * @return The supplied insets with any applied insets consumed
+     */
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) {
+            // We weren't called from within a direct call to fitSystemWindows,
+            // call into it as a fallback in case we're in a class that overrides it
+            // and has logic to perform.
+            if (fitSystemWindows(insets.getSystemWindowInsets())) {
+                return insets.cloneWithSystemWindowInsetsConsumed();
+            }
+        } else {
+            // We were called from within a direct call to fitSystemWindows.
+            if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
+                return insets.cloneWithSystemWindowInsetsConsumed();
+            }
+        }
+        return insets;
+    }
+
+    /**
+     * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
+     * window insets to this view. The listener's
+     * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+     * method will be called instead of the view's
+     * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+     *
+     * @param listener Listener to set
+     *
+     * @see #onApplyWindowInsets(WindowInsets)
+     */
+    public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) {
+        getListenerInfo().mOnApplyWindowInsetsListener = listener;
+    }
+
+    /**
+     * Request to apply the given window insets to this view or another view in its subtree.
+     *
+     * <p>This method should be called by clients wishing to apply insets corresponding to areas
+     * obscured by window decorations or overlays. This can include the status and navigation bars,
+     * action bars, input methods and more. New inset categories may be added in the future.
+     * The method returns the insets provided minus any that were applied by this view or its
+     * children.</p>
+     *
+     * <p>Clients wishing to provide custom behavior should override the
+     * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a
+     * {@link OnApplyWindowInsetsListener} via the
+     * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener}
+     * method.</p>
+     *
+     * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method.
+     * </p>
+     *
+     * @param insets Insets to apply
+     * @return The provided insets minus the insets that were consumed
+     */
+    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+        try {
+            mPrivateFlags3 |= PFLAG3_APPLYING_INSETS;
+            if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) {
+                return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets);
+            } else {
+                return onApplyWindowInsets(insets);
+            }
+        } finally {
+            mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS;
+        }
+    }
+
+    /**
      * @hide Compute the insets that should be consumed by this view and the ones
      * that should propagate to those under it.
      */
@@ -5995,6 +6121,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
 
     /**
      * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed.
+     * @deprecated Use {@link #requestApplyInsets()} for newer platform versions.
      */
     public void requestFitSystemWindows() {
         if (mParent != null) {
@@ -6003,6 +6130,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     }
 
     /**
+     * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed.
+     */
+    public void requestApplyInsets() {
+        requestFitSystemWindows();
+    }
+
+    /**
      * For use by PhoneWindow to make its own system window fitting optional.
      * @hide
      */
@@ -18668,6 +18802,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         public void onViewDetachedFromWindow(View v);
     }
 
+    /**
+     * Listener for applying window insets on a view in a custom way.
+     *
+     * <p>Apps may choose to implement this interface if they want to apply custom policy
+     * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener
+     * is set, its
+     * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+     * method will be called instead of the View's own
+     * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener
+     * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply
+     * the View's normal behavior as part of its own.</p>
+     */
+    public interface OnApplyWindowInsetsListener {
+        /**
+         * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set}
+         * on a View, this listener method will be called instead of the view's own
+         * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+         *
+         * @param v The view applying window insets
+         * @param insets The insets to apply
+         * @return The insets supplied, minus any insets that were consumed
+         */
+        public WindowInsets onApplyWindowInsets(View v, WindowInsets insets);
+    }
+
     private final class UnsetPressedState implements Runnable {
         public void run() {
             setPressed(false);
index 5763e72..f346ee8 100644 (file)
@@ -5429,21 +5429,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
         }
     }
 
-
     @Override
-    protected boolean fitSystemWindows(Rect insets) {
-        boolean done = super.fitSystemWindows(insets);
-        if (!done) {
-            final int count = mChildrenCount;
-            final View[] children = mChildren;
+    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+        insets = super.dispatchApplyWindowInsets(insets);
+        if (insets.hasInsets()) {
+            final int count = getChildCount();
             for (int i = 0; i < count; i++) {
-                done = children[i].fitSystemWindows(insets);
-                if (done) {
+                insets = getChildAt(i).dispatchApplyWindowInsets(insets);
+                if (!insets.hasInsets()) {
                     break;
                 }
             }
         }
-        return done;
+        return insets;
     }
 
     /**
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
new file mode 100644 (file)
index 0000000..cdfcb43
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2014 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 android.graphics.Rect;
+
+/**
+ * Describes a set of insets for window content.
+ *
+ * <p>WindowInsets are immutable and may be expanded to include more inset types in the future.
+ * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
+ * with the adjusted properties.</p>
+ *
+ * @see View.OnApplyWindowInsetsListener
+ * @see View#onApplyWindowInsets(WindowInsets)
+ */
+public class WindowInsets {
+    private Rect mSystemWindowInsets;
+    private Rect mWindowDecorInsets;
+    private Rect mTempRect;
+
+    private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
+
+    /**
+     * 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
+     */
+    public static final WindowInsets EMPTY = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+
+    /** @hide */
+    public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
+        mSystemWindowInsets = systemWindowInsets;
+        mWindowDecorInsets = windowDecorInsets;
+    }
+
+    /**
+     * Construct a new WindowInsets, copying all values from a source WindowInsets.
+     *
+     * @param src Source to copy insets from
+     */
+    public WindowInsets(WindowInsets src) {
+        mSystemWindowInsets = src.mSystemWindowInsets;
+        mWindowDecorInsets = src.mWindowDecorInsets;
+    }
+
+    /** @hide */
+    public WindowInsets(Rect systemWindowInsets) {
+        mSystemWindowInsets = systemWindowInsets;
+        mWindowDecorInsets = EMPTY_RECT;
+    }
+
+    /**
+     * Used to provide a safe copy of the system window insets to pass through
+     * to the existing fitSystemWindows method and other similar internals.
+     * @hide
+     */
+    public Rect getSystemWindowInsets() {
+        if (mTempRect == null) {
+            mTempRect = new Rect();
+        }
+        mTempRect.set(mSystemWindowInsets);
+        return mTempRect;
+    }
+
+    /**
+     * Returns the left system window inset in pixels.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return The left system window inset
+     */
+    public int getSystemWindowInsetLeft() {
+        return mSystemWindowInsets.left;
+    }
+
+    /**
+     * Returns the top system window inset in pixels.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return The top system window inset
+     */
+    public int getSystemWindowInsetTop() {
+        return mSystemWindowInsets.top;
+    }
+
+    /**
+     * Returns the right system window inset in pixels.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return The right system window inset
+     */
+    public int getSystemWindowInsetRight() {
+        return mSystemWindowInsets.right;
+    }
+
+    /**
+     * Returns the bottom system window inset in pixels.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return The bottom system window inset
+     */
+    public int getSystemWindowInsetBottom() {
+        return mSystemWindowInsets.bottom;
+    }
+
+    /**
+     * Returns the left window decor inset in pixels.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return The left window decor inset
+     */
+    public int getWindowDecorInsetLeft() {
+        return mWindowDecorInsets.left;
+    }
+
+    /**
+     * Returns the top window decor inset in pixels.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return The top window decor inset
+     */
+    public int getWindowDecorInsetTop() {
+        return mWindowDecorInsets.top;
+    }
+
+    /**
+     * Returns the right window decor inset in pixels.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return The right window decor inset
+     */
+    public int getWindowDecorInsetRight() {
+        return mWindowDecorInsets.right;
+    }
+
+    /**
+     * Returns the bottom window decor inset in pixels.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return The bottom window decor inset
+     */
+    public int getWindowDecorInsetBottom() {
+        return mWindowDecorInsets.bottom;
+    }
+
+    /**
+     * Returns true if this WindowInsets has nonzero system window insets.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return true if any of the system window inset values are nonzero
+     */
+    public boolean hasSystemWindowInsets() {
+        return mSystemWindowInsets.left != 0 || mSystemWindowInsets.top != 0 ||
+                mSystemWindowInsets.right != 0 || mSystemWindowInsets.bottom != 0;
+    }
+
+    /**
+     * Returns true if this WindowInsets has nonzero window decor insets.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return true if any of the window decor inset values are nonzero
+     */
+    public boolean hasWindowDecorInsets() {
+        return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
+                mWindowDecorInsets.right != 0 || mWindowDecorInsets.bottom != 0;
+    }
+
+    /**
+     * Returns true if this WindowInsets has any nonzero insets.
+     *
+     * @return true if any inset values are nonzero
+     */
+    public boolean hasInsets() {
+        return hasSystemWindowInsets() || hasWindowDecorInsets();
+    }
+
+    public WindowInsets cloneWithSystemWindowInsetsConsumed() {
+        final WindowInsets result = new WindowInsets(this);
+        result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
+        return result;
+    }
+
+    public WindowInsets cloneWithSystemWindowInsetsConsumed(boolean left, boolean top,
+            boolean right, boolean bottom) {
+        if (left || top || right || bottom) {
+            final WindowInsets result = new WindowInsets(this);
+            result.mSystemWindowInsets = new Rect(left ? 0 : mSystemWindowInsets.left,
+                    top ? 0 : mSystemWindowInsets.top,
+                    right ? 0 : mSystemWindowInsets.right,
+                    bottom ? 0 : mSystemWindowInsets.bottom);
+            return result;
+        }
+        return this;
+    }
+
+    public WindowInsets cloneWithSystemWindowInsets(int left, int top, int right, int bottom) {
+        final WindowInsets result = new WindowInsets(this);
+        result.mSystemWindowInsets = new Rect(left, top, right, bottom);
+        return result;
+    }
+
+    public WindowInsets cloneWithWindowDecorInsetsConsumed() {
+        final WindowInsets result = new WindowInsets(this);
+        result.mWindowDecorInsets.set(0, 0, 0, 0);
+        return result;
+    }
+
+    public WindowInsets cloneWithWindowDecorInsetsConsumed(boolean left, boolean top,
+            boolean right, boolean bottom) {
+        if (left || top || right || bottom) {
+            final WindowInsets result = new WindowInsets(this);
+            result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left,
+                    top ? 0 : mWindowDecorInsets.top,
+                    right ? 0 : mWindowDecorInsets.right,
+                    bottom ? 0 : mWindowDecorInsets.bottom);
+            return result;
+        }
+        return this;
+    }
+
+    public WindowInsets cloneWithWindowDecorInsets(int left, int top, int right, int bottom) {
+        final WindowInsets result = new WindowInsets(this);
+        result.mWindowDecorInsets = new Rect(left, top, right, bottom);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets + " windowDecorInsets=" +
+                mWindowDecorInsets + "}";
+    }
+}
index 5469b63..c957b67 100644 (file)
@@ -20,6 +20,7 @@ import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.view.ViewGroup;
+import android.view.WindowInsets;
 import com.android.internal.app.ActionBarImpl;
 
 import android.content.Context;
@@ -96,7 +97,7 @@ public class ActionBarOverlayLayout extends ViewGroup {
             if (mLastSystemUiVisibility != 0) {
                 int newVis = mLastSystemUiVisibility;
                 onWindowSystemUiVisibilityChanged(newVis);
-                requestFitSystemWindows();
+                requestApplyInsets();
             }
         }
     }
@@ -152,7 +153,7 @@ public class ActionBarOverlayLayout extends ViewGroup {
         }
         if ((diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
             if (mActionBar != null) {
-                requestFitSystemWindows();
+                requestApplyInsets();
             }
         }
     }
@@ -190,19 +191,20 @@ public class ActionBarOverlayLayout extends ViewGroup {
     }
 
     @Override
-    protected boolean fitSystemWindows(Rect insets) {
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         pullChildren();
 
         final int vis = getWindowSystemUiVisibility();
         final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
+        final Rect systemInsets = insets.getSystemWindowInsets();
 
         // The top and bottom action bars are always within the content area.
-        boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true);
+        boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
         if (mActionBarBottom != null) {
-            changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
+            changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
         }
 
-        mBaseInnerInsets.set(insets);
+        mBaseInnerInsets.set(systemInsets);
         computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets);
         if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
             changed = true;
@@ -215,9 +217,9 @@ public class ActionBarOverlayLayout extends ViewGroup {
 
         // We don't do any more at this point.  To correctly compute the content/inner
         // insets in all cases, we need to know the measured size of the various action
-        // bar elements.  fitSystemWindows() happens before the measure pass, so we can't
+        // bar elements.  onApplyWindowInsets() happens before the measure pass, so we can't
         // do that here.  Instead we will take this up in onMeasure().
-        return true;
+        return WindowInsets.EMPTY;
     }
 
     @Override
@@ -321,7 +323,7 @@ public class ActionBarOverlayLayout extends ViewGroup {
             // the app's fitSystemWindows().  We do this before measuring the content
             // view to keep the same semantics as the normal fitSystemWindows() call.
             mLastInnerInsets.set(mInnerInsets);
-            super.fitSystemWindows(mInnerInsets);
+            mContent.dispatchApplyWindowInsets(new WindowInsets(mInnerInsets));
         }
 
         measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);