Merge "Added Calendar Tile Sample" into androidx-main
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index 8d7b821..b9e5de9 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -2824,7 +2824,7 @@
   }
 
   public final class WindowCompat {
-    method public static androidx.core.view.WindowInsetsControllerCompat? getInsetsController(android.view.Window, android.view.View);
+    method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getInsetsController(android.view.Window, android.view.View);
     method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
     method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
     field public static final int FEATURE_ACTION_BAR = 8; // 0x8
@@ -2949,7 +2949,7 @@
   }
 
   public final class WindowInsetsControllerCompat {
-    ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+    ctor @Deprecated public WindowInsetsControllerCompat(android.view.Window, android.view.View);
     method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
     method public void controlWindowInsetsAnimation(int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
     method public int getSystemBarsBehavior();
@@ -2961,7 +2961,7 @@
     method public void setAppearanceLightStatusBars(boolean);
     method public void setSystemBarsBehavior(int);
     method public void show(int);
-    method @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+    method @Deprecated @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
     field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
     field public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
     field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index f6a0b6b..3261120 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -2829,7 +2829,7 @@
   }
 
   public final class WindowCompat {
-    method public static androidx.core.view.WindowInsetsControllerCompat? getInsetsController(android.view.Window, android.view.View);
+    method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getInsetsController(android.view.Window, android.view.View);
     method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
     method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
     field public static final int FEATURE_ACTION_BAR = 8; // 0x8
@@ -2954,7 +2954,7 @@
   }
 
   public final class WindowInsetsControllerCompat {
-    ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+    ctor @Deprecated public WindowInsetsControllerCompat(android.view.Window, android.view.View);
     method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
     method public void controlWindowInsetsAnimation(int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
     method public int getSystemBarsBehavior();
@@ -2966,7 +2966,7 @@
     method public void setAppearanceLightStatusBars(boolean);
     method public void setSystemBarsBehavior(int);
     method public void show(int);
-    method @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+    method @Deprecated @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
     field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
     field public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
     field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 657a67f..f39b4fe 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -3271,7 +3271,7 @@
   }
 
   public final class WindowCompat {
-    method public static androidx.core.view.WindowInsetsControllerCompat? getInsetsController(android.view.Window, android.view.View);
+    method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getInsetsController(android.view.Window, android.view.View);
     method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
     method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
     field public static final int FEATURE_ACTION_BAR = 8; // 0x8
@@ -3402,7 +3402,7 @@
   }
 
   public final class WindowInsetsControllerCompat {
-    ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+    ctor @Deprecated public WindowInsetsControllerCompat(android.view.Window, android.view.View);
     method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
     method public void controlWindowInsetsAnimation(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
     method public int getSystemBarsBehavior();
@@ -3414,7 +3414,7 @@
     method public void setAppearanceLightStatusBars(boolean);
     method public void setSystemBarsBehavior(int);
     method public void show(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
-    method @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+    method @Deprecated @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
     field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
     field public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
     field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
diff --git a/core/core/src/androidTest/java/androidx/core/view/ViewCompatTest.java b/core/core/src/androidTest/java/androidx/core/view/ViewCompatTest.java
index 4f2c3a3..79fae38 100644
--- a/core/core/src/androidTest/java/androidx/core/view/ViewCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/view/ViewCompatTest.java
@@ -40,12 +40,10 @@
 import android.os.Bundle;
 import android.support.v4.BaseInstrumentationTestCase;
 import android.view.Display;
-import android.view.LayoutInflater;
 import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.appcompat.view.ContextThemeWrapper;
 import androidx.core.graphics.Insets;
 import androidx.core.test.R;
 import androidx.test.annotation.UiThreadTest;
@@ -54,7 +52,6 @@
 import androidx.test.filters.SdkSuppress;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -313,28 +310,6 @@
                 bundleCaptor.getValue().getInt(ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT));
     }
 
-    @Ignore
-    @Test
-    public void testGetWindowInsetsController_UnwrapsContextWrappers()
-            throws Throwable {
-        final ContextThemeWrapper wrapper = new ContextThemeWrapper(mActivityTestRule.getActivity(),
-                0);
-
-
-        final LayoutInflater inflater = LayoutInflater.from(wrapper);
-        final View view = inflater.createView(View.class.getName(), null, null);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivityTestRule.getActivity().setContentView(view);
-            }
-        });
-
-        final WindowInsetsControllerCompat controller = ViewCompat.getWindowInsetsController(view);
-
-        assertNotNull(controller);
-    }
-
     private static boolean isViewIdGenerated(int id) {
         return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0;
     }
diff --git a/core/core/src/androidTest/java/androidx/core/view/WindowInsetsAnimationCompatActivityTest.kt b/core/core/src/androidTest/java/androidx/core/view/WindowInsetsAnimationCompatActivityTest.kt
index ed40508..88dec5b 100644
--- a/core/core/src/androidTest/java/androidx/core/view/WindowInsetsAnimationCompatActivityTest.kt
+++ b/core/core/src/androidTest/java/androidx/core/view/WindowInsetsAnimationCompatActivityTest.kt
@@ -61,7 +61,7 @@
         onView(withId(R.id.edittext)).perform(ViewActions.closeSoftKeyboard())
         scenario.onActivity {
             WindowCompat.setDecorFitsSystemWindows(it.window, false)
-            WindowCompat.getInsetsController(it.window, it.window.decorView)!!.show(systemBars())
+            ViewCompat.getWindowInsetsController(it.window.decorView)!!.show(systemBars())
             barsShown = true
         }
         onIdle()
diff --git a/core/core/src/androidTest/java/androidx/core/view/WindowInsetsCompatActivityTest.kt b/core/core/src/androidTest/java/androidx/core/view/WindowInsetsCompatActivityTest.kt
index 456e8ae..e2d4e48 100644
--- a/core/core/src/androidTest/java/androidx/core/view/WindowInsetsCompatActivityTest.kt
+++ b/core/core/src/androidTest/java/androidx/core/view/WindowInsetsCompatActivityTest.kt
@@ -300,11 +300,7 @@
             WindowCompat.setDecorFitsSystemWindows(activity.window, false)
         }
         val container: View = scenario.withActivity { findViewById(R.id.container) }
-        scenario.onActivity { activity ->
-            WindowCompat.getInsetsController(activity.window, container)!!.show(
-                Type.systemBars()
-            )
-        }
+        ViewCompat.getWindowInsetsController(container)!!.show(Type.systemBars())
 
         // Get the current insets and check that the system bars insets are not empty
         val navigationBar = ViewCompat.getRootWindowInsets(container)
diff --git a/core/core/src/androidTest/java/androidx/core/view/WindowInsetsControllerCompatActivityTest.kt b/core/core/src/androidTest/java/androidx/core/view/WindowInsetsControllerCompatActivityTest.kt
index 58611ce..8e94c21 100644
--- a/core/core/src/androidTest/java/androidx/core/view/WindowInsetsControllerCompatActivityTest.kt
+++ b/core/core/src/androidTest/java/androidx/core/view/WindowInsetsControllerCompatActivityTest.kt
@@ -16,11 +16,13 @@
 
 package androidx.core.view
 
+import android.app.Dialog
 import android.os.Build
 import android.view.View
 import android.view.WindowInsetsController
 import android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
 import android.widget.EditText
+import android.widget.TextView
 import androidx.annotation.RequiresApi
 import androidx.core.graphics.Insets
 import androidx.core.test.R
@@ -135,7 +137,7 @@
             editText.requestFocus()
         }
         assertThat(editText.isFocused, `is`(true))
-        if (Build.VERSION.SDK_INT == 30) {
+        if (Build.VERSION.SDK_INT >= 30) {
             // Dirty hack until we figure out why the IME is not showing if we don't wait before
             Thread.sleep(100)
         }
@@ -148,6 +150,65 @@
      */
     @SdkSuppress(minSdkVersion = 23)
     @Test
+    public fun do_not_show_IME_if_TextView_in_dialog_not_focused() {
+        val dialog = scenario.withActivity {
+            object : Dialog(this) {
+                override fun onAttachedToWindow() {
+                    super.onAttachedToWindow()
+                    WindowCompat.setDecorFitsSystemWindows(window!!, false)
+                }
+            }.apply {
+                setContentView(R.layout.insets_compat_activity)
+            }
+        }
+
+        val editText = dialog.findViewById<TextView>(R.id.edittext)
+
+        // We hide the edit text to ensure it won't be automatically focused
+        scenario.onActivity {
+            dialog.show()
+            editText.visibility = View.GONE
+            assertThat(editText.isFocused, `is`(false))
+        }
+
+        val type = WindowInsetsCompat.Type.ime()
+        scenario.onActivity { ViewCompat.getWindowInsetsController(editText)!!.show(type) }
+        container.assertInsetsVisibility(type, false)
+    }
+
+    /**
+     * IME visibility is only reliable on API 23+, where we have access to the root WindowInsets
+     */
+    @SdkSuppress(minSdkVersion = 23)
+    @Test
+    fun show_IME_fromEditText_in_dialog() {
+        val dialog = scenario.withActivity {
+            object : Dialog(this) {
+                override fun onAttachedToWindow() {
+                    super.onAttachedToWindow()
+                    WindowCompat.setDecorFitsSystemWindows(window!!, false)
+                }
+            }.apply {
+                setContentView(R.layout.insets_compat_activity)
+            }
+        }
+
+        val type = WindowInsetsCompat.Type.ime()
+        val editText = dialog.findViewById<TextView>(R.id.edittext)
+
+        scenario.onActivity { dialog.show() }
+
+        val controller = ViewCompat.getWindowInsetsController(editText)!!
+
+        scenario.onActivity { controller.show(type) }
+        editText.assertInsetsVisibility(type, true)
+    }
+
+    /**
+     * IME visibility is only reliable on API 23+, where we have access to the root WindowInsets
+     */
+    @SdkSuppress(minSdkVersion = 23)
+    @Test
     public fun hide_IME() {
         // Test do not currently work on Cuttlefish
         assumeNotCuttlefish()
@@ -200,20 +261,46 @@
 
     /**
      * Tests that after calling setAppearanceLightStatusBars in API 30
-     * isAppearanceLightStatusBars is true and SYSTEM_UI_FLAG_LIGHT_STATUS_BAR flag is unset.
-     *
-     * Currently this works only with Impl30(Window window, WindowInsetsControllerCompat
-     * compatController) constructor (b/180881870).
+     * isAppearanceLightStatusBars is true and SYSTEM_UI_FLAG_LIGHT_STATUS_BAR flag is unset
+     * when using the `ViewCompat` getter.
      */
     @SdkSuppress(minSdkVersion = 30, maxSdkVersion = 30)
     @Test
-    public fun systemBar_light_theme() {
+    public fun systemBar_light_view_compat_getter() {
         val decorView = scenario.withActivity { window.decorView }
 
         scenario.onActivity { activity ->
-            windowInsetsController = WindowInsetsControllerCompat(
-                activity.window, activity.findViewById(R.id.container)
-            )
+            windowInsetsController = ViewCompat.getWindowInsetsController(
+                activity.findViewById(R.id.container)
+            )!!
+
+            decorView.systemUiVisibility = decorView.systemUiVisibility or
+                View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+            windowInsetsController.setAppearanceLightStatusBars(true)
+        }
+
+        assertThat(
+            decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+            equalTo(0)
+        )
+        assertThat(windowInsetsController.isAppearanceLightStatusBars(), `is`(true))
+    }
+
+    /**
+     * Tests that after calling setAppearanceLightStatusBars in API 30
+     * isAppearanceLightStatusBars is true and SYSTEM_UI_FLAG_LIGHT_STATUS_BAR flag is unset
+     * when using the deprecated `Window` and `View` `WindowCompat` getter.
+     */
+    @SdkSuppress(minSdkVersion = 30, maxSdkVersion = 30)
+    @Test
+    public fun systemBar_light_window_compat_window_view_getter() {
+        val decorView = scenario.withActivity { window.decorView }
+
+        scenario.onActivity { activity ->
+            windowInsetsController = WindowCompat.getInsetsController(
+                activity.window,
+                activity.findViewById(R.id.container)
+            )!!
 
             decorView.systemUiVisibility = decorView.systemUiVisibility or
                 View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
diff --git a/core/core/src/main/java/androidx/core/view/ViewCompat.java b/core/core/src/main/java/androidx/core/view/ViewCompat.java
index b5225f0..155e942 100644
--- a/core/core/src/main/java/androidx/core/view/ViewCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ViewCompat.java
@@ -20,11 +20,9 @@
 
 import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
-import android.app.Activity;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Matrix;
@@ -49,7 +47,6 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ViewTreeObserver;
-import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowInsetsController;
 import android.view.WindowManager;
@@ -2669,22 +2666,15 @@
      *
      * @return A {@link WindowInsetsControllerCompat} or {@code null} if the view is neither
      * attached to a window nor a view tree with a decor.
-     * @see WindowCompat#getInsetsController(Window, View)
      */
     @Nullable
     public static WindowInsetsControllerCompat getWindowInsetsController(@NonNull View view) {
-        if (Build.VERSION.SDK_INT >= 30) {
-            return Api30Impl.getWindowInsetsController(view);
-        } else {
-            Context context = view.getContext();
-            while (context instanceof ContextWrapper) {
-                if (context instanceof Activity) {
-                    Window window = ((Activity) context).getWindow();
-                    return window != null ? WindowCompat.getInsetsController(window, view) : null;
-                }
-                context = ((ContextWrapper) context).getBaseContext();
-            }
+        // Pre-API 30 implementations depend on the root view's WindowManager.LayoutParams
+        // to set and unset window flags.
+        if (!(view.getRootView().getLayoutParams() instanceof WindowManager.LayoutParams)) {
             return null;
+        } else {
+            return new WindowInsetsControllerCompat(view);
         }
     }
 
@@ -5073,14 +5063,6 @@
             // This class is not instantiable.
         }
 
-        @Nullable
-        public static WindowInsetsControllerCompat getWindowInsetsController(@NonNull View view) {
-            WindowInsetsController windowInsetsController = view.getWindowInsetsController();
-            return windowInsetsController != null
-                    ? WindowInsetsControllerCompat.toWindowInsetsControllerCompat(
-                    windowInsetsController) : null;
-        }
-
         @DoNotInline
         static void setStateDescription(View view, CharSequence stateDescription) {
             view.setStateDescription(stateDescription);
diff --git a/core/core/src/main/java/androidx/core/view/WindowCompat.java b/core/core/src/main/java/androidx/core/view/WindowCompat.java
index a1f324d..d6ac49e 100644
--- a/core/core/src/main/java/androidx/core/view/WindowCompat.java
+++ b/core/core/src/main/java/androidx/core/view/WindowCompat.java
@@ -21,7 +21,6 @@
 import android.os.Build;
 import android.view.View;
 import android.view.Window;
-import android.view.WindowInsetsController;
 
 import androidx.annotation.DoNotInline;
 import androidx.annotation.IdRes;
@@ -124,22 +123,20 @@
         }
     }
 
-
     /**
-     * Retrieves the single {@link WindowInsetsController} of the window this view is attached to.
+     * Retrieves the single {@link WindowInsetsControllerCompat} of the window this view is attached
+     * to.
      *
-     * @return The {@link WindowInsetsController} or {@code null} if the view is neither attached to
-     * a window nor a view tree with a decor.
+     * @return The {@link WindowInsetsControllerCompat} or {@code null} if the view is neither
+     * attached to a window nor a view tree with a decor.
      * @see Window#getInsetsController()
+     * @deprecated use {@link ViewCompat#getWindowInsetsController(View)} instead
      */
     @Nullable
+    @Deprecated
     public static WindowInsetsControllerCompat getInsetsController(@NonNull Window window,
             @NonNull View view) {
-        if (Build.VERSION.SDK_INT >= 30) {
-            return Api30Impl.getInsetsController(window);
-        } else {
-            return new WindowInsetsControllerCompat(window, view);
-        }
+        return ViewCompat.getWindowInsetsController(view);
     }
 
     @RequiresApi(16)
@@ -174,16 +171,6 @@
                 final boolean decorFitsSystemWindows) {
             window.setDecorFitsSystemWindows(decorFitsSystemWindows);
         }
-
-        @DoNotInline
-        static WindowInsetsControllerCompat getInsetsController(@NonNull Window window) {
-            WindowInsetsController insetsController = window.getInsetsController();
-            if (insetsController != null) {
-                return WindowInsetsControllerCompat.toWindowInsetsControllerCompat(
-                        insetsController);
-            }
-            return null;
-        }
     }
 
     @RequiresApi(28)
diff --git a/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java b/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java
index fa006cd..26e7614 100644
--- a/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java
+++ b/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java
@@ -39,6 +39,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.collection.SimpleArrayMap;
 import androidx.core.graphics.Insets;
+import androidx.core.util.Preconditions;
 import androidx.core.view.WindowInsetsCompat.Type.InsetsType;
 
 import java.lang.annotation.Retention;
@@ -85,27 +86,38 @@
 
     private final Impl mImpl;
 
+    /**
+     * This version fails to workaround
+     * <a href="https://issuetracker.google.com/issues/180881870">
+     *     https://issuetracker.google.com/issues/180881870
+     * </a>, but is present for backwards compatibility.
+     */
     @RequiresApi(30)
+    @Deprecated
     private WindowInsetsControllerCompat(@NonNull WindowInsetsController insetsController) {
+        mImpl = new Impl30(insetsController, this);
+    }
+
+    WindowInsetsControllerCompat(@NonNull View view) {
         if (SDK_INT >= 30) {
-            mImpl = new Impl30(insetsController, this);
+            mImpl = new Impl30(view, this);
+        } else if (SDK_INT >= 26) {
+            mImpl = new Impl26(view);
+        } else if (SDK_INT >= 23) {
+            mImpl = new Impl23(view);
+        } else if (SDK_INT >= 20) {
+            mImpl = new Impl20(view);
         } else {
             mImpl = new Impl();
         }
     }
 
+    /**
+     * @deprecated Use {@link ViewCompat#getWindowInsetsController(View)} instead
+     */
+    @Deprecated
     public WindowInsetsControllerCompat(@NonNull Window window, @NonNull View view) {
-        if (SDK_INT >= 30) {
-            mImpl = new Impl30(window, this);
-        } else if (SDK_INT >= 26) {
-            mImpl = new Impl26(window, view);
-        } else if (SDK_INT >= 23) {
-            mImpl = new Impl23(window, view);
-        } else if (SDK_INT >= 20) {
-            mImpl = new Impl20(window, view);
-        } else {
-            mImpl = new Impl();
-        }
+        this(view);
     }
 
     /**
@@ -113,11 +125,13 @@
      * compatibility purpose.
      *
      * @param insetsController The {@link WindowInsetsController} to wrap.
-     * @return The provided {@link WindowInsetsControllerCompat} wrapped into a
+     * @return The provided {@link WindowInsetsController} wrapped into a
      * {@link WindowInsetsControllerCompat}
+     * @deprecated Use {@link ViewCompat#getWindowInsetsController(View)} instead
      */
     @NonNull
     @RequiresApi(30)
+    @Deprecated
     public static WindowInsetsControllerCompat toWindowInsetsControllerCompat(
             @NonNull WindowInsetsController insetsController) {
         return new WindowInsetsControllerCompat(insetsController);
@@ -390,13 +404,9 @@
     private static class Impl20 extends Impl {
 
         @NonNull
-        protected final Window mWindow;
+        protected final View mView;
 
-        @Nullable
-        private final View mView;
-
-        Impl20(@NonNull Window window, @Nullable View view) {
-            mWindow = window;
+        Impl20(@NonNull View view) {
             mView = view;
         }
 
@@ -425,18 +435,13 @@
                     View view = mView;
 
 
-                    if (view != null && (view.isInEditMode() || view.onCheckIsTextEditor())) {
+                    if (view.isInEditMode() || view.onCheckIsTextEditor()) {
                         // The IME needs a text view to be focused to be shown
                         // The view given to retrieve this controller is a textView so we can assume
                         // that we can focus it in order to show the IME
                         view.requestFocus();
                     } else {
-                        view = mWindow.getCurrentFocus();
-                    }
-
-                    // Fallback on the container view
-                    if (view == null) {
-                        view = mWindow.findViewById(android.R.id.content);
+                        view = mView.getRootView().findFocus();
                     }
 
                     if (view != null && view.hasWindowFocus()) {
@@ -472,33 +477,39 @@
                     setSystemUiFlag(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
                     return;
                 case WindowInsetsCompat.Type.IME:
-                    ((InputMethodManager) mWindow.getContext()
+                    ((InputMethodManager) mView.getContext()
                             .getSystemService(Context.INPUT_METHOD_SERVICE))
-                            .hideSoftInputFromWindow(mWindow.getDecorView().getWindowToken(),
+                            .hideSoftInputFromWindow(mView.getRootView().getWindowToken(),
                                     0);
             }
         }
 
         protected void setSystemUiFlag(int systemUiFlag) {
-            View decorView = mWindow.getDecorView();
+            View decorView = mView.getRootView();
             decorView.setSystemUiVisibility(
                     decorView.getSystemUiVisibility()
                             | systemUiFlag);
         }
 
         protected void unsetSystemUiFlag(int systemUiFlag) {
-            View decorView = mWindow.getDecorView();
+            View decorView = mView.getRootView();
             decorView.setSystemUiVisibility(
                     decorView.getSystemUiVisibility()
                             & ~systemUiFlag);
         }
 
         protected void setWindowFlag(int windowFlag) {
-            mWindow.addFlags(windowFlag);
+            WindowManager.LayoutParams layoutParams =
+                    (WindowManager.LayoutParams) mView.getRootView().getLayoutParams();
+            layoutParams.flags |= windowFlag;
+            mView.getRootView().setLayoutParams(layoutParams);
         }
 
         protected void unsetWindowFlag(int windowFlag) {
-            mWindow.clearFlags(windowFlag);
+            WindowManager.LayoutParams layoutParams =
+                    (WindowManager.LayoutParams) mView.getRootView().getLayoutParams();
+            layoutParams.flags &= ~windowFlag;
+            mView.getRootView().setLayoutParams(layoutParams);
         }
 
         @Override
@@ -545,13 +556,13 @@
     @RequiresApi(23)
     private static class Impl23 extends Impl20 {
 
-        Impl23(@NonNull Window window, @Nullable View view) {
-            super(window, view);
+        Impl23(@NonNull View view) {
+            super(view);
         }
 
         @Override
         public boolean isAppearanceLightStatusBars() {
-            return (mWindow.getDecorView().getSystemUiVisibility()
+            return (mView.getRootView().getSystemUiVisibility()
                     & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
         }
 
@@ -570,13 +581,13 @@
     @RequiresApi(26)
     private static class Impl26 extends Impl23 {
 
-        Impl26(@NonNull Window window, @Nullable View view) {
-            super(window, view);
+        Impl26(@NonNull View view) {
+            super(view);
         }
 
         @Override
         public boolean isAppearanceLightNavigationBars() {
-            return (mWindow.getDecorView().getSystemUiVisibility()
+            return (mView.getRootView().getSystemUiVisibility()
                     & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0;
         }
 
@@ -602,13 +613,26 @@
                 WindowInsetsController.OnControllableInsetsChangedListener>
                 mListeners = new SimpleArrayMap<>();
 
-        protected Window mWindow;
+        protected View mView;
 
-        Impl30(@NonNull Window window, @NonNull WindowInsetsControllerCompat compatController) {
-            this(window.getInsetsController(), compatController);
-            mWindow = window;
+        Impl30(@NonNull View view, @NonNull WindowInsetsControllerCompat compatController) {
+            this(
+                    Preconditions.checkNotNull(view.getWindowInsetsController(),
+                    "The insets controller is null. "
+                            + "The root view might have been detached from its window"),
+                    compatController);
+            mView = view;
         }
 
+        /**
+         * This version fails to workaround
+         * <a href="https://issuetracker.google.com/issues/180881870">
+         *     https://issuetracker.google.com/issues/180881870
+         * </a>, but is present for backwards compatibility.
+         *
+         * @deprecated Use {@link #Impl30(View, WindowInsetsControllerCompat) } instead
+         */
+        @Deprecated
         Impl30(@NonNull WindowInsetsController insetsController,
                 @NonNull WindowInsetsControllerCompat compatController) {
             mInsetsController = insetsController;
@@ -634,7 +658,7 @@
         @Override
         public void setAppearanceLightStatusBars(boolean isLight) {
             if (isLight) {
-                if (mWindow != null) {
+                if (mView != null) {
                     unsetSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                 }
 
@@ -762,7 +786,7 @@
         }
 
         protected void unsetSystemUiFlag(int systemUiFlag) {
-            View decorView = mWindow.getDecorView();
+            View decorView = mView.getRootView();
             decorView.setSystemUiVisibility(
                     decorView.getSystemUiVisibility()
                             & ~systemUiFlag);
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index 260ecfd..9684c9b 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -26,6 +26,6 @@
 # Disable docs
 androidx.enableDocumentation=false
 androidx.playground.snapshotBuildId=8005530
-androidx.playground.metalavaBuildId=7856580
+androidx.playground.metalavaBuildId=8073933
 androidx.playground.dokkaBuildId=7472101
 androidx.studio.type=playground
diff --git a/samples/Support4Demos/src/main/java/com/example/android/supportv4/view/WindowInsetsControllerPlayground.kt b/samples/Support4Demos/src/main/java/com/example/android/supportv4/view/WindowInsetsControllerPlayground.kt
index fb424b1..3d8fa9f 100644
--- a/samples/Support4Demos/src/main/java/com/example/android/supportv4/view/WindowInsetsControllerPlayground.kt
+++ b/samples/Support4Demos/src/main/java/com/example/android/supportv4/view/WindowInsetsControllerPlayground.kt
@@ -504,7 +504,7 @@
                     id: Long
                 ) {
                     if (parent != null && view != null) {
-                        WindowCompat.getInsetsController(window, view)!!
+                        ViewCompat.getWindowInsetsController(view)!!
                             .systemBarsBehavior = types[selectedItem]!!
                     }
                 }