Introduce Window.setContentOnApplyWindowInsetsListener
When root-level content containers fit insets, they used to just
apply and consume the entire system insets. However, with the new
Inset APIs, and with deprecating ADJUST_RESIZE IME flag, we want
to give apps an easy way to customize this behavior.
For that, we introduce Window.setOnContentApplyWindowInsetsListener
that returns what kind of margins/padding should be applied and
what should be dispatched to the content views. This is essentially
a replacement for SYSTEM_UI_FLAG_LAYOUT_* as well as
SOFT_INPUT_ADJUST_RESIZE: It allows apps to choose which insets
should be handled on the window level vs view level.
For that, we mark the window decor views as
FRAMEWORK_OPTIONAL_FIT_SYSTEM_WINDOWS, in order to distinguish the
case when support library calls makeOptionalFitSystemWindows(). This
is because of two reasons:
- We don't want the listener to be invoked twice.
- We can not do the compat ping-pong between onApplyWindowInsets
and fitSystemWindows. This is because during the ping-pong, the
result of the OnContentApplyWindowInsetsListener would be lost.
However, we still need to do the compat ping-pong for
ActionBarOverlayLayout in the support library (until that gets
migrated to use onApplyWindowInsets), so we have this separate
dispatching path that only gets used for framework optional
fitting views.
Test: WindowTest
Bug: 118118435
Change-Id: I4b514addd9e094163062d651972f85615b4a35db
diff --git a/api/current.txt b/api/current.txt
index 1c03c23..2132fc5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -53858,6 +53858,7 @@
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);
@@ -53896,6 +53897,7 @@
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);
@@ -53990,6 +53992,10 @@
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);
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 8e52ee9..86ff0f4 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1194,7 +1194,7 @@
Context.LAYOUT_INFLATER_SERVICE);
mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
- mWindow.getWindow().setFitWindowInsetsTypes(WindowInsets.Type.systemBars());
+ mWindow.getWindow().getAttributes().setFitWindowInsetsTypes(WindowInsets.Type.systemBars());
mWindow.getWindow().addPrivateFlags(PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND);
mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener(
(v, insets) -> v.onApplyWindowInsets(
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 52b7294..5cb52ea 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1137,7 +1137,7 @@
mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
mCallbacks, this, mDispatcherState,
WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
- mWindow.getWindow().setFitWindowInsetsTypes(0 /* types */);
+ mWindow.getWindow().getAttributes().setFitWindowInsetsTypes(0 /* types */);
mWindow.getWindow().addFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5356334..9eec1e9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -23,6 +23,10 @@
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.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
import static java.lang.Math.max;
@@ -97,6 +101,7 @@
import android.util.LayoutDirection;
import android.util.Log;
import android.util.LongSparseLongArray;
+import android.util.Pair;
import android.util.Pools.SynchronizedPool;
import android.util.Property;
import android.util.SparseArray;
@@ -110,6 +115,7 @@
import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.AccessibilityIterators.WordTextSegmentIterator;
import android.view.ContextMenu.ContextMenuInfo;
+import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
import android.view.WindowInsetsAnimationCallback.DispatchMode;
@@ -140,6 +146,7 @@
import android.widget.ScrollBarDrawable;
import com.android.internal.R;
+import com.android.internal.policy.DecorView;
import com.android.internal.view.TooltipPopup;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.ScrollBarUtils;
@@ -1510,6 +1517,10 @@
* Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate
* that they are optional and should be skipped if the window has
* requested system UI flags that ignore those insets for layout.
+ * <p>
+ * This is only used for support library as of Android R. The framework now uses
+ * {@link #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS} such that it can skip the legacy
+ * insets path that loses insets information.
*/
static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800;
@@ -2258,7 +2269,7 @@
* be extended in the future to hold our own class with more than just
* a Rect. :)
*/
- static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>();
+ static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new);
/**
* Map used to store views' tags.
@@ -3420,6 +3431,7 @@
* 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED
* 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE
* 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK
+ * 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS
* |-------|-------|-------|-------|
*/
@@ -3457,6 +3469,11 @@
PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED
| PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE;
+ /**
+ * @see #OPTIONAL_FITS_SYSTEM_WINDOWS
+ */
+ static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100;
+
/* End of masks for mPrivateFlags4 */
/** @hide */
@@ -10983,23 +11000,22 @@
private boolean fitSystemWindowsInt(Rect insets) {
if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
- mUserPaddingStart = UNDEFINED_PADDING;
- mUserPaddingEnd = UNDEFINED_PADDING;
Rect localInsets = sThreadLocal.get();
- if (localInsets == null) {
- localInsets = new Rect();
- sThreadLocal.set(localInsets);
- }
boolean res = computeFitSystemWindows(insets, localInsets);
- mUserPaddingLeftInitial = localInsets.left;
- mUserPaddingRightInitial = localInsets.right;
- internalSetPadding(localInsets.left, localInsets.top,
- localInsets.right, localInsets.bottom);
+ applyInsets(localInsets);
return res;
}
return false;
}
+ private void applyInsets(Rect insets) {
+ mUserPaddingStart = UNDEFINED_PADDING;
+ mUserPaddingEnd = UNDEFINED_PADDING;
+ mUserPaddingLeftInitial = insets.left;
+ mUserPaddingRightInitial = insets.right;
+ internalSetPadding(insets.left, insets.top, insets.right, insets.bottom);
+ }
+
/**
* Called when the view should apply {@link WindowInsets} according to its internal policy.
*
@@ -11026,6 +11042,10 @@
* @return The supplied insets with any applied insets consumed
*/
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0
+ && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) {
+ return onApplyFrameworkOptionalFitSystemWindows(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
@@ -11042,6 +11062,13 @@
return insets;
}
+ private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) {
+ Rect localInsets = sThreadLocal.get();
+ WindowInsets result = computeSystemWindowInsets(insets, localInsets);
+ applyInsets(localInsets);
+ return result;
+ }
+
/**
* Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
* window insets to this view. The listener's
@@ -11332,16 +11359,23 @@
* @return Insets that should be passed along to views under this one
*/
public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) {
- if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
- || mAttachInfo == null
- || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0)) {
+ boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0
+ || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0;
+ if (isOptionalFitSystemWindows && mAttachInfo != null) {
+ OnContentApplyWindowInsetsListener listener =
+ mAttachInfo.mContentOnApplyWindowInsetsListener;
+ if (listener == null) {
+ // The application wants to take care of fitting system window for
+ // the content.
+ outLocalInsets.setEmpty();
+ return in;
+ }
+ Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(in);
+ outLocalInsets.set(result.first.toRect());
+ return result.second;
+ } else {
outLocalInsets.set(in.getSystemWindowInsetsAsRect());
return in.consumeSystemWindowInsets().inset(outLocalInsets);
- } else {
- // The application wants to take care of fitting system window for
- // the content.
- outLocalInsets.setEmpty();
- return in;
}
}
@@ -11412,7 +11446,7 @@
}
/**
- * For use by PhoneWindow to make its own system window fitting optional.
+ * @see #OPTIONAL_FITS_SYSTEM_WINDOWS
* @hide
*/
@UnsupportedAppUsage
@@ -11421,6 +11455,14 @@
}
/**
+ * @see #PFLAG4_OPTIONAL_FITS_SYSTEM_WINDOWS
+ * @hide
+ */
+ public void makeFrameworkOptionalFitsSystemWindows() {
+ mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS;
+ }
+
+ /**
* Returns the visibility status for this view.
*
* @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
@@ -28378,6 +28420,7 @@
* window.
*/
final static class AttachInfo {
+
interface Callbacks {
void playSoundEffect(int effectId);
boolean performHapticFeedback(int effectId, boolean always);
@@ -28817,6 +28860,11 @@
ContentCaptureManager mContentCaptureManager;
/**
+ * Listener used to fit content on window level.
+ */
+ OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener;
+
+ /**
* Creates a new set of attachment information with the specified
* events handler and thread.
*
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e6470a7..59d6d87 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -55,6 +55,7 @@
import android.util.Pools.SynchronizedPool;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
import android.view.WindowInsetsAnimationCallback.DispatchMode;
import android.view.WindowInsetsAnimationCallback.InsetsAnimation;
@@ -1527,6 +1528,19 @@
}
}
+ /**
+ * @hide
+ */
+ @Override
+ public void makeFrameworkOptionalFitsSystemWindows() {
+ super.makeFrameworkOptionalFitsSystemWindows();
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ children[i].makeFrameworkOptionalFitsSystemWindows();
+ }
+ }
+
@Override
public void dispatchDisplayHint(int hint) {
super.dispatchDisplayHint(hint);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 09ebd00..0572c24 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -32,6 +32,8 @@
import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -78,6 +80,7 @@
import android.graphics.Color;
import android.graphics.FrameInfo;
import android.graphics.HardwareRenderer.FrameDrawingCallback;
+import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -122,6 +125,7 @@
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
+import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
@@ -755,6 +759,11 @@
mActivityConfigCallback = callback;
}
+ public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
+ mAttachInfo.mContentOnApplyWindowInsetsListener = listener;
+ requestFitSystemWindows();
+ }
+
public void addWindowCallbacks(WindowCallbacks callback) {
synchronized (mWindowCallbacks) {
mWindowCallbacks.add(callback);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a1894f3..0ef4e33 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -33,6 +33,7 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -46,6 +47,9 @@
import android.transition.Scene;
import android.transition.Transition;
import android.transition.TransitionManager;
+import android.util.Pair;
+import android.view.View.OnApplyWindowInsetsListener;
+import android.view.ViewGroup.LayoutParams;
import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type.InsetsType;
import android.view.accessibility.AccessibilityEvent;
@@ -692,6 +696,32 @@
int dropCountSinceLastInvocation);
}
+ /**
+ * Listener for applying window insets on the content of a window 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 fitting root-level content views.
+ *
+ * @see Window#setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener)
+ */
+ public interface OnContentApplyWindowInsetsListener {
+
+ /**
+ * Called when the window needs to apply insets on the container of its content view which
+ * are set by calling {@link #setContentView}. The method should determine what insets to
+ * apply on the container of the root level content view and what should be dispatched to
+ * the content view's
+ * {@link View#setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener)} through the view
+ * hierarchy.
+ *
+ * @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.
+ */
+ @NonNull Pair<Insets, WindowInsets> onContentApplyWindowInsets(
+ @NonNull WindowInsets insets);
+ }
public Window(Context context) {
mContext = context;
@@ -1281,57 +1311,33 @@
}
/**
- * A shortcut for {@link WindowManager.LayoutParams#setFitWindowInsetsTypes(int)}
- * @hide pending unhide
+ * Sets the listener to be invoked when fitting root-level content views.
+ * <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.
+ * </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 setFitWindowInsetsTypes(@InsetsType int types) {
- final WindowManager.LayoutParams attrs = getAttributes();
- attrs.setFitWindowInsetsTypes(types);
- dispatchWindowAttributesChanged(attrs);
+ public void setOnContentApplyWindowInsetsListener(
+ @Nullable OnContentApplyWindowInsetsListener contentOnApplyWindowInsetsListener) {
}
/**
- * A shortcut for {@link WindowManager.LayoutParams#setFitWindowInsetsSides(int)}
- * @hide pending unhide
+ * 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.
+ * </p>
*/
- public void setFitWindowInsetsSides(@InsetsSide int sides) {
- final WindowManager.LayoutParams attrs = getAttributes();
- attrs.setFitWindowInsetsSides(sides);
- dispatchWindowAttributesChanged(attrs);
- }
-
- /**
- * A shortcut for {@link WindowManager.LayoutParams#setFitIgnoreVisibility(boolean)}
- * @hide pending unhide
- */
- public void setFitIgnoreVisibility(boolean ignore) {
- final WindowManager.LayoutParams attrs = getAttributes();
- attrs.setFitIgnoreVisibility(ignore);
- dispatchWindowAttributesChanged(attrs);
- }
-
- /**
- * A shortcut for {@link WindowManager.LayoutParams#getFitWindowInsetsTypes}
- * @hide pending unhide
- */
- public @InsetsType int getFitWindowInsetsTypes() {
- return getAttributes().getFitWindowInsetsTypes();
- }
-
- /**
- * A shortcut for {@link WindowManager.LayoutParams#getFitWindowInsetsSides()}
- * @hide pending unhide
- */
- public @InsetsSide int getFitWindowInsetsSides() {
- return getAttributes().getFitWindowInsetsSides();
- }
-
- /**
- * A shortcut for {@link WindowManager.LayoutParams#getFitIgnoreVisibility()}
- * @hide pending unhide
- */
- public boolean getFitIgnoreVisibility() {
- return getAttributes().getFitIgnoreVisibility();
+ public void resetOnContentApplyWindowInsetsListener() {
}
/**
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 4abd397..0663f85 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -17,8 +17,11 @@
package com.android.internal.policy;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.view.View.SYSTEM_UI_LAYOUT_FLAGS;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -30,6 +33,8 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -43,6 +48,7 @@
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
@@ -66,6 +72,7 @@
import android.util.AndroidRuntimeException;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
@@ -307,6 +314,8 @@
/** @see ViewRootImpl#mActivityConfigCallback */
private ActivityConfigCallback mActivityConfigCallback;
+ private OnContentApplyWindowInsetsListener mPendingOnContentApplyWindowInsetsListener;
+
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
@@ -2092,6 +2101,34 @@
/** 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());
+ }
+ }
+
+ private OnContentApplyWindowInsetsListener createDefaultContentWindowInsetsListener() {
+ return insets -> {
+ if ((getDecorView().getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) != 0) {
+ return new Pair<>(Insets.NONE, insets);
+ }
+
+ boolean includeIme = (getAttributes().softInputMode & SOFT_INPUT_MASK_ADJUST)
+ == SOFT_INPUT_ADJUST_RESIZE;
+ Insets insetsToApply;
+ if (ViewRootImpl.sNewInsetsMode == 0) {
+ insetsToApply = insets.getSystemWindowInsets();
+ } else {
+ insetsToApply = insets.getInsets(systemBars() | (includeIme ? ime() : 0));
+ }
+ insets = insets.inset(insetsToApply);
+ return new Pair<>(insetsToApply,
+ insets.inset(insetsToApply).consumeSystemWindowInsets());
+ };
}
static private final String FOCUSED_ID_TAG = "android:focusedViewId";
@@ -2656,7 +2693,7 @@
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
- mDecor.makeOptionalFitsSystemWindows();
+ mDecor.makeFrameworkOptionalFitsSystemWindows();
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
@@ -3853,4 +3890,19 @@
public List<Rect> getSystemGestureExclusionRects() {
return getViewRootImpl().getRootSystemGestureExclusionRects();
}
+
+ @Override
+ public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
+ ViewRootImpl impl = getViewRootImpl();
+ if (impl != null) {
+ impl.setOnContentApplyWindowInsetsListener(listener);
+ } else {
+ mPendingOnContentApplyWindowInsetsListener = listener;
+ }
+ }
+
+ @Override
+ public void resetOnContentApplyWindowInsetsListener() {
+ setOnContentApplyWindowInsetsListener(createDefaultContentWindowInsetsListener());
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index 8c756ec..34baa2d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -20,6 +20,7 @@
import static android.content.DialogInterface.BUTTON_POSITIVE;
import static android.os.UserManager.DISALLOW_ADD_USER;
import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
+import static android.view.WindowInsets.Type.statusBars;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -367,8 +368,8 @@
window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
- window.setFitWindowInsetsTypes(
- window.getFitWindowInsetsTypes() & ~WindowInsets.Type.statusBars());
+ window.getAttributes().setFitWindowInsetsTypes(
+ window.getAttributes().getFitWindowInsetsTypes() & ~statusBars());
}
private void notifyUserSelected(UserRecord userRecord) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 315ea0a..9ab3dbc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -35,6 +35,7 @@
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.Window
import android.view.WindowInsets.Type
+import android.view.WindowInsets.Type.statusBars
import android.view.WindowManager
import android.widget.TextView
import com.android.internal.annotations.VisibleForTesting
@@ -288,13 +289,13 @@
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
addFlags(wmFlags)
setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL)
- setFitWindowInsetsTypes(getFitWindowInsetsTypes() and Type.statusBars().inv())
setWindowAnimations(com.android.internal.R.style.Animation_InputMethod)
attributes = attributes.apply {
format = PixelFormat.TRANSLUCENT
title = ChannelEditorDialogController::class.java.simpleName
gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
+ fitWindowInsetsTypes = attributes.fitWindowInsetsTypes and statusBars().inv()
width = MATCH_PARENT
height = WRAP_CONTENT
}