public final class

WindowInsetsControllerCompat

extends java.lang.Object

 java.lang.Object

↳androidx.core.view.WindowInsetsControllerCompat

Gradle dependencies

compile group: 'androidx.core', name: 'core', version: '1.9.0-alpha04'

  • groupId: androidx.core
  • artifactId: core
  • version: 1.9.0-alpha04

Artifact androidx.core:core:1.9.0-alpha04 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.core:core com.android.support:support-compat

Overview

Provide simple controls of windows that generate insets. For SDKs >= 30, this class is a simple wrapper around WindowInsetsController. For lower SDKs, this class aims to behave as close as possible to the original implementation.

Summary

Fields
public static final intBEHAVIOR_SHOW_BARS_BY_SWIPE

Option for WindowInsetsControllerCompat.setSystemBarsBehavior(int): Window would like to remain interactive when hiding navigation bars by calling WindowInsetsControllerCompat.hide(int) or WindowInsetsAnimationControllerCompat.setInsetsAndAlpha(Insets, float, float).

public static final intBEHAVIOR_SHOW_BARS_BY_TOUCH

The default option for WindowInsetsControllerCompat.setSystemBarsBehavior(int).

public static final intBEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

Option for WindowInsetsControllerCompat.setSystemBarsBehavior(int): Window would like to remain interactive when hiding navigation bars by calling WindowInsetsControllerCompat.hide(int) or WindowInsetsAnimationControllerCompat.setInsetsAndAlpha(Insets, float, float).

Constructors
publicWindowInsetsControllerCompat(Window window, View view)

Methods
public voidaddOnControllableInsetsChangedListener(WindowInsetsControllerCompat.OnControllableInsetsChangedListener listener)

Adds a to the window insets controller.

public voidcontrolWindowInsetsAnimation(int types, long durationMillis, Interpolator interpolator, CancellationSignal cancellationSignal, WindowInsetsAnimationControlListenerCompat listener)

Lets the application control window inset animations in a frame-by-frame manner by modifying the position of the windows in the system causing insets directly using WindowInsetsAnimationControllerCompat.setInsetsAndAlpha(Insets, float, float) in the controller provided by the given listener.

public intgetSystemBarsBehavior()

Retrieves the requested behavior of system bars.

public voidhide(int types)

Makes a set of windows causing insets disappear.

public booleanisAppearanceLightNavigationBars()

Checks if the foreground of the navigation bar is set to light.

public booleanisAppearanceLightStatusBars()

Checks if the foreground of the status bar is set to light.

public voidremoveOnControllableInsetsChangedListener(WindowInsetsControllerCompat.OnControllableInsetsChangedListener listener)

Removes a from the window insets controller.

public voidsetAppearanceLightNavigationBars(boolean isLight)

If true, changes the foreground color of the navigation bars to light so that the items on the bar can be read clearly.

public voidsetAppearanceLightStatusBars(boolean isLight)

If true, changes the foreground color of the status bars to light so that the items on the bar can be read clearly.

public voidsetSystemBarsBehavior(int behavior)

Controls the behavior of system bars.

public voidshow(int types)

Makes a set of windows that cause insets appear on screen.

public static WindowInsetsControllerCompattoWindowInsetsControllerCompat(WindowInsetsController insetsController)

Wrap a WindowInsetsController into a WindowInsetsControllerCompat for compatibility purpose.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH

The default option for WindowInsetsControllerCompat.setSystemBarsBehavior(int). System bars will be forcibly shown on any user interaction on the corresponding display if navigation bars are hidden by WindowInsetsControllerCompat.hide(int) or WindowInsetsAnimationControllerCompat.setInsetsAndAlpha(Insets, float, float).

public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE

Option for WindowInsetsControllerCompat.setSystemBarsBehavior(int): Window would like to remain interactive when hiding navigation bars by calling WindowInsetsControllerCompat.hide(int) or WindowInsetsAnimationControllerCompat.setInsetsAndAlpha(Insets, float, float).

When system bars are hidden in this mode, they can be revealed with system gestures, such as swiping from the edge of the screen where the bar is hidden from.

public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

Option for WindowInsetsControllerCompat.setSystemBarsBehavior(int): Window would like to remain interactive when hiding navigation bars by calling WindowInsetsControllerCompat.hide(int) or WindowInsetsAnimationControllerCompat.setInsetsAndAlpha(Insets, float, float).

When system bars are hidden in this mode, they can be revealed temporarily with system gestures, such as swiping from the edge of the screen where the bar is hidden from. These transient system bars will overlay app’s content, may have some degree of transparency, and will automatically hide after a short timeout.

Constructors

public WindowInsetsControllerCompat(Window window, View view)

Methods

public static WindowInsetsControllerCompat toWindowInsetsControllerCompat(WindowInsetsController insetsController)

Deprecated: Use WindowCompat.getInsetsController(Window, View) instead

Wrap a WindowInsetsController into a WindowInsetsControllerCompat for compatibility purpose.

Parameters:

insetsController: The WindowInsetsController to wrap.

Returns:

The provided WindowInsetsController wrapped into a WindowInsetsControllerCompat

public void show(int types)

Makes a set of windows that cause insets appear on screen.

Note that if the window currently doesn't have control over a certain type, it will apply the change as soon as the window gains control. The app can listen to the event by observing View and checking visibility with WindowInsets.

Parameters:

types: A bitmask of WindowInsetsCompat.Type specifying what windows the app would like to make appear on screen.

public void hide(int types)

Makes a set of windows causing insets disappear.

Note that if the window currently doesn't have control over a certain type, it will apply the change as soon as the window gains control. The app can listen to the event by observing View and checking visibility with WindowInsets.

Parameters:

types: A bitmask of WindowInsetsCompat.Type specifying what windows the app would like to make disappear.

public boolean isAppearanceLightStatusBars()

Checks if the foreground of the status bar is set to light.

This method always returns false on API < 23.

Returns:

true if the foreground is light

See also: WindowInsetsControllerCompat.setAppearanceLightStatusBars(boolean)

public void setAppearanceLightStatusBars(boolean isLight)

If true, changes the foreground color of the status bars to light so that the items on the bar can be read clearly. If false, reverts to the default appearance.

This method has no effect on API < 23.

See also: WindowInsetsControllerCompat.isAppearanceLightStatusBars()

public boolean isAppearanceLightNavigationBars()

Checks if the foreground of the navigation bar is set to light.

This method always returns false on API < 26.

Returns:

true if the foreground is light

See also: WindowInsetsControllerCompat.setAppearanceLightNavigationBars(boolean)

public void setAppearanceLightNavigationBars(boolean isLight)

If true, changes the foreground color of the navigation bars to light so that the items on the bar can be read clearly. If false, reverts to the default appearance.

This method has no effect on API < 26.

See also: WindowInsetsControllerCompat.isAppearanceLightNavigationBars()

public void controlWindowInsetsAnimation(int types, long durationMillis, Interpolator interpolator, CancellationSignal cancellationSignal, WindowInsetsAnimationControlListenerCompat listener)

Lets the application control window inset animations in a frame-by-frame manner by modifying the position of the windows in the system causing insets directly using WindowInsetsAnimationControllerCompat.setInsetsAndAlpha(Insets, float, float) in the controller provided by the given listener.

This method only works on API >= 30 since there is no way to control the window in the system on prior APIs.

Parameters:

types: The WindowInsetsCompat.Types the application has requested to control.
durationMillis: Duration of animation in MILLISECONDS, or -1 if the animation doesn't have a predetermined duration. This value will be passed to WindowInsetsAnimationCompat.getDurationMillis()
interpolator: The interpolator used for this animation, or null if this animation doesn't follow an interpolation curve. This value will be passed to WindowInsetsAnimationCompat.getInterpolator() and used to calculate WindowInsetsAnimationCompat.getInterpolatedFraction().
cancellationSignal: A cancellation signal that the caller can use to cancel the request to obtain control, or once they have control, to cancel the control.
listener: The that gets called when the windows are ready to be controlled, among other callbacks.

See also: WindowInsetsAnimationCompat.getFraction(), WindowInsetsAnimationCompat.getInterpolatedFraction(), WindowInsetsAnimationCompat.getInterpolator(), WindowInsetsAnimationCompat.getDurationMillis()

public void setSystemBarsBehavior(int behavior)

Controls the behavior of system bars.

Parameters:

behavior: Determines how the bars behave when being hidden by the application.

See also: WindowInsetsControllerCompat.getSystemBarsBehavior()

public int getSystemBarsBehavior()

Retrieves the requested behavior of system bars.

Returns:

the system bar behavior controlled by this window.

See also: WindowInsetsControllerCompat.setSystemBarsBehavior(int)

public void addOnControllableInsetsChangedListener(WindowInsetsControllerCompat.OnControllableInsetsChangedListener listener)

Adds a to the window insets controller.

Parameters:

listener: The listener to add.

See also: WindowInsetsControllerCompat.OnControllableInsetsChangedListener, WindowInsetsControllerCompat.removeOnControllableInsetsChangedListener(WindowInsetsControllerCompat.OnControllableInsetsChangedListener)

public void removeOnControllableInsetsChangedListener(WindowInsetsControllerCompat.OnControllableInsetsChangedListener listener)

Removes a from the window insets controller.

Parameters:

listener: The listener to remove.

See also: WindowInsetsControllerCompat.OnControllableInsetsChangedListener, WindowInsetsControllerCompat.addOnControllableInsetsChangedListener(WindowInsetsControllerCompat.OnControllableInsetsChangedListener)

Source

/*
 * Copyright 2020 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 androidx.core.view;

import static android.os.Build.VERSION.SDK_INT;

import android.annotation.SuppressLint;
import android.content.Context;
import android.inputmethodservice.InputMethodService;
import android.os.CancellationSignal;
import android.view.View;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimationControlListener;
import android.view.WindowInsetsAnimationController;
import android.view.WindowInsetsController;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.view.inputmethod.InputMethodManager;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.collection.SimpleArrayMap;
import androidx.core.graphics.Insets;
import androidx.core.view.WindowInsetsCompat.Type.InsetsType;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.TimeUnit;

/**
 * Provide simple controls of windows that generate insets.
 *
 * For SDKs >= 30, this class is a simple wrapper around {@link WindowInsetsController}. For
 * lower SDKs, this class aims to behave as close as possible to the original implementation.
 */
public final class WindowInsetsControllerCompat {

    /**
     * The default option for {@link #setSystemBarsBehavior(int)}. System bars will be forcibly
     * shown on any user interaction on the corresponding display if navigation bars are hidden
     * by {@link #hide(int)} or
     * {@link WindowInsetsAnimationControllerCompat#setInsetsAndAlpha(Insets, float, float)}.
     */
    public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0;

    /**
     * Option for {@link #setSystemBarsBehavior(int)}: Window would like to remain interactive
     * when hiding navigation bars by calling {@link #hide(int)} or
     * {@link WindowInsetsAnimationControllerCompat#setInsetsAndAlpha(Insets, float, float)}.
     * <p>
     * When system bars are hidden in this mode, they can be revealed with system
     * gestures, such as swiping from the edge of the screen where the bar is hidden from.
     */
    public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1;

    /**
     * Option for {@link #setSystemBarsBehavior(int)}: Window would like to remain
     * interactive when hiding navigation bars by calling {@link #hide(int)} or
     * {@link WindowInsetsAnimationControllerCompat#setInsetsAndAlpha(Insets, float, float)}.
     * <p>
     * When system bars are hidden in this mode, they can be revealed temporarily with system
     * gestures, such as swiping from the edge of the screen where the bar is hidden from. These
     * transient system bars will overlay app’s content, may have some degree of
     * transparency, and will automatically hide after a short timeout.
     */
    public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2;

    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);
    }

    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();
        }
    }

    /**
     * Wrap a {@link WindowInsetsController} into a {@link WindowInsetsControllerCompat} for
     * compatibility purpose.
     *
     * @param insetsController The {@link WindowInsetsController} to wrap.
     * @return The provided {@link WindowInsetsController} wrapped into a
     * {@link WindowInsetsControllerCompat}
     * @deprecated Use {@link WindowCompat#getInsetsController(Window, View)} instead
     */
    @NonNull
    @RequiresApi(30)
    @Deprecated
    public static WindowInsetsControllerCompat toWindowInsetsControllerCompat(
            @NonNull WindowInsetsController insetsController) {
        return new WindowInsetsControllerCompat(insetsController);
    }

    /**
     * Determines the behavior of system bars when hiding them by calling {@link #hide}.
     *
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(value = {BEHAVIOR_SHOW_BARS_BY_TOUCH, BEHAVIOR_SHOW_BARS_BY_SWIPE,
            BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE})
    @interface Behavior {
    }

    /**
     * Makes a set of windows that cause insets appear on screen.
     * <p>
     * Note that if the window currently doesn't have control over a certain type, it will apply the
     * change as soon as the window gains control. The app can listen to the event by observing
     * {@link View#onApplyWindowInsets} and checking visibility with {@link WindowInsets#isVisible}.
     *
     * @param types A bitmask of {@link WindowInsetsCompat.Type} specifying what windows the app
     *              would like to make appear on screen.
     */
    public void show(@InsetsType int types) {
        mImpl.show(types);
    }

    /**
     * Makes a set of windows causing insets disappear.
     * <p>
     * Note that if the window currently doesn't have control over a certain type, it will apply the
     * change as soon as the window gains control. The app can listen to the event by observing
     * {@link View#onApplyWindowInsets} and checking visibility with {@link WindowInsets#isVisible}.
     *
     * @param types A bitmask of {@link WindowInsetsCompat.Type} specifying what windows the app
     *              would like to make disappear.
     */
    public void hide(@InsetsType int types) {
        mImpl.hide(types);
    }


    /**
     * Checks if the foreground of the status bar is set to light.
     * <p>
     * This method always returns false on API < 23.
     *
     * @return true if the foreground is light
     * @see #setAppearanceLightStatusBars(boolean)
     */
    public boolean isAppearanceLightStatusBars() {
        return mImpl.isAppearanceLightStatusBars();
    }

    /**
     * If true, changes the foreground color of the status bars to light so that the items on the
     * bar can be read clearly. If false, reverts to the default appearance.
     * <p>
     * This method has no effect on API < 23.
     *
     * @see #isAppearanceLightStatusBars()
     */
    public void setAppearanceLightStatusBars(boolean isLight) {
        mImpl.setAppearanceLightStatusBars(isLight);
    }

    /**
     * Checks if the foreground of the navigation bar is set to light.
     * <p>
     * This method always returns false on API < 26.
     *
     * @return true if the foreground is light
     * @see #setAppearanceLightNavigationBars(boolean)
     */
    public boolean isAppearanceLightNavigationBars() {
        return mImpl.isAppearanceLightNavigationBars();
    }

    /**
     * If true, changes the foreground color of the navigation bars to light so that the items on
     * the bar can be read clearly. If false, reverts to the default appearance.
     * <p>
     * This method has no effect on API < 26.
     *
     * @see #isAppearanceLightNavigationBars()
     */
    public void setAppearanceLightNavigationBars(boolean isLight) {
        mImpl.setAppearanceLightNavigationBars(isLight);
    }

    /**
     * Lets the application control window inset animations in a frame-by-frame manner by
     * modifying the position of the windows in the system causing insets directly using
     * {@link WindowInsetsAnimationControllerCompat#setInsetsAndAlpha} in the controller provided
     * by the given listener.
     * <p>
     * This method only works on API >= 30 since there is no way to control the window in the
     * system on prior APIs.
     *
     * @param types              The {@link WindowInsetsCompat.Type}s the application has
     *                           requested to control.
     * @param durationMillis     Duration of animation in {@link TimeUnit#MILLISECONDS}, or -1 if
     *                           the animation doesn't have a predetermined duration. This value
     *                           will be passed to
     *                           {@link WindowInsetsAnimationCompat#getDurationMillis()}
     * @param interpolator       The interpolator used for this animation, or {@code null } if
     *                           this animation doesn't follow an interpolation curve. This value
     *                           will be passed to
     *                           {@link WindowInsetsAnimationCompat#getInterpolator()} and used
     *                           to calculate
     *                           {@link WindowInsetsAnimationCompat#getInterpolatedFraction()}.
     * @param cancellationSignal A cancellation signal that the caller can use to cancel the
     *                           request to obtain control, or once they have control, to cancel
     *                           the control.
     * @param listener           The {@link WindowInsetsAnimationControlListener} that gets
     *                           called when the windows are ready to be controlled, among other
     *                           callbacks.
     * @see WindowInsetsAnimationCompat#getFraction()
     * @see WindowInsetsAnimationCompat#getInterpolatedFraction()
     * @see WindowInsetsAnimationCompat#getInterpolator()
     * @see WindowInsetsAnimationCompat#getDurationMillis()
     */
    public void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
            @Nullable Interpolator interpolator,
            @Nullable CancellationSignal cancellationSignal,
            @NonNull WindowInsetsAnimationControlListenerCompat listener) {
        mImpl.controlWindowInsetsAnimation(types,
                durationMillis,
                interpolator,
                cancellationSignal,
                listener);
    }

    /**
     * Controls the behavior of system bars.
     *
     * @param behavior Determines how the bars behave when being hidden by the application.
     * @see #getSystemBarsBehavior
     */
    public void setSystemBarsBehavior(@Behavior int behavior) {
        mImpl.setSystemBarsBehavior(behavior);
    }

    /**
     * Retrieves the requested behavior of system bars.
     *
     * @return the system bar behavior controlled by this window.
     * @see #setSystemBarsBehavior(int)
     */
    @SuppressLint("WrongConstant")
    @Behavior
    public int getSystemBarsBehavior() {
        return mImpl.getSystemBarsBehavior();
    }

    /**
     * Adds a {@link WindowInsetsController.OnControllableInsetsChangedListener} to the window
     * insets controller.
     *
     * @param listener The listener to add.
     * @see WindowInsetsControllerCompat.OnControllableInsetsChangedListener
     * @see #removeOnControllableInsetsChangedListener(
     *WindowInsetsControllerCompat.OnControllableInsetsChangedListener)
     */
    public void addOnControllableInsetsChangedListener(
            @NonNull WindowInsetsControllerCompat.OnControllableInsetsChangedListener listener) {
        mImpl.addOnControllableInsetsChangedListener(listener);
    }

    /**
     * Removes a {@link WindowInsetsController.OnControllableInsetsChangedListener} from the
     * window insets controller.
     *
     * @param listener The listener to remove.
     * @see WindowInsetsControllerCompat.OnControllableInsetsChangedListener
     * @see #addOnControllableInsetsChangedListener(
     *WindowInsetsControllerCompat.OnControllableInsetsChangedListener)
     */
    public void removeOnControllableInsetsChangedListener(
            @NonNull WindowInsetsControllerCompat.OnControllableInsetsChangedListener
                    listener) {
        mImpl.removeOnControllableInsetsChangedListener(listener);
    }

    /**
     * Listener to be notified when the set of controllable {@link WindowInsetsCompat.Type}
     * controlled by a {@link WindowInsetsController} changes.
     * <p>
     * Once a {@link WindowInsetsCompat.Type} becomes controllable, the app will be able to
     * control the window that is causing this type of insets by calling
     * {@link #controlWindowInsetsAnimation}.
     * <p>
     * Note: When listening to cancellability of the {@link WindowInsets.Type#ime},
     * {@link #controlWindowInsetsAnimation} may still fail in case the {@link InputMethodService}
     * decides to cancel the show request. This could happen when there is a hardware keyboard
     * attached.
     *
     * @see #addOnControllableInsetsChangedListener(
     *WindowInsetsControllerCompat.OnControllableInsetsChangedListener)
     * @see #removeOnControllableInsetsChangedListener(
     *WindowInsetsControllerCompat.OnControllableInsetsChangedListener)
     */
    public interface OnControllableInsetsChangedListener {

        /**
         * Called when the set of controllable {@link WindowInsetsCompat.Type} changes.
         *
         * @param controller The controller for which the set of controllable
         *                   {@link WindowInsetsCompat.Type}s
         *                   are changing.
         * @param typeMask   Bitwise behavior type-mask of the {@link WindowInsetsCompat.Type}s
         *                   the controller is currently able to control.
         */
        void onControllableInsetsChanged(@NonNull WindowInsetsControllerCompat controller,
                @InsetsType int typeMask);
    }

    private static class Impl {
        Impl() {
            //private
        }

        void show(int types) {
        }

        void hide(int types) {
        }

        void controlWindowInsetsAnimation(int types, long durationMillis,
                Interpolator interpolator, CancellationSignal cancellationSignal,
                WindowInsetsAnimationControlListenerCompat listener) {
        }

        void setSystemBarsBehavior(int behavior) {
        }

        int getSystemBarsBehavior() {
            return 0;
        }

        public boolean isAppearanceLightStatusBars() {
            return false;
        }

        public void setAppearanceLightStatusBars(boolean isLight) {
        }

        public boolean isAppearanceLightNavigationBars() {
            return false;
        }

        public void setAppearanceLightNavigationBars(boolean isLight) {
        }

        void addOnControllableInsetsChangedListener(
                WindowInsetsControllerCompat.OnControllableInsetsChangedListener listener) {
        }

        void removeOnControllableInsetsChangedListener(
                @NonNull WindowInsetsControllerCompat.OnControllableInsetsChangedListener
                        listener) {
        }
    }

    @RequiresApi(20)
    private static class Impl20 extends Impl {

        @NonNull
        protected final Window mWindow;

        @NonNull
        private final View mView;

        Impl20(@NonNull Window window, @NonNull View view) {
            mWindow = window;
            mView = view;
        }

        @Override
        void show(int typeMask) {
            for (int i = WindowInsetsCompat.Type.FIRST; i <= WindowInsetsCompat.Type.LAST;
                    i = i << 1) {
                if ((typeMask & i) == 0) {
                    continue;
                }
                showForType(i);
            }
        }

        private void showForType(int type) {
            switch (type) {
                case WindowInsetsCompat.Type.STATUS_BARS:
                    unsetSystemUiFlag(View.SYSTEM_UI_FLAG_FULLSCREEN);
                    unsetWindowFlag(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                    return;
                case WindowInsetsCompat.Type.NAVIGATION_BARS:
                    unsetSystemUiFlag(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
                    return;
                case WindowInsetsCompat.Type.IME:
                    // We'll try to find an available textView to focus to show the IME
                    View view = mView;


                    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);
                    }

                    if (view != null && view.hasWindowFocus()) {
                        final View finalView = view;
                        finalView.post(() -> {
                            InputMethodManager imm =
                                    (InputMethodManager) finalView.getContext()
                                            .getSystemService(Context.INPUT_METHOD_SERVICE);
                            imm.showSoftInput(finalView, 0);

                        });
                    }
            }
        }

        @Override
        void hide(int typeMask) {
            for (int i = WindowInsetsCompat.Type.FIRST; i <= WindowInsetsCompat.Type.LAST;
                    i = i << 1) {
                if ((typeMask & i) == 0) {
                    continue;
                }
                hideForType(i);
            }
        }

        private void hideForType(int type) {
            switch (type) {
                case WindowInsetsCompat.Type.STATUS_BARS:
                    setSystemUiFlag(View.SYSTEM_UI_FLAG_FULLSCREEN);
                    return;
                case WindowInsetsCompat.Type.NAVIGATION_BARS:
                    setSystemUiFlag(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
                    return;
                case WindowInsetsCompat.Type.IME:
                    ((InputMethodManager) mWindow.getContext()
                            .getSystemService(Context.INPUT_METHOD_SERVICE))
                            .hideSoftInputFromWindow(mWindow.getDecorView().getWindowToken(),
                                    0);
            }
        }

        protected void setSystemUiFlag(int systemUiFlag) {
            View decorView = mWindow.getDecorView();
            decorView.setSystemUiVisibility(
                    decorView.getSystemUiVisibility()
                            | systemUiFlag);
        }

        protected void unsetSystemUiFlag(int systemUiFlag) {
            View decorView = mWindow.getDecorView();
            decorView.setSystemUiVisibility(
                    decorView.getSystemUiVisibility()
                            & ~systemUiFlag);
        }

        protected void setWindowFlag(int windowFlag) {
            mWindow.addFlags(windowFlag);
        }

        protected void unsetWindowFlag(int windowFlag) {
            mWindow.clearFlags(windowFlag);
        }

        @Override
        void controlWindowInsetsAnimation(int types, long durationMillis,
                Interpolator interpolator, CancellationSignal cancellationSignal,
                WindowInsetsAnimationControlListenerCompat listener) {
        }

        @Override
        void setSystemBarsBehavior(int behavior) {
            switch (behavior) {
                case BEHAVIOR_SHOW_BARS_BY_SWIPE:
                    unsetSystemUiFlag(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
                    setSystemUiFlag(View.SYSTEM_UI_FLAG_IMMERSIVE);
                    break;
                case BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE:
                    unsetSystemUiFlag(View.SYSTEM_UI_FLAG_IMMERSIVE);
                    setSystemUiFlag(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
                    break;
                case BEHAVIOR_SHOW_BARS_BY_TOUCH:
                    unsetSystemUiFlag(View.SYSTEM_UI_FLAG_IMMERSIVE
                            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
                    break;
            }
        }

        @Override
        int getSystemBarsBehavior() {
            return 0;
        }

        @Override
        void addOnControllableInsetsChangedListener(
                WindowInsetsControllerCompat.OnControllableInsetsChangedListener listener) {
        }

        @Override
        void removeOnControllableInsetsChangedListener(
                @NonNull WindowInsetsControllerCompat.OnControllableInsetsChangedListener
                        listener) {
        }
    }

    @RequiresApi(23)
    private static class Impl23 extends Impl20 {

        Impl23(@NonNull Window window, @Nullable View view) {
            super(window, view);
        }

        @Override
        public boolean isAppearanceLightStatusBars() {
            return (mWindow.getDecorView().getSystemUiVisibility()
                    & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
        }

        @Override
        public void setAppearanceLightStatusBars(boolean isLight) {
            if (isLight) {
                unsetWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                setWindowFlag(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                setSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            } else {
                unsetSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            }
        }
    }

    @RequiresApi(26)
    private static class Impl26 extends Impl23 {

        Impl26(@NonNull Window window, @Nullable View view) {
            super(window, view);
        }

        @Override
        public boolean isAppearanceLightNavigationBars() {
            return (mWindow.getDecorView().getSystemUiVisibility()
                    & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0;
        }

        @Override
        public void setAppearanceLightNavigationBars(boolean isLight) {
            if (isLight) {
                unsetWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
                setWindowFlag(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                setSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
            } else {
                unsetSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
            }
        }
    }

    @RequiresApi(30)
    private static class Impl30 extends Impl {

        final WindowInsetsControllerCompat mCompatController;
        final WindowInsetsController mInsetsController;
        private final SimpleArrayMap<
                WindowInsetsControllerCompat.OnControllableInsetsChangedListener,
                WindowInsetsController.OnControllableInsetsChangedListener>
                mListeners = new SimpleArrayMap<>();

        protected Window mWindow;

        Impl30(@NonNull Window window, @NonNull WindowInsetsControllerCompat compatController) {
            this(window.getInsetsController(), compatController);
            mWindow = window;
        }

        Impl30(@NonNull WindowInsetsController insetsController,
                @NonNull WindowInsetsControllerCompat compatController) {
            mInsetsController = insetsController;
            mCompatController = compatController;
        }

        @Override
        void show(@InsetsType int types) {
            if (mWindow != null && (types & WindowInsetsCompat.Type.IME) != 0 && SDK_INT < 32) {
                InputMethodManager imm =
                        (InputMethodManager) mWindow.getContext()
                                .getSystemService(Context.INPUT_METHOD_SERVICE);

                // This is a strange-looking workaround by making a call and ignoring the result.
                // We don't use the return value here, but isActive() has the side-effect of
                // calling a hidden method checkFocus(), which ensures that the IME state has the
                // correct view in some situations (especially when the focused view changes).
                // This is essentially a backport, since an equivalent checkFocus() call was
                // added in API 32 to improve behavior:
                // https://issuetracker.google.com/issues/189858204
                imm.isActive();
            }
            mInsetsController.show(types);
        }

        @Override
        void hide(@InsetsType int types) {
            mInsetsController.hide(types);
        }

        @Override
        public boolean isAppearanceLightStatusBars() {
            return (mInsetsController.getSystemBarsAppearance()
                    & WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS) != 0;
        }

        @Override
        public void setAppearanceLightStatusBars(boolean isLight) {
            if (isLight) {
                if (mWindow != null) {
                    setSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                }

                mInsetsController.setSystemBarsAppearance(
                        WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
                        WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
            } else {
                if (mWindow != null) {
                    unsetSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
                }

                mInsetsController.setSystemBarsAppearance(
                        0,
                        WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
            }
        }

        @Override
        public boolean isAppearanceLightNavigationBars() {
            return (mInsetsController.getSystemBarsAppearance()
                    & WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS) != 0;
        }

        @Override
        public void setAppearanceLightNavigationBars(boolean isLight) {
            if (isLight) {
                if (mWindow != null) {
                    setSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
                }

                mInsetsController.setSystemBarsAppearance(
                        WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS,
                        WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS);
            } else {
                if (mWindow != null) {
                    unsetSystemUiFlag(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
                }

                mInsetsController.setSystemBarsAppearance(
                        0,
                        WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS);
            }
        }

        @Override
        void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
                @Nullable Interpolator interpolator,
                @Nullable CancellationSignal cancellationSignal,
                @NonNull final WindowInsetsAnimationControlListenerCompat listener) {

            WindowInsetsAnimationControlListener fwListener =
                    new WindowInsetsAnimationControlListener() {

                        private WindowInsetsAnimationControllerCompat mCompatAnimController = null;

                        @Override
                        public void onReady(@NonNull WindowInsetsAnimationController controller,
                                int types) {
                            mCompatAnimController =
                                    new WindowInsetsAnimationControllerCompat(controller);
                            listener.onReady(mCompatAnimController, types);
                        }

                        @Override
                        public void onFinished(
                                @NonNull WindowInsetsAnimationController controller) {
                            listener.onFinished(mCompatAnimController);
                        }

                        @Override
                        public void onCancelled(
                                @Nullable WindowInsetsAnimationController controller) {
                            listener.onCancelled(controller == null ? null : mCompatAnimController);
                        }
                    };

            mInsetsController.controlWindowInsetsAnimation(types,
                    durationMillis,
                    interpolator,
                    cancellationSignal,
                    fwListener);
        }

        /**
         * Controls the behavior of system bars.
         *
         * @param behavior Determines how the bars behave when being hidden by the application.
         * @see #getSystemBarsBehavior
         */
        @Override
        void setSystemBarsBehavior(@Behavior int behavior) {
            mInsetsController.setSystemBarsBehavior(behavior);
        }

        /**
         * Retrieves the requested behavior of system bars.
         *
         * @return the system bar behavior controlled by this window.
         * @see #setSystemBarsBehavior(int)
         */
        @SuppressLint("WrongConstant")
        @Override
        @Behavior
        int getSystemBarsBehavior() {
            return mInsetsController.getSystemBarsBehavior();
        }

        @Override
        void addOnControllableInsetsChangedListener(
                @NonNull final WindowInsetsControllerCompat.OnControllableInsetsChangedListener
                        listener) {

            if (mListeners.containsKey(listener)) {
                // The listener has already been added.
                return;
            }
            WindowInsetsController.OnControllableInsetsChangedListener
                    fwListener = (controller, typeMask) -> {
                        if (mInsetsController == controller) {
                            listener.onControllableInsetsChanged(
                                    mCompatController, typeMask);
                        }
                    };
            mListeners.put(listener, fwListener);
            mInsetsController.addOnControllableInsetsChangedListener(fwListener);
        }

        @Override
        void removeOnControllableInsetsChangedListener(
                @NonNull WindowInsetsControllerCompat.OnControllableInsetsChangedListener
                        listener) {
            WindowInsetsController.OnControllableInsetsChangedListener
                    fwListener = mListeners.remove(listener);
            if (fwListener != null) {
                mInsetsController.removeOnControllableInsetsChangedListener(fwListener);
            }
        }

        protected void unsetSystemUiFlag(int systemUiFlag) {
            View decorView = mWindow.getDecorView();
            decorView.setSystemUiVisibility(
                    decorView.getSystemUiVisibility()
                            & ~systemUiFlag);
        }

        protected void setSystemUiFlag(int systemUiFlag) {
            View decorView = mWindow.getDecorView();
            decorView.setSystemUiVisibility(
                    decorView.getSystemUiVisibility()
                            | systemUiFlag);
        }
    }
}