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