1 /* 2 * Copyright (C) 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 com.android.server.wm; 18 19 import static com.android.server.wm.WindowFramesProto.CONTAINING_FRAME; 20 import static com.android.server.wm.WindowFramesProto.CONTENT_FRAME; 21 import static com.android.server.wm.WindowFramesProto.CONTENT_INSETS; 22 import static com.android.server.wm.WindowFramesProto.CUTOUT; 23 import static com.android.server.wm.WindowFramesProto.DECOR_FRAME; 24 import static com.android.server.wm.WindowFramesProto.DISPLAY_FRAME; 25 import static com.android.server.wm.WindowFramesProto.FRAME; 26 import static com.android.server.wm.WindowFramesProto.OUTSETS; 27 import static com.android.server.wm.WindowFramesProto.OUTSET_FRAME; 28 import static com.android.server.wm.WindowFramesProto.OVERSCAN_FRAME; 29 import static com.android.server.wm.WindowFramesProto.OVERSCAN_INSETS; 30 import static com.android.server.wm.WindowFramesProto.PARENT_FRAME; 31 import static com.android.server.wm.WindowFramesProto.STABLE_INSETS; 32 import static com.android.server.wm.WindowFramesProto.VISIBLE_FRAME; 33 import static com.android.server.wm.WindowFramesProto.VISIBLE_INSETS; 34 35 import android.annotation.NonNull; 36 import android.graphics.Rect; 37 import android.util.proto.ProtoOutputStream; 38 import android.view.DisplayCutout; 39 40 import com.android.server.wm.utils.InsetUtils; 41 import com.android.server.wm.utils.WmDisplayCutout; 42 43 import java.io.PrintWriter; 44 45 /** 46 * Container class for all the window frames that affect how windows are laid out. 47 * 48 * TODO(b/111611553): Investigate which frames are still needed and which are duplicates 49 */ 50 public class WindowFrames { 51 private static final StringBuilder sTmpSB = new StringBuilder(); 52 53 /** 54 * In most cases, this is the area of the entire screen. 55 * 56 * TODO(b/111611553): The name is unclear and most likely should be swapped with 57 * {@link #mDisplayFrame} 58 * TODO(b/111611553): In some cases, it also includes top insets, like for IME. Determine 59 * whether this is still necessary to do. 60 */ 61 public final Rect mParentFrame = new Rect(); 62 63 /** 64 * The entire screen area of the {@link TaskStack} this window is in. Usually equal to the 65 * screen area of the device. 66 * 67 * TODO(b/111611553): The name is unclear and most likely should be swapped with 68 * {@link #mParentFrame} 69 */ 70 public final Rect mDisplayFrame = new Rect(); 71 72 /** 73 * The region of the display frame that the display type supports displaying content on. This 74 * is mostly a special case for TV where some displays don’t have the entire display usable. 75 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to 76 * allow window display contents to extend into the overscan region. 77 */ 78 public final Rect mOverscanFrame = new Rect(); 79 80 /** 81 * Legacy stuff. Generally equal to the content frame expect when the IME for older apps 82 * displays hint text. 83 */ 84 public final Rect mVisibleFrame = new Rect(); 85 86 /** 87 * The area not occupied by the status and navigation bars. So, if both status and navigation 88 * bars are visible, the decor frame is equal to the stable frame. 89 */ 90 public final Rect mDecorFrame = new Rect(); 91 92 /** 93 * Equal to the decor frame if the IME (e.g. keyboard) is not present. Equal to the decor frame 94 * minus the area occupied by the IME if the IME is present. 95 */ 96 public final Rect mContentFrame = new Rect(); 97 98 /** 99 * The display frame minus the stable insets. This value is always constant regardless of if 100 * the status bar or navigation bar is visible. 101 */ 102 public final Rect mStableFrame = new Rect(); 103 104 /** 105 * Frame that includes dead area outside of the surface but where we want to pretend that it's 106 * possible to draw. 107 */ 108 final public Rect mOutsetFrame = new Rect(); 109 110 /** 111 * Similar to {@link #mDisplayFrame} 112 * 113 * TODO: Why is this different than mDisplayFrame 114 */ 115 final Rect mContainingFrame = new Rect(); 116 117 /** 118 * "Real" frame that the application sees, in display coordinate space. 119 */ 120 final Rect mFrame = new Rect(); 121 122 /** 123 * The last real frame that was reported to the client. 124 */ 125 final Rect mLastFrame = new Rect(); 126 127 private boolean mFrameSizeChanged = false; 128 129 // Frame that is scaled to the application's coordinate space when in 130 // screen size compatibility mode. 131 final Rect mCompatFrame = new Rect(); 132 133 /** 134 * Whether the parent frame would have been different if there was no display cutout. 135 */ 136 private boolean mParentFrameWasClippedByDisplayCutout; 137 138 /** 139 * Part of the display that has been cut away. See {@link DisplayCutout}. 140 */ 141 WmDisplayCutout mDisplayCutout = WmDisplayCutout.NO_CUTOUT; 142 143 /** 144 * The last cutout that has been reported to the client. 145 */ 146 private WmDisplayCutout mLastDisplayCutout = WmDisplayCutout.NO_CUTOUT; 147 148 private boolean mDisplayCutoutChanged; 149 150 /** 151 * Insets that determine the area covered by the display overscan region. These are in the 152 * application's coordinate space (without compatibility scale applied). 153 */ 154 final Rect mOverscanInsets = new Rect(); 155 final Rect mLastOverscanInsets = new Rect(); 156 private boolean mOverscanInsetsChanged; 157 158 /** 159 * Insets that determine the area covered by the stable system windows. These are in the 160 * application's coordinate space (without compatibility scale applied). 161 */ 162 final Rect mStableInsets = new Rect(); 163 final Rect mLastStableInsets = new Rect(); 164 private boolean mStableInsetsChanged; 165 166 /** 167 * Outsets determine the area outside of the surface where we want to pretend that it's possible 168 * to draw anyway. 169 */ 170 final Rect mOutsets = new Rect(); 171 final Rect mLastOutsets = new Rect(); 172 private boolean mOutsetsChanged = false; 173 174 /** 175 * Insets that determine the actually visible area. These are in the application's 176 * coordinate space (without compatibility scale applied). 177 */ 178 final Rect mVisibleInsets = new Rect(); 179 final Rect mLastVisibleInsets = new Rect(); 180 private boolean mVisibleInsetsChanged; 181 182 /** 183 * Insets that are covered by system windows (such as the status bar) and 184 * transient docking windows (such as the IME). These are in the application's 185 * coordinate space (without compatibility scale applied). 186 */ 187 final Rect mContentInsets = new Rect(); 188 final Rect mLastContentInsets = new Rect(); 189 private boolean mContentInsetsChanged; 190 191 private final Rect mTmpRect = new Rect(); 192 193 private boolean mHasOutsets; 194 195 private boolean mContentChanged; 196 WindowFrames()197 public WindowFrames() { 198 } 199 WindowFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame)200 public WindowFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame, 201 Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame) { 202 setFrames(parentFrame, displayFrame, overscanFrame, contentFrame, visibleFrame, decorFrame, 203 stableFrame, outsetFrame); 204 } 205 setFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame)206 public void setFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame, 207 Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, 208 Rect outsetFrame) { 209 mParentFrame.set(parentFrame); 210 mDisplayFrame.set(displayFrame); 211 mOverscanFrame.set(overscanFrame); 212 mContentFrame.set(contentFrame); 213 mVisibleFrame.set(visibleFrame); 214 mDecorFrame.set(decorFrame); 215 mStableFrame.set(stableFrame); 216 mOutsetFrame.set(outsetFrame); 217 } 218 setParentFrameWasClippedByDisplayCutout( boolean parentFrameWasClippedByDisplayCutout)219 public void setParentFrameWasClippedByDisplayCutout( 220 boolean parentFrameWasClippedByDisplayCutout) { 221 mParentFrameWasClippedByDisplayCutout = parentFrameWasClippedByDisplayCutout; 222 } 223 parentFrameWasClippedByDisplayCutout()224 boolean parentFrameWasClippedByDisplayCutout() { 225 return mParentFrameWasClippedByDisplayCutout; 226 } 227 setDisplayCutout(WmDisplayCutout displayCutout)228 public void setDisplayCutout(WmDisplayCutout displayCutout) { 229 mDisplayCutout = displayCutout; 230 } 231 232 /** 233 * @return true if the width or height has changed since last reported to the client. 234 */ didFrameSizeChange()235 private boolean didFrameSizeChange() { 236 return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height()); 237 } 238 239 /** 240 * Calculates the outsets for this windowFrame. The outsets are calculated by the area between 241 * the {@link #mOutsetFrame} and the {@link #mContentFrame}. If there are no outsets, then 242 * {@link #mOutsets} is set to empty. 243 */ calculateOutsets()244 void calculateOutsets() { 245 if (mHasOutsets) { 246 InsetUtils.insetsBetweenFrames(mOutsetFrame, mContentFrame, mOutsets); 247 } 248 } 249 250 /** 251 * Calculate the insets for the type 252 * {@link android.view.WindowManager.LayoutParams#TYPE_DOCK_DIVIDER} 253 * 254 * @param cutoutInsets The insets for the cutout. 255 */ calculateDockedDividerInsets(Rect cutoutInsets)256 void calculateDockedDividerInsets(Rect cutoutInsets) { 257 // For the docked divider, we calculate the stable insets like a full-screen window 258 // so it can use it to calculate the snap positions. 259 mTmpRect.set(mDisplayFrame); 260 mTmpRect.inset(cutoutInsets); 261 mTmpRect.intersectUnchecked(mStableFrame); 262 InsetUtils.insetsBetweenFrames(mDisplayFrame, mTmpRect, mStableInsets); 263 264 // The divider doesn't care about insets in any case, so set it to empty so we don't 265 // trigger a relayout when moving it. 266 mContentInsets.setEmpty(); 267 mVisibleInsets.setEmpty(); 268 mDisplayCutout = WmDisplayCutout.NO_CUTOUT; 269 } 270 271 /** 272 * Calculate the insets for a window. 273 * 274 * @param windowsAreFloating Whether the window is in a floating task such as pinned or 275 * freeform 276 * @param inFullscreenContainer Whether the window is in a container that takes up the screen's 277 * entire space 278 * @param windowBounds The bounds for the window 279 */ calculateInsets(boolean windowsAreFloating, boolean inFullscreenContainer, Rect windowBounds)280 void calculateInsets(boolean windowsAreFloating, boolean inFullscreenContainer, 281 Rect windowBounds) { 282 // Override right and/or bottom insets in case if the frame doesn't fit the screen in 283 // non-fullscreen mode. 284 boolean overrideRightInset = !windowsAreFloating && !inFullscreenContainer 285 && mFrame.right > windowBounds.right; 286 boolean overrideBottomInset = !windowsAreFloating && !inFullscreenContainer 287 && mFrame.bottom > windowBounds.bottom; 288 289 mTmpRect.set(mFrame.left, mFrame.top, 290 overrideRightInset ? windowBounds.right : mFrame.right, 291 overrideBottomInset ? windowBounds.bottom : mFrame.bottom); 292 293 InsetUtils.insetsBetweenFrames(mTmpRect, mContentFrame, mContentInsets); 294 InsetUtils.insetsBetweenFrames(mTmpRect, mVisibleFrame, mVisibleInsets); 295 InsetUtils.insetsBetweenFrames(mTmpRect, mStableFrame, mStableInsets); 296 } 297 298 /** 299 * Scales all the insets by a specific amount. 300 * 301 * @param scale The amount to scale the insets by. 302 */ scaleInsets(float scale)303 void scaleInsets(float scale) { 304 mOverscanInsets.scale(scale); 305 mContentInsets.scale(scale); 306 mVisibleInsets.scale(scale); 307 mStableInsets.scale(scale); 308 mOutsets.scale(scale); 309 } 310 offsetFrames(int layoutXDiff, int layoutYDiff)311 void offsetFrames(int layoutXDiff, int layoutYDiff) { 312 mFrame.offset(layoutXDiff, layoutYDiff); 313 mContentFrame.offset(layoutXDiff, layoutYDiff); 314 mVisibleFrame.offset(layoutXDiff, layoutYDiff); 315 mStableFrame.offset(layoutXDiff, layoutYDiff); 316 } 317 318 /** 319 * Updates info about whether the size of the window has changed since last reported. 320 * 321 * @return true if info about size has changed since last reported. 322 */ setReportResizeHints()323 boolean setReportResizeHints() { 324 mOverscanInsetsChanged |= !mLastOverscanInsets.equals(mOverscanInsets); 325 mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets); 326 mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets); 327 mStableInsetsChanged |= !mLastStableInsets.equals(mStableInsets); 328 mOutsetsChanged |= !mLastOutsets.equals(mOutsets); 329 mFrameSizeChanged |= didFrameSizeChange(); 330 mDisplayCutoutChanged |= !mLastDisplayCutout.equals(mDisplayCutout); 331 return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged 332 || mStableInsetsChanged || mOutsetsChanged || mFrameSizeChanged 333 || mDisplayCutoutChanged; 334 } 335 336 /** 337 * Resets the insets changed flags so they're all set to false again. This should be called 338 * after the insets are reported to client. 339 */ resetInsetsChanged()340 void resetInsetsChanged() { 341 mOverscanInsetsChanged = false; 342 mContentInsetsChanged = false; 343 mVisibleInsetsChanged = false; 344 mStableInsetsChanged = false; 345 mOutsetsChanged = false; 346 mFrameSizeChanged = false; 347 mDisplayCutoutChanged = false; 348 } 349 350 /** 351 * Copy over inset values as the last insets that were sent to the client. 352 */ updateLastInsetValues()353 void updateLastInsetValues() { 354 mLastOverscanInsets.set(mOverscanInsets); 355 mLastContentInsets.set(mContentInsets); 356 mLastVisibleInsets.set(mVisibleInsets); 357 mLastStableInsets.set(mStableInsets); 358 mLastOutsets.set(mOutsets); 359 mLastDisplayCutout = mDisplayCutout; 360 } 361 362 /** 363 * Sets the last content insets as (-1, -1, -1, -1) to force the next layout pass to update 364 * the client. 365 */ resetLastContentInsets()366 void resetLastContentInsets() { 367 mLastContentInsets.set(-1, -1, -1, -1); 368 } 369 370 /** 371 * Sets whether the frame has outsets. 372 */ setHasOutsets(boolean hasOutsets)373 public void setHasOutsets(boolean hasOutsets) { 374 if (mHasOutsets == hasOutsets) { 375 return; 376 } 377 mHasOutsets = hasOutsets; 378 if (!hasOutsets) { 379 mOutsets.setEmpty(); 380 } 381 } 382 383 /** 384 * Sets whether the content has changed. This means that either the size or parent frame has 385 * changed. 386 */ setContentChanged(boolean contentChanged)387 public void setContentChanged(boolean contentChanged) { 388 mContentChanged = contentChanged; 389 } 390 391 /** 392 * @see #setContentChanged(boolean) 393 */ hasContentChanged()394 boolean hasContentChanged() { 395 return mContentChanged; 396 } 397 writeToProto(@onNull ProtoOutputStream proto, long fieldId)398 public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) { 399 final long token = proto.start(fieldId); 400 mParentFrame.writeToProto(proto, PARENT_FRAME); 401 mContentFrame.writeToProto(proto, CONTENT_FRAME); 402 mDisplayFrame.writeToProto(proto, DISPLAY_FRAME); 403 mOverscanFrame.writeToProto(proto, OVERSCAN_FRAME); 404 mVisibleFrame.writeToProto(proto, VISIBLE_FRAME); 405 mDecorFrame.writeToProto(proto, DECOR_FRAME); 406 mOutsetFrame.writeToProto(proto, OUTSET_FRAME); 407 mContainingFrame.writeToProto(proto, CONTAINING_FRAME); 408 mFrame.writeToProto(proto, FRAME); 409 mDisplayCutout.getDisplayCutout().writeToProto(proto, CUTOUT); 410 mContentInsets.writeToProto(proto, CONTENT_INSETS); 411 mOverscanInsets.writeToProto(proto, OVERSCAN_INSETS); 412 mVisibleInsets.writeToProto(proto, VISIBLE_INSETS); 413 mStableInsets.writeToProto(proto, STABLE_INSETS); 414 mOutsets.writeToProto(proto, OUTSETS); 415 416 proto.end(token); 417 } 418 dump(PrintWriter pw, String prefix)419 public void dump(PrintWriter pw, String prefix) { 420 pw.println(prefix + "Frames: containing=" 421 + mContainingFrame.toShortString(sTmpSB) 422 + " parent=" + mParentFrame.toShortString(sTmpSB)); 423 pw.println(prefix + " display=" + mDisplayFrame.toShortString(sTmpSB) 424 + " overscan=" + mOverscanFrame.toShortString(sTmpSB)); 425 pw.println(prefix + " content=" + mContentFrame.toShortString(sTmpSB) 426 + " visible=" + mVisibleFrame.toShortString(sTmpSB)); 427 pw.println(prefix + " decor=" + mDecorFrame.toShortString(sTmpSB)); 428 pw.println(prefix + " outset=" + mOutsetFrame.toShortString(sTmpSB)); 429 pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB) 430 + " last=" + mLastFrame.toShortString(sTmpSB)); 431 pw.println(prefix + " cutout=" + mDisplayCutout.getDisplayCutout() 432 + " last=" + mLastDisplayCutout.getDisplayCutout()); 433 pw.print(prefix + "Cur insets: overscan=" + mOverscanInsets.toShortString(sTmpSB) 434 + " content=" + mContentInsets.toShortString(sTmpSB) 435 + " visible=" + mVisibleInsets.toShortString(sTmpSB) 436 + " stable=" + mStableInsets.toShortString(sTmpSB) 437 + " outsets=" + mOutsets.toShortString(sTmpSB)); 438 pw.println(prefix + "Lst insets: overscan=" + mLastOverscanInsets.toShortString(sTmpSB) 439 + " content=" + mLastContentInsets.toShortString(sTmpSB) 440 + " visible=" + mLastVisibleInsets.toShortString(sTmpSB) 441 + " stable=" + mLastStableInsets.toShortString(sTmpSB) 442 + " outset=" + mLastOutsets.toShortString(sTmpSB)); 443 } 444 getInsetsInfo()445 String getInsetsInfo() { 446 return "ci=" + mContentInsets.toShortString() 447 + " vi=" + mVisibleInsets.toShortString() 448 + " si=" + mStableInsets.toShortString() 449 + " of=" + mOutsets.toShortString(); 450 } 451 getInsetsChangedInfo()452 String getInsetsChangedInfo() { 453 return "contentInsetsChanged=" + mContentInsetsChanged 454 + " " + mContentInsets.toShortString() 455 + " visibleInsetsChanged=" + mVisibleInsetsChanged 456 + " " + mVisibleInsets.toShortString() 457 + " stableInsetsChanged=" + mStableInsetsChanged 458 + " " + mStableInsets.toShortString() 459 + " outsetsChanged=" + mOutsetsChanged 460 + " " + mOutsets.toShortString() 461 + " displayCutoutChanged=" + mDisplayCutoutChanged; 462 } 463 } 464