1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.core.view; 18 19 import android.app.Activity; 20 import android.graphics.Rect; 21 import android.os.Build; 22 import android.view.View; 23 import android.view.Window; 24 25 import androidx.annotation.IdRes; 26 import androidx.annotation.RequiresApi; 27 28 import org.jspecify.annotations.NonNull; 29 30 /** 31 * Helper for accessing features in {@link Window}. 32 */ 33 public final class WindowCompat { 34 /** 35 * Flag for enabling the Action Bar. 36 * This is enabled by default for some devices. The Action Bar 37 * replaces the title bar and provides an alternate location 38 * for an on-screen menu button on some devices. 39 */ 40 public static final int FEATURE_ACTION_BAR = 8; 41 42 /** 43 * Flag for requesting an Action Bar that overlays window content. 44 * Normally an Action Bar will sit in the space above window content, but if this 45 * feature is requested along with {@link #FEATURE_ACTION_BAR} it will be layered over 46 * the window content itself. This is useful if you would like your app to have more control 47 * over how the Action Bar is displayed, such as letting application content scroll beneath 48 * an Action Bar with a transparent background or otherwise displaying a transparent/translucent 49 * Action Bar over application content. 50 * 51 * <p>This mode is especially useful with {@link View#SYSTEM_UI_FLAG_FULLSCREEN 52 * View.SYSTEM_UI_FLAG_FULLSCREEN}, which allows you to seamlessly hide the 53 * action bar in conjunction with other screen decorations. 54 * 55 * <p>As of {@link Build.VERSION_CODES#JELLY_BEAN}, when an 56 * ActionBar is in this mode it will adjust the insets provided to 57 * {@link View#fitSystemWindows(Rect) View.fitSystemWindows(Rect)} 58 * to include the content covered by the action bar, so you can do layout within 59 * that space. 60 */ 61 public static final int FEATURE_ACTION_BAR_OVERLAY = 9; 62 63 /** 64 * Flag for specifying the behavior of action modes when an Action Bar is not present. 65 * If overlay is enabled, the action mode UI will be allowed to cover existing window content. 66 */ 67 public static final int FEATURE_ACTION_MODE_OVERLAY = 10; 68 WindowCompat()69 private WindowCompat() {} 70 71 /** 72 * Finds a view that was identified by the {@code android:id} XML attribute 73 * that was processed in {@link Activity#onCreate}, or throws an 74 * IllegalArgumentException if the ID is invalid, or there is no matching view in the hierarchy. 75 * <p> 76 * <strong>Note:</strong> In most cases -- depending on compiler support -- 77 * the resulting view is automatically cast to the target class type. If 78 * the target class type is unconstrained, an explicit cast may be 79 * necessary. 80 * 81 * @param window window in which to find the view. 82 * @param id the ID to search for 83 * @return a view with given ID 84 * @see ViewCompat#requireViewById(View, int) 85 * @see Window#findViewById(int) 86 */ 87 @SuppressWarnings("TypeParameterUnusedInFormals") requireViewById(@onNull Window window, @IdRes int id)88 public static <T extends View> @NonNull T requireViewById(@NonNull Window window, 89 @IdRes int id) { 90 if (Build.VERSION.SDK_INT >= 28) { 91 return Api28Impl.requireViewById(window, id); 92 } 93 94 T view = window.findViewById(id); 95 if (view == null) { 96 throw new IllegalArgumentException("ID does not reference a View inside this Window"); 97 } 98 return view; 99 } 100 101 /** 102 * Sets whether the decor view should fit root-level content views for 103 * {@link WindowInsetsCompat}. 104 * <p> 105 * If set to {@code false}, the framework will not fit the content view to the insets and will 106 * just pass through the {@link WindowInsetsCompat} to the content view. 107 * </p> 108 * <p> 109 * Please note: using the {@link View#setSystemUiVisibility(int)} API in your app can 110 * conflict with this method. Please discontinue use of {@link View#setSystemUiVisibility(int)}. 111 * </p> 112 * 113 * @param window The current window. 114 * @param decorFitsSystemWindows Whether the decor view should fit root-level content views for 115 * insets. 116 */ setDecorFitsSystemWindows(@onNull Window window, final boolean decorFitsSystemWindows)117 public static void setDecorFitsSystemWindows(@NonNull Window window, 118 final boolean decorFitsSystemWindows) { 119 if (Build.VERSION.SDK_INT >= 35) { 120 Api35Impl.setDecorFitsSystemWindows(window, decorFitsSystemWindows); 121 } else if (Build.VERSION.SDK_INT >= 30) { 122 Api30Impl.setDecorFitsSystemWindows(window, decorFitsSystemWindows); 123 } else { 124 Api16Impl.setDecorFitsSystemWindows(window, decorFitsSystemWindows); 125 } 126 } 127 128 /** 129 * Retrieves the single {@link WindowInsetsControllerCompat} of the window this view is attached 130 * to. 131 * 132 * @return The {@link WindowInsetsControllerCompat} for the window. 133 * @see Window#getInsetsController() 134 */ getInsetsController(@onNull Window window, @NonNull View view)135 public static @NonNull WindowInsetsControllerCompat getInsetsController(@NonNull Window window, 136 @NonNull View view) { 137 return new WindowInsetsControllerCompat(window, view); 138 } 139 140 static class Api16Impl { Api16Impl()141 private Api16Impl() { 142 // This class is not instantiable. 143 } 144 setDecorFitsSystemWindows(@onNull Window window, final boolean decorFitsSystemWindows)145 static void setDecorFitsSystemWindows(@NonNull Window window, 146 final boolean decorFitsSystemWindows) { 147 final int decorFitsFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE 148 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 149 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 150 151 final View decorView = window.getDecorView(); 152 final int sysUiVis = decorView.getSystemUiVisibility(); 153 decorView.setSystemUiVisibility(decorFitsSystemWindows 154 ? sysUiVis & ~decorFitsFlags 155 : sysUiVis | decorFitsFlags); 156 } 157 } 158 159 @RequiresApi(30) 160 static class Api30Impl { Api30Impl()161 private Api30Impl() { 162 // This class is not instantiable. 163 } 164 setDecorFitsSystemWindows(@onNull Window window, final boolean decorFitsSystemWindows)165 static void setDecorFitsSystemWindows(@NonNull Window window, 166 final boolean decorFitsSystemWindows) { 167 final int stableFlag = View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 168 169 final View decorView = window.getDecorView(); 170 final int sysUiVis = decorView.getSystemUiVisibility(); 171 decorView.setSystemUiVisibility(decorFitsSystemWindows 172 ? sysUiVis & ~stableFlag 173 : sysUiVis | stableFlag); 174 window.setDecorFitsSystemWindows(decorFitsSystemWindows); 175 } 176 } 177 178 @RequiresApi(35) 179 static class Api35Impl { Api35Impl()180 private Api35Impl() { 181 // This class is not instantiable. 182 } 183 setDecorFitsSystemWindows(@onNull Window window, final boolean decorFitsSystemWindows)184 static void setDecorFitsSystemWindows(@NonNull Window window, 185 final boolean decorFitsSystemWindows) { 186 window.setDecorFitsSystemWindows(decorFitsSystemWindows); 187 } 188 } 189 190 @RequiresApi(28) 191 static class Api28Impl { Api28Impl()192 private Api28Impl() { 193 // This class is not instantiable. 194 } 195 196 @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) requireViewById(Window window, int id)197 static <T> T requireViewById(Window window, int id) { 198 return (T) window.requireViewById(id); 199 } 200 } 201 } 202