1 /* 2 * Copyright (C) 2006 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 android.view; 18 19 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 20 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 21 import static android.view.View.SYSTEM_UI_FLAG_VISIBLE; 22 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; 23 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; 24 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 25 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; 26 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 27 import static android.window.WindowProviderService.isWindowProviderService; 28 29 import android.annotation.CallbackExecutor; 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.annotation.UiContext; 33 import android.app.ResourcesManager; 34 import android.compat.annotation.UnsupportedAppUsage; 35 import android.content.Context; 36 import android.content.res.Configuration; 37 import android.graphics.Rect; 38 import android.graphics.Region; 39 import android.os.Bundle; 40 import android.os.IBinder; 41 import android.os.RemoteException; 42 import android.os.StrictMode; 43 import android.window.WindowContext; 44 import android.window.WindowProvider; 45 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.internal.os.IResultReceiver; 48 49 import java.util.List; 50 import java.util.concurrent.Executor; 51 import java.util.function.Consumer; 52 53 /** 54 * Provides low-level communication with the system window manager for 55 * operations that are bound to a particular context, display or parent window. 56 * Instances of this object are sensitive to the compatibility info associated 57 * with the running application. 58 * 59 * This object implements the {@link ViewManager} interface, 60 * allowing you to add any View subclass as a top-level window on the screen. 61 * Additional window manager specific layout parameters are defined for 62 * control over how windows are displayed. It also implements the {@link WindowManager} 63 * interface, allowing you to control the displays attached to the device. 64 * 65 * <p>Applications will not normally use WindowManager directly, instead relying 66 * on the higher-level facilities in {@link android.app.Activity} and 67 * {@link android.app.Dialog}. 68 * 69 * <p>Even for low-level window manager access, it is almost never correct to use 70 * this class. For example, {@link android.app.Activity#getWindowManager} 71 * provides a window manager for adding windows that are associated with that 72 * activity -- the window manager will not normally allow you to add arbitrary 73 * windows that are not associated with an activity. 74 * 75 * @see WindowManager 76 * @see WindowManagerGlobal 77 * @hide 78 */ 79 public final class WindowManagerImpl implements WindowManager { 80 @UnsupportedAppUsage 81 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); 82 @UiContext 83 @VisibleForTesting 84 public final Context mContext; 85 private final Window mParentWindow; 86 87 /** 88 * If {@link LayoutParams#token} is {@code null} and no parent window is specified, the value 89 * of {@link LayoutParams#token} will be overridden to {@code mDefaultToken}. 90 */ 91 private IBinder mDefaultToken; 92 93 /** 94 * This token will be set to {@link LayoutParams#mWindowContextToken} and used to receive 95 * configuration changes from the server side. 96 */ 97 @Nullable 98 private final IBinder mWindowContextToken; 99 WindowManagerImpl(Context context)100 public WindowManagerImpl(Context context) { 101 this(context, null /* parentWindow */, null /* clientToken */); 102 } 103 WindowManagerImpl(Context context, Window parentWindow, @Nullable IBinder windowContextToken)104 private WindowManagerImpl(Context context, Window parentWindow, 105 @Nullable IBinder windowContextToken) { 106 mContext = context; 107 mParentWindow = parentWindow; 108 mWindowContextToken = windowContextToken; 109 } 110 createLocalWindowManager(Window parentWindow)111 public WindowManagerImpl createLocalWindowManager(Window parentWindow) { 112 return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken); 113 } 114 createPresentationWindowManager(Context displayContext)115 public WindowManagerImpl createPresentationWindowManager(Context displayContext) { 116 return new WindowManagerImpl(displayContext, mParentWindow, mWindowContextToken); 117 } 118 119 /** Creates a {@link WindowManager} for a {@link WindowContext}. */ createWindowContextWindowManager(Context context)120 public static WindowManager createWindowContextWindowManager(Context context) { 121 final IBinder clientToken = context.getWindowContextToken(); 122 return new WindowManagerImpl(context, null /* parentWindow */, clientToken); 123 } 124 125 /** 126 * Sets the window token to assign when none is specified by the client or 127 * available from the parent window. 128 * 129 * @param token The default token to assign. 130 */ setDefaultToken(IBinder token)131 public void setDefaultToken(IBinder token) { 132 mDefaultToken = token; 133 } 134 135 @Override addView(@onNull View view, @NonNull ViewGroup.LayoutParams params)136 public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { 137 applyTokens(params); 138 mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow, 139 mContext.getUserId()); 140 } 141 142 @Override updateViewLayout(@onNull View view, @NonNull ViewGroup.LayoutParams params)143 public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { 144 applyTokens(params); 145 mGlobal.updateViewLayout(view, params); 146 } 147 applyTokens(@onNull ViewGroup.LayoutParams params)148 private void applyTokens(@NonNull ViewGroup.LayoutParams params) { 149 if (!(params instanceof WindowManager.LayoutParams)) { 150 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); 151 } 152 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; 153 assertWindowContextTypeMatches(wparams.type); 154 // Only use the default token if we don't have a parent window and a token. 155 if (mDefaultToken != null && mParentWindow == null && wparams.token == null) { 156 wparams.token = mDefaultToken; 157 } 158 wparams.mWindowContextToken = mWindowContextToken; 159 } 160 assertWindowContextTypeMatches(@ayoutParams.WindowType int windowType)161 private void assertWindowContextTypeMatches(@LayoutParams.WindowType int windowType) { 162 if (!(mContext instanceof WindowProvider)) { 163 return; 164 } 165 // Don't need to check sub-window type because sub window should be allowed to be attached 166 // to the parent window. 167 if (windowType >= FIRST_SUB_WINDOW && windowType <= LAST_SUB_WINDOW) { 168 return; 169 } 170 final WindowProvider windowProvider = (WindowProvider) mContext; 171 if (windowProvider.getWindowType() == windowType) { 172 return; 173 } 174 IllegalArgumentException exception = new IllegalArgumentException("Window type mismatch." 175 + " Window Context's window type is " + windowProvider.getWindowType() 176 + ", while LayoutParams' type is set to " + windowType + "." 177 + " Please create another Window Context via" 178 + " createWindowContext(getDisplay(), " + windowType + ", null)" 179 + " to add window with type:" + windowType); 180 if (!isWindowProviderService(windowProvider.getWindowContextOptions())) { 181 throw exception; 182 } 183 // Throw IncorrectCorrectViolation if the Window Context is allowed to provide multiple 184 // window types. Usually it's because the Window Context is a WindowProviderService. 185 StrictMode.onIncorrectContextUsed("WindowContext's window type must" 186 + " match type in WindowManager.LayoutParams", exception); 187 } 188 189 @Override removeView(View view)190 public void removeView(View view) { 191 mGlobal.removeView(view, false); 192 } 193 194 @Override removeViewImmediate(View view)195 public void removeViewImmediate(View view) { 196 mGlobal.removeView(view, true); 197 } 198 199 @Override requestAppKeyboardShortcuts( final KeyboardShortcutsReceiver receiver, int deviceId)200 public void requestAppKeyboardShortcuts( 201 final KeyboardShortcutsReceiver receiver, int deviceId) { 202 IResultReceiver resultReceiver = new IResultReceiver.Stub() { 203 @Override 204 public void send(int resultCode, Bundle resultData) throws RemoteException { 205 List<KeyboardShortcutGroup> result = 206 resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY); 207 receiver.onKeyboardShortcutsReceived(result); 208 } 209 }; 210 try { 211 WindowManagerGlobal.getWindowManagerService() 212 .requestAppKeyboardShortcuts(resultReceiver, deviceId); 213 } catch (RemoteException e) { 214 } 215 } 216 217 @Override getDefaultDisplay()218 public Display getDefaultDisplay() { 219 return mContext.getDisplayNoVerify(); 220 } 221 222 @Override getCurrentImeTouchRegion()223 public Region getCurrentImeTouchRegion() { 224 try { 225 return WindowManagerGlobal.getWindowManagerService().getCurrentImeTouchRegion(); 226 } catch (RemoteException e) { 227 } 228 return null; 229 } 230 231 @Override setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow)232 public void setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow) { 233 try { 234 WindowManagerGlobal.getWindowManagerService() 235 .setShouldShowWithInsecureKeyguard(displayId, shouldShow); 236 } catch (RemoteException e) { 237 } 238 } 239 240 @Override setShouldShowSystemDecors(int displayId, boolean shouldShow)241 public void setShouldShowSystemDecors(int displayId, boolean shouldShow) { 242 try { 243 WindowManagerGlobal.getWindowManagerService() 244 .setShouldShowSystemDecors(displayId, shouldShow); 245 } catch (RemoteException e) { 246 } 247 } 248 249 @Override shouldShowSystemDecors(int displayId)250 public boolean shouldShowSystemDecors(int displayId) { 251 try { 252 return WindowManagerGlobal.getWindowManagerService().shouldShowSystemDecors(displayId); 253 } catch (RemoteException e) { 254 } 255 return false; 256 } 257 258 @Override setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy)259 public void setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy) { 260 try { 261 WindowManagerGlobal.getWindowManagerService().setDisplayImePolicy(displayId, imePolicy); 262 } catch (RemoteException e) { 263 } 264 } 265 266 @Override getDisplayImePolicy(int displayId)267 public @DisplayImePolicy int getDisplayImePolicy(int displayId) { 268 try { 269 return WindowManagerGlobal.getWindowManagerService().getDisplayImePolicy(displayId); 270 } catch (RemoteException e) { 271 } 272 return DISPLAY_IME_POLICY_FALLBACK_DISPLAY; 273 } 274 275 @Override getCurrentWindowMetrics()276 public WindowMetrics getCurrentWindowMetrics() { 277 final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext; 278 final Rect bounds = getCurrentBounds(context); 279 280 return new WindowMetrics(bounds, computeWindowInsets(bounds)); 281 } 282 getCurrentBounds(Context context)283 private static Rect getCurrentBounds(Context context) { 284 synchronized (ResourcesManager.getInstance()) { 285 return context.getResources().getConfiguration().windowConfiguration.getBounds(); 286 } 287 } 288 289 @Override getMaximumWindowMetrics()290 public WindowMetrics getMaximumWindowMetrics() { 291 final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext; 292 final Rect maxBounds = getMaximumBounds(context); 293 294 return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds)); 295 } 296 getMaximumBounds(Context context)297 private static Rect getMaximumBounds(Context context) { 298 synchronized (ResourcesManager.getInstance()) { 299 return context.getResources().getConfiguration().windowConfiguration.getMaxBounds(); 300 } 301 } 302 303 // TODO(b/150095967): Set window type to LayoutParams computeWindowInsets(Rect bounds)304 private WindowInsets computeWindowInsets(Rect bounds) { 305 // Initialize params which used for obtaining all system insets. 306 final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 307 params.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; 308 final Context context = (mParentWindow != null) ? mParentWindow.getContext() : mContext; 309 params.token = Context.getToken(context); 310 params.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 311 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 312 params.setFitInsetsTypes(0); 313 params.setFitInsetsSides(0); 314 315 return getWindowInsetsFromServer(params, bounds); 316 } 317 getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds)318 private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds) { 319 try { 320 final InsetsState insetsState = new InsetsState(); 321 final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService() 322 .getWindowInsets(attrs, mContext.getDisplayId(), insetsState); 323 final Configuration config = mContext.getResources().getConfiguration(); 324 final boolean isScreenRound = config.isScreenRound(); 325 final int windowingMode = config.windowConfiguration.getWindowingMode(); 326 return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/, 327 isScreenRound, alwaysConsumeSystemBars, SOFT_INPUT_ADJUST_NOTHING, attrs.flags, 328 SYSTEM_UI_FLAG_VISIBLE, attrs.type, windowingMode, null /* typeSideMap */); 329 } catch (RemoteException e) { 330 throw e.rethrowFromSystemServer(); 331 } 332 } 333 334 @Override holdLock(IBinder token, int durationMs)335 public void holdLock(IBinder token, int durationMs) { 336 try { 337 WindowManagerGlobal.getWindowManagerService().holdLock(token, durationMs); 338 } catch (RemoteException e) { 339 throw e.rethrowFromSystemServer(); 340 } 341 } 342 343 @Override isCrossWindowBlurEnabled()344 public boolean isCrossWindowBlurEnabled() { 345 return CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled(); 346 } 347 348 @Override addCrossWindowBlurEnabledListener(@onNull Consumer<Boolean> listener)349 public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { 350 addCrossWindowBlurEnabledListener(mContext.getMainExecutor(), listener); 351 } 352 353 @Override addCrossWindowBlurEnabledListener(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> listener)354 public void addCrossWindowBlurEnabledListener(@NonNull @CallbackExecutor Executor executor, 355 @NonNull Consumer<Boolean> listener) { 356 CrossWindowBlurListeners.getInstance().addListener(executor, listener); 357 } 358 359 @Override removeCrossWindowBlurEnabledListener(@onNull Consumer<Boolean> listener)360 public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { 361 CrossWindowBlurListeners.getInstance().removeListener(listener); 362 } 363 364 @Override isTaskSnapshotSupported()365 public boolean isTaskSnapshotSupported() { 366 try { 367 return WindowManagerGlobal.getWindowManagerService().isTaskSnapshotSupported(); 368 } catch (RemoteException e) { 369 } 370 return false; 371 } 372 } 373