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