WindowCompat.java
/*
* Copyright 2018 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 android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowInsetsController;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
/**
* Helper for accessing features in {@link Window}.
*/
public final class WindowCompat {
/**
* Flag for enabling the Action Bar.
* This is enabled by default for some devices. The Action Bar
* replaces the title bar and provides an alternate location
* for an on-screen menu button on some devices.
*/
public static final int FEATURE_ACTION_BAR = 8;
/**
* Flag for requesting an Action Bar that overlays window content.
* Normally an Action Bar will sit in the space above window content, but if this
* feature is requested along with {@link #FEATURE_ACTION_BAR} it will be layered over
* the window content itself. This is useful if you would like your app to have more control
* over how the Action Bar is displayed, such as letting application content scroll beneath
* an Action Bar with a transparent background or otherwise displaying a transparent/translucent
* Action Bar over application content.
*
* <p>This mode is especially useful with {@link View#SYSTEM_UI_FLAG_FULLSCREEN
* View.SYSTEM_UI_FLAG_FULLSCREEN}, which allows you to seamlessly hide the
* action bar in conjunction with other screen decorations.
*
* <p>As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, when an
* ActionBar is in this mode it will adjust the insets provided to
* {@link View#fitSystemWindows(android.graphics.Rect) View.fitSystemWindows(Rect)}
* to include the content covered by the action bar, so you can do layout within
* that space.
*/
public static final int FEATURE_ACTION_BAR_OVERLAY = 9;
/**
* Flag for specifying the behavior of action modes when an Action Bar is not present.
* If overlay is enabled, the action mode UI will be allowed to cover existing window content.
*/
public static final int FEATURE_ACTION_MODE_OVERLAY = 10;
private WindowCompat() {}
/**
* Finds a view that was identified by the {@code android:id} XML attribute
* that was processed in {@link android.app.Activity#onCreate}, or throws an
* IllegalArgumentException if the ID is invalid, or there is no matching view in the hierarchy.
* <p>
* <strong>Note:</strong> In most cases -- depending on compiler support --
* the resulting view is automatically cast to the target class type. If
* the target class type is unconstrained, an explicit cast may be
* necessary.
*
* @param id the ID to search for
* @return a view with given ID
* @see ViewCompat#requireViewById(View, int)
* @see Window#findViewById(int)
*/
@SuppressWarnings("TypeParameterUnusedInFormals")
@NonNull
public static <T extends View> T requireViewById(@NonNull Window window, @IdRes int id) {
if (Build.VERSION.SDK_INT >= 28) {
return window.requireViewById(id);
}
T view = window.findViewById(id);
if (view == null) {
throw new IllegalArgumentException("ID does not reference a View inside this Window");
}
return view;
}
/**
* Sets whether the decor view should fit root-level content views for
* {@link WindowInsetsCompat}.
* <p>
* If set to {@code false}, the framework will not fit the content view to the insets and will
* just pass through the {@link WindowInsetsCompat} to the content view.
* </p>
* <p>
* Please note: using the {@link View#setSystemUiVisibility(int)} API in your app can
* conflict with this method. Please discontinue use of {@link View#setSystemUiVisibility(int)}.
* </p>
*
* @param window The current window.
* @param decorFitsSystemWindows Whether the decor view should fit root-level content views for
* insets.
*/
public static void setDecorFitsSystemWindows(@NonNull Window window,
final boolean decorFitsSystemWindows) {
if (Build.VERSION.SDK_INT >= 30) {
Impl30.setDecorFitsSystemWindows(window, decorFitsSystemWindows);
} else if (Build.VERSION.SDK_INT >= 16) {
Impl16.setDecorFitsSystemWindows(window, decorFitsSystemWindows);
}
}
/**
* Retrieves the single {@link WindowInsetsController} 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.
* @see Window#getInsetsController()
*/
@Nullable
public static WindowInsetsControllerCompat getInsetsController(@NonNull Window window,
@NonNull View view) {
if (Build.VERSION.SDK_INT >= 30) {
return Impl30.getInsetsController(window);
} else {
return new WindowInsetsControllerCompat(window, view);
}
}
@RequiresApi(16)
private static class Impl16 {
static void setDecorFitsSystemWindows(@NonNull Window window,
final boolean decorFitsSystemWindows) {
final int decorFitsFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
final View decorView = window.getDecorView();
final int sysUiVis = decorView.getSystemUiVisibility();
decorView.setSystemUiVisibility(decorFitsSystemWindows
? sysUiVis & ~decorFitsFlags
: sysUiVis | decorFitsFlags);
}
}
@RequiresApi(30)
private static class Impl30 {
static void setDecorFitsSystemWindows(@NonNull Window window,
final boolean decorFitsSystemWindows) {
window.setDecorFitsSystemWindows(decorFitsSystemWindows);
}
static WindowInsetsControllerCompat getInsetsController(@NonNull Window window) {
WindowInsetsController insetsController = window.getInsetsController();
if (insetsController != null) {
return WindowInsetsControllerCompat.toWindowInsetsControllerCompat(
insetsController);
}
return null;
}
}
}