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.WindowManager.LayoutParams.FIRST_SUB_WINDOW; 20 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; 21 import static android.window.WindowProviderService.isWindowProviderService; 22 23 import android.annotation.CallbackExecutor; 24 import android.annotation.IntRange; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.UiContext; 28 import android.compat.annotation.UnsupportedAppUsage; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.graphics.Bitmap; 32 import android.graphics.Region; 33 import android.os.Bundle; 34 import android.os.IBinder; 35 import android.os.RemoteException; 36 import android.os.StrictMode; 37 import android.window.ITaskFpsCallback; 38 import android.window.TaskFpsCallback; 39 import android.window.WindowContext; 40 import android.window.WindowMetricsController; 41 import android.window.WindowProvider; 42 43 import com.android.internal.annotations.GuardedBy; 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.internal.os.IResultReceiver; 46 47 import java.util.ArrayList; 48 import java.util.Iterator; 49 import java.util.List; 50 import java.util.Objects; 51 import java.util.Set; 52 import java.util.concurrent.Executor; 53 import java.util.function.Consumer; 54 import java.util.function.IntConsumer; 55 56 /** 57 * Provides low-level communication with the system window manager for 58 * operations that are bound to a particular context, display or parent window. 59 * Instances of this object are sensitive to the compatibility info associated 60 * with the running application. 61 * 62 * This object implements the {@link ViewManager} interface, 63 * allowing you to add any View subclass as a top-level window on the screen. 64 * Additional window manager specific layout parameters are defined for 65 * control over how windows are displayed. It also implements the {@link WindowManager} 66 * interface, allowing you to control the displays attached to the device. 67 * 68 * <p>Applications will not normally use WindowManager directly, instead relying 69 * on the higher-level facilities in {@link android.app.Activity} and 70 * {@link android.app.Dialog}. 71 * 72 * <p>Even for low-level window manager access, it is almost never correct to use 73 * this class. For example, {@link android.app.Activity#getWindowManager} 74 * provides a window manager for adding windows that are associated with that 75 * activity -- the window manager will not normally allow you to add arbitrary 76 * windows that are not associated with an activity. 77 * 78 * @see WindowManager 79 * @see WindowManagerGlobal 80 * @hide 81 */ 82 public final class WindowManagerImpl implements WindowManager { 83 @UnsupportedAppUsage 84 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); 85 @UiContext 86 @VisibleForTesting 87 public final Context mContext; 88 private final Window mParentWindow; 89 90 /** 91 * If {@link LayoutParams#token} is {@code null} and no parent window is specified, the value 92 * of {@link LayoutParams#token} will be overridden to {@code mDefaultToken}. 93 */ 94 private IBinder mDefaultToken; 95 96 /** 97 * This token will be set to {@link LayoutParams#mWindowContextToken} and used to receive 98 * configuration changes from the server side. 99 */ 100 @Nullable 101 private final IBinder mWindowContextToken; 102 103 @GuardedBy("mOnFpsCallbackListenerProxies") 104 private final ArrayList<OnFpsCallbackListenerProxy> mOnFpsCallbackListenerProxies = 105 new ArrayList<>(); 106 107 /** A controller to handle {@link WindowMetrics} related APIs */ 108 @NonNull 109 private final WindowMetricsController mWindowMetricsController; 110 WindowManagerImpl(Context context)111 public WindowManagerImpl(Context context) { 112 this(context, null /* parentWindow */, null /* clientToken */); 113 } 114 WindowManagerImpl(Context context, Window parentWindow, @Nullable IBinder windowContextToken)115 private WindowManagerImpl(Context context, Window parentWindow, 116 @Nullable IBinder windowContextToken) { 117 mContext = context; 118 mParentWindow = parentWindow; 119 mWindowContextToken = windowContextToken; 120 mWindowMetricsController = new WindowMetricsController(mContext); 121 } 122 createLocalWindowManager(Window parentWindow)123 public WindowManagerImpl createLocalWindowManager(Window parentWindow) { 124 return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken); 125 } 126 createPresentationWindowManager(Context displayContext)127 public WindowManagerImpl createPresentationWindowManager(Context displayContext) { 128 return new WindowManagerImpl(displayContext, mParentWindow, mWindowContextToken); 129 } 130 131 /** Creates a {@link WindowManager} for a {@link WindowContext}. */ createWindowContextWindowManager(Context context)132 public static WindowManager createWindowContextWindowManager(Context context) { 133 final IBinder clientToken = context.getWindowContextToken(); 134 return new WindowManagerImpl(context, null /* parentWindow */, clientToken); 135 } 136 137 /** 138 * Sets the window token to assign when none is specified by the client or 139 * available from the parent window. 140 * 141 * @param token The default token to assign. 142 */ setDefaultToken(IBinder token)143 public void setDefaultToken(IBinder token) { 144 mDefaultToken = token; 145 } 146 147 @Override addView(@onNull View view, @NonNull ViewGroup.LayoutParams params)148 public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { 149 applyTokens(params); 150 mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow, 151 mContext.getUserId()); 152 } 153 154 @Override updateViewLayout(@onNull View view, @NonNull ViewGroup.LayoutParams params)155 public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { 156 applyTokens(params); 157 mGlobal.updateViewLayout(view, params); 158 } 159 applyTokens(@onNull ViewGroup.LayoutParams params)160 private void applyTokens(@NonNull ViewGroup.LayoutParams params) { 161 if (!(params instanceof WindowManager.LayoutParams)) { 162 throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); 163 } 164 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; 165 assertWindowContextTypeMatches(wparams.type); 166 // Only use the default token if we don't have a parent window and a token. 167 if (mDefaultToken != null && mParentWindow == null && wparams.token == null) { 168 wparams.token = mDefaultToken; 169 } 170 wparams.mWindowContextToken = mWindowContextToken; 171 } 172 assertWindowContextTypeMatches(@ayoutParams.WindowType int windowType)173 private void assertWindowContextTypeMatches(@LayoutParams.WindowType int windowType) { 174 if (!(mContext instanceof WindowProvider)) { 175 return; 176 } 177 // Don't need to check sub-window type because sub window should be allowed to be attached 178 // to the parent window. 179 if (windowType >= FIRST_SUB_WINDOW && windowType <= LAST_SUB_WINDOW) { 180 return; 181 } 182 final WindowProvider windowProvider = (WindowProvider) mContext; 183 if (windowProvider.getWindowType() == windowType) { 184 return; 185 } 186 IllegalArgumentException exception = new IllegalArgumentException("Window type mismatch." 187 + " Window Context's window type is " + windowProvider.getWindowType() 188 + ", while LayoutParams' type is set to " + windowType + "." 189 + " Please create another Window Context via" 190 + " createWindowContext(getDisplay(), " + windowType + ", null)" 191 + " to add window with type:" + windowType); 192 if (!isWindowProviderService(windowProvider.getWindowContextOptions())) { 193 throw exception; 194 } 195 // Throw IncorrectCorrectViolation if the Window Context is allowed to provide multiple 196 // window types. Usually it's because the Window Context is a WindowProviderService. 197 StrictMode.onIncorrectContextUsed("WindowContext's window type must" 198 + " match type in WindowManager.LayoutParams", exception); 199 } 200 201 @Override removeView(View view)202 public void removeView(View view) { 203 mGlobal.removeView(view, false); 204 } 205 206 @Override removeViewImmediate(View view)207 public void removeViewImmediate(View view) { 208 mGlobal.removeView(view, true); 209 } 210 211 @Override requestAppKeyboardShortcuts( final KeyboardShortcutsReceiver receiver, int deviceId)212 public void requestAppKeyboardShortcuts( 213 final KeyboardShortcutsReceiver receiver, int deviceId) { 214 IResultReceiver resultReceiver = new IResultReceiver.Stub() { 215 @Override 216 public void send(int resultCode, Bundle resultData) throws RemoteException { 217 List<KeyboardShortcutGroup> result = 218 resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY, 219 android.view.KeyboardShortcutGroup.class); 220 receiver.onKeyboardShortcutsReceived(result); 221 } 222 }; 223 try { 224 WindowManagerGlobal.getWindowManagerService() 225 .requestAppKeyboardShortcuts(resultReceiver, deviceId); 226 } catch (RemoteException e) { 227 throw e.rethrowFromSystemServer(); 228 } 229 } 230 231 @Override requestImeKeyboardShortcuts( final KeyboardShortcutsReceiver receiver, int deviceId)232 public void requestImeKeyboardShortcuts( 233 final KeyboardShortcutsReceiver receiver, int deviceId) { 234 IResultReceiver resultReceiver = new IResultReceiver.Stub() { 235 @Override 236 public void send(int resultCode, Bundle resultData) throws RemoteException { 237 List<KeyboardShortcutGroup> result = 238 resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY, 239 android.view.KeyboardShortcutGroup.class); 240 receiver.onKeyboardShortcutsReceived(result); 241 } 242 }; 243 try { 244 WindowManagerGlobal.getWindowManagerService() 245 .requestImeKeyboardShortcuts(resultReceiver, deviceId); 246 } catch (RemoteException e) { 247 throw e.rethrowFromSystemServer(); 248 } 249 } 250 251 @Override getDefaultDisplay()252 public Display getDefaultDisplay() { 253 return mContext.getDisplayNoVerify(); 254 } 255 256 @Override getCurrentImeTouchRegion()257 public Region getCurrentImeTouchRegion() { 258 try { 259 return WindowManagerGlobal.getWindowManagerService().getCurrentImeTouchRegion(); 260 } catch (RemoteException e) { 261 } 262 return null; 263 } 264 265 @Override setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow)266 public void setShouldShowWithInsecureKeyguard(int displayId, boolean shouldShow) { 267 try { 268 WindowManagerGlobal.getWindowManagerService() 269 .setShouldShowWithInsecureKeyguard(displayId, shouldShow); 270 } catch (RemoteException e) { 271 } 272 } 273 274 @Override setShouldShowSystemDecors(int displayId, boolean shouldShow)275 public void setShouldShowSystemDecors(int displayId, boolean shouldShow) { 276 try { 277 WindowManagerGlobal.getWindowManagerService() 278 .setShouldShowSystemDecors(displayId, shouldShow); 279 } catch (RemoteException e) { 280 } 281 } 282 283 @Override shouldShowSystemDecors(int displayId)284 public boolean shouldShowSystemDecors(int displayId) { 285 try { 286 return WindowManagerGlobal.getWindowManagerService().shouldShowSystemDecors(displayId); 287 } catch (RemoteException e) { 288 } 289 return false; 290 } 291 292 @Override setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy)293 public void setDisplayImePolicy(int displayId, @DisplayImePolicy int imePolicy) { 294 try { 295 WindowManagerGlobal.getWindowManagerService().setDisplayImePolicy(displayId, imePolicy); 296 } catch (RemoteException e) { 297 } 298 } 299 300 @Override getDisplayImePolicy(int displayId)301 public @DisplayImePolicy int getDisplayImePolicy(int displayId) { 302 try { 303 return WindowManagerGlobal.getWindowManagerService().getDisplayImePolicy(displayId); 304 } catch (RemoteException e) { 305 } 306 return DISPLAY_IME_POLICY_FALLBACK_DISPLAY; 307 } 308 309 @Override isGlobalKey(int keyCode)310 public boolean isGlobalKey(int keyCode) { 311 try { 312 return WindowManagerGlobal.getWindowManagerService().isGlobalKey(keyCode); 313 } catch (RemoteException e) { 314 } 315 return false; 316 } 317 318 @Override getCurrentWindowMetrics()319 public WindowMetrics getCurrentWindowMetrics() { 320 return mWindowMetricsController.getCurrentWindowMetrics(); 321 } 322 323 @Override getMaximumWindowMetrics()324 public WindowMetrics getMaximumWindowMetrics() { 325 return mWindowMetricsController.getMaximumWindowMetrics(); 326 } 327 328 @Override 329 @NonNull getPossibleMaximumWindowMetrics(int displayId)330 public Set<WindowMetrics> getPossibleMaximumWindowMetrics(int displayId) { 331 return mWindowMetricsController.getPossibleMaximumWindowMetrics(displayId); 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 addProposedRotationListener(@onNull @allbackExecutor Executor executor, @NonNull IntConsumer listener)365 public void addProposedRotationListener(@NonNull @CallbackExecutor Executor executor, 366 @NonNull IntConsumer listener) { 367 Objects.requireNonNull(executor, "executor must not be null"); 368 Objects.requireNonNull(listener, "listener must not be null"); 369 final IBinder contextToken = Context.getToken(mContext); 370 if (contextToken == null) { 371 throw new UnsupportedOperationException("The context of this window manager instance " 372 + "must be a UI context, e.g. an Activity or a Context created by " 373 + "Context#createWindowContext()"); 374 } 375 mGlobal.registerProposedRotationListener(contextToken, executor, listener); 376 } 377 378 @Override removeProposedRotationListener(@onNull IntConsumer listener)379 public void removeProposedRotationListener(@NonNull IntConsumer listener) { 380 mGlobal.unregisterProposedRotationListener(Context.getToken(mContext), listener); 381 } 382 383 @Override isTaskSnapshotSupported()384 public boolean isTaskSnapshotSupported() { 385 try { 386 return WindowManagerGlobal.getWindowManagerService().isTaskSnapshotSupported(); 387 } catch (RemoteException e) { 388 } 389 return false; 390 } 391 392 @Override registerTaskFpsCallback(@ntRangefrom = 0) int taskId, @NonNull Executor executor, TaskFpsCallback callback)393 public void registerTaskFpsCallback(@IntRange(from = 0) int taskId, @NonNull Executor executor, 394 TaskFpsCallback callback) { 395 final OnFpsCallbackListenerProxy onFpsCallbackListenerProxy = 396 new OnFpsCallbackListenerProxy(executor, callback); 397 try { 398 WindowManagerGlobal.getWindowManagerService().registerTaskFpsCallback( 399 taskId, onFpsCallbackListenerProxy); 400 } catch (RemoteException e) { 401 throw e.rethrowFromSystemServer(); 402 } 403 synchronized (mOnFpsCallbackListenerProxies) { 404 mOnFpsCallbackListenerProxies.add(onFpsCallbackListenerProxy); 405 } 406 } 407 408 @Override unregisterTaskFpsCallback(TaskFpsCallback callback)409 public void unregisterTaskFpsCallback(TaskFpsCallback callback) { 410 synchronized (mOnFpsCallbackListenerProxies) { 411 final Iterator<OnFpsCallbackListenerProxy> iterator = 412 mOnFpsCallbackListenerProxies.iterator(); 413 while (iterator.hasNext()) { 414 final OnFpsCallbackListenerProxy proxy = iterator.next(); 415 if (proxy.mCallback == callback) { 416 try { 417 WindowManagerGlobal.getWindowManagerService() 418 .unregisterTaskFpsCallback(proxy); 419 } catch (RemoteException e) { 420 throw e.rethrowFromSystemServer(); 421 } 422 iterator.remove(); 423 } 424 } 425 } 426 } 427 428 private static class OnFpsCallbackListenerProxy 429 extends ITaskFpsCallback.Stub { 430 private final Executor mExecutor; 431 private final TaskFpsCallback mCallback; 432 OnFpsCallbackListenerProxy(Executor executor, TaskFpsCallback callback)433 private OnFpsCallbackListenerProxy(Executor executor, TaskFpsCallback callback) { 434 mExecutor = executor; 435 mCallback = callback; 436 } 437 438 @Override onFpsReported(float fps)439 public void onFpsReported(float fps) { 440 mExecutor.execute(() -> { 441 mCallback.onFpsReported(fps); 442 }); 443 } 444 } 445 446 @Override snapshotTaskForRecents(int taskId)447 public Bitmap snapshotTaskForRecents(int taskId) { 448 try { 449 return WindowManagerGlobal.getWindowManagerService().snapshotTaskForRecents(taskId); 450 } catch (RemoteException e) { 451 e.rethrowAsRuntimeException(); 452 } 453 return null; 454 } 455 getDefaultToken()456 IBinder getDefaultToken() { 457 return mDefaultToken; 458 } 459 460 @Override 461 @NonNull notifyScreenshotListeners(int displayId)462 public List<ComponentName> notifyScreenshotListeners(int displayId) { 463 try { 464 return List.copyOf(WindowManagerGlobal.getWindowManagerService() 465 .notifyScreenshotListeners(displayId)); 466 } catch (RemoteException e) { 467 throw e.rethrowFromSystemServer(); 468 } 469 } 470 } 471