blob: cbe7d9d05e28b165ace284ccdd31e6a15c080c1b [file] [log] [blame]
chaviw553b0212018-07-12 13:37:01 -07001/*
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
17package com.android.server.wm;
18
19import static com.android.server.wm.WindowFramesProto.CONTAINING_FRAME;
20import static com.android.server.wm.WindowFramesProto.CONTENT_FRAME;
chaviw9c81e632018-07-31 11:17:52 -070021import static com.android.server.wm.WindowFramesProto.CONTENT_INSETS;
chaviwcdba9a42018-07-19 11:36:42 -070022import static com.android.server.wm.WindowFramesProto.CUTOUT;
chaviw553b0212018-07-12 13:37:01 -070023import static com.android.server.wm.WindowFramesProto.DECOR_FRAME;
24import static com.android.server.wm.WindowFramesProto.DISPLAY_FRAME;
chaviw492139a2018-07-16 16:07:35 -070025import static com.android.server.wm.WindowFramesProto.FRAME;
chaviw9c81e632018-07-31 11:17:52 -070026import static com.android.server.wm.WindowFramesProto.OUTSETS;
chaviw553b0212018-07-12 13:37:01 -070027import static com.android.server.wm.WindowFramesProto.OUTSET_FRAME;
28import static com.android.server.wm.WindowFramesProto.OVERSCAN_FRAME;
chaviw9c81e632018-07-31 11:17:52 -070029import static com.android.server.wm.WindowFramesProto.OVERSCAN_INSETS;
chaviw553b0212018-07-12 13:37:01 -070030import static com.android.server.wm.WindowFramesProto.PARENT_FRAME;
chaviw9c81e632018-07-31 11:17:52 -070031import static com.android.server.wm.WindowFramesProto.STABLE_INSETS;
chaviw553b0212018-07-12 13:37:01 -070032import static com.android.server.wm.WindowFramesProto.VISIBLE_FRAME;
chaviw9c81e632018-07-31 11:17:52 -070033import static com.android.server.wm.WindowFramesProto.VISIBLE_INSETS;
chaviw553b0212018-07-12 13:37:01 -070034
35import android.annotation.NonNull;
36import android.graphics.Rect;
37import android.util.proto.ProtoOutputStream;
chaviwcdba9a42018-07-19 11:36:42 -070038import android.view.DisplayCutout;
chaviw9c81e632018-07-31 11:17:52 -070039import android.view.WindowManager;
chaviwcdba9a42018-07-19 11:36:42 -070040
chaviw9c81e632018-07-31 11:17:52 -070041import com.android.server.wm.utils.InsetUtils;
chaviwcdba9a42018-07-19 11:36:42 -070042import com.android.server.wm.utils.WmDisplayCutout;
chaviw553b0212018-07-12 13:37:01 -070043
chaviwc65fa582018-08-09 15:33:13 -070044import java.io.PrintWriter;
45
chaviw553b0212018-07-12 13:37:01 -070046/**
47 * Container class for all the window frames that affect how windows are laid out.
48 *
49 * TODO(b/111611553): Investigate which frames are still needed and which are duplicates
50 */
51public class WindowFrames {
chaviwc65fa582018-08-09 15:33:13 -070052 private static final StringBuilder sTmpSB = new StringBuilder();
chaviw553b0212018-07-12 13:37:01 -070053
54 /**
55 * In most cases, this is the area of the entire screen.
56 *
57 * TODO(b/111611553): The name is unclear and most likely should be swapped with
58 * {@link #mDisplayFrame}
59 * TODO(b/111611553): In some cases, it also includes top insets, like for IME. Determine
60 * whether this is still necessary to do.
61 */
62 public final Rect mParentFrame = new Rect();
63
64 /**
65 * The entire screen area of the {@link TaskStack} this window is in. Usually equal to the
66 * screen area of the device.
67 *
68 * TODO(b/111611553): The name is unclear and most likely should be swapped with
69 * {@link #mParentFrame}
chaviw9c81e632018-07-31 11:17:52 -070070 */
chaviw553b0212018-07-12 13:37:01 -070071 public final Rect mDisplayFrame = new Rect();
72
73 /**
74 * The region of the display frame that the display type supports displaying content on. This
75 * is mostly a special case for TV where some displays don’t have the entire display usable.
76 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to
77 * allow window display contents to extend into the overscan region.
78 */
79 public final Rect mOverscanFrame = new Rect();
80
81 /**
82 * Legacy stuff. Generally equal to the content frame expect when the IME for older apps
83 * displays hint text.
84 */
85 public final Rect mVisibleFrame = new Rect();
86
87 /**
88 * The area not occupied by the status and navigation bars. So, if both status and navigation
89 * bars are visible, the decor frame is equal to the stable frame.
90 */
91 public final Rect mDecorFrame = new Rect();
92
93 /**
94 * Equal to the decor frame if the IME (e.g. keyboard) is not present. Equal to the decor frame
95 * minus the area occupied by the IME if the IME is present.
96 */
97 public final Rect mContentFrame = new Rect();
98
99 /**
100 * The display frame minus the stable insets. This value is always constant regardless of if
101 * the status bar or navigation bar is visible.
102 */
103 public final Rect mStableFrame = new Rect();
104
105 /**
106 * Frame that includes dead area outside of the surface but where we want to pretend that it's
107 * possible to draw.
108 */
109 final public Rect mOutsetFrame = new Rect();
110
111 /**
112 * Similar to {@link #mDisplayFrame}
113 *
114 * TODO: Why is this different than mDisplayFrame
115 */
116 final Rect mContainingFrame = new Rect();
117
chaviw492139a2018-07-16 16:07:35 -0700118 /**
119 * "Real" frame that the application sees, in display coordinate space.
120 */
121 final Rect mFrame = new Rect();
122
123 /**
124 * The last real frame that was reported to the client.
125 */
126 final Rect mLastFrame = new Rect();
127
chaviw9c81e632018-07-31 11:17:52 -0700128 private boolean mFrameSizeChanged = false;
129
130 // Frame that is scaled to the application's coordinate space when in
131 // screen size compatibility mode.
132 final Rect mCompatFrame = new Rect();
133
chaviwcdba9a42018-07-19 11:36:42 -0700134 /**
135 * Whether the parent frame would have been different if there was no display cutout.
136 */
137 private boolean mParentFrameWasClippedByDisplayCutout;
138
139 /**
140 * Part of the display that has been cut away. See {@link DisplayCutout}.
141 */
142 WmDisplayCutout mDisplayCutout = WmDisplayCutout.NO_CUTOUT;
143
144 /**
145 * The last cutout that has been reported to the client.
146 */
chaviw9c81e632018-07-31 11:17:52 -0700147 private WmDisplayCutout mLastDisplayCutout = WmDisplayCutout.NO_CUTOUT;
148
149 private boolean mDisplayCutoutChanged;
150
151 /**
152 * Insets that determine the area covered by the display overscan region. These are in the
153 * application's coordinate space (without compatibility scale applied).
154 */
155 final Rect mOverscanInsets = new Rect();
156 final Rect mLastOverscanInsets = new Rect();
157 private boolean mOverscanInsetsChanged;
158
159 /**
160 * Insets that determine the area covered by the stable system windows. These are in the
161 * application's coordinate space (without compatibility scale applied).
162 */
163 final Rect mStableInsets = new Rect();
164 final Rect mLastStableInsets = new Rect();
165 private boolean mStableInsetsChanged;
166
167 /**
168 * Outsets determine the area outside of the surface where we want to pretend that it's possible
169 * to draw anyway.
170 */
171 final Rect mOutsets = new Rect();
172 final Rect mLastOutsets = new Rect();
173 private boolean mOutsetsChanged = false;
174
175 /**
176 * Insets that determine the actually visible area. These are in the application's
177 * coordinate space (without compatibility scale applied).
178 */
179 final Rect mVisibleInsets = new Rect();
180 final Rect mLastVisibleInsets = new Rect();
181 private boolean mVisibleInsetsChanged;
182
183 /**
184 * Insets that are covered by system windows (such as the status bar) and
185 * transient docking windows (such as the IME). These are in the application's
186 * coordinate space (without compatibility scale applied).
187 */
188 final Rect mContentInsets = new Rect();
189 final Rect mLastContentInsets = new Rect();
190 private boolean mContentInsetsChanged;
191
192 private final Rect mTmpRect = new Rect();
chaviwcdba9a42018-07-19 11:36:42 -0700193
chaviw553b0212018-07-12 13:37:01 -0700194 public WindowFrames() {
195 }
196
197 public WindowFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame,
198 Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame) {
199 setFrames(parentFrame, displayFrame, overscanFrame, contentFrame, visibleFrame, decorFrame,
200 stableFrame, outsetFrame);
201 }
202
203 public void setFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame,
204 Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
205 Rect outsetFrame) {
206 mParentFrame.set(parentFrame);
207 mDisplayFrame.set(displayFrame);
208 mOverscanFrame.set(overscanFrame);
209 mContentFrame.set(contentFrame);
210 mVisibleFrame.set(visibleFrame);
211 mDecorFrame.set(decorFrame);
212 mStableFrame.set(stableFrame);
213 mOutsetFrame.set(outsetFrame);
214 }
215
chaviwcdba9a42018-07-19 11:36:42 -0700216 public void setParentFrameWasClippedByDisplayCutout(
217 boolean parentFrameWasClippedByDisplayCutout) {
218 mParentFrameWasClippedByDisplayCutout = parentFrameWasClippedByDisplayCutout;
219 }
220
221 boolean parentFrameWasClippedByDisplayCutout() {
222 return mParentFrameWasClippedByDisplayCutout;
223 }
224
225 public void setDisplayCutout(WmDisplayCutout displayCutout) {
226 mDisplayCutout = displayCutout;
227 }
228
229 /**
230 * @return true if the width or height has changed since last reported to the client.
231 */
chaviw9c81e632018-07-31 11:17:52 -0700232 private boolean didFrameSizeChange() {
chaviwcdba9a42018-07-19 11:36:42 -0700233 return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
234 }
235
236 /**
chaviw9c81e632018-07-31 11:17:52 -0700237 * Calculates the outsets for this windowFrame. The outsets are calculated by the area between
238 * the {@link #mOutsetFrame} and the {@link #mContentFrame}. If there are no outsets, then
239 * {@link #mOutsets} is set to empty.
240 *
241 * @param hasOutsets Whether this frame has outsets.
chaviwcdba9a42018-07-19 11:36:42 -0700242 */
chaviw9c81e632018-07-31 11:17:52 -0700243 void calculateOutsets(boolean hasOutsets) {
244 if (hasOutsets) {
245 InsetUtils.insetsBetweenFrames(mOutsetFrame, mContentFrame, mOutsets);
246 } else {
247 mOutsets.setEmpty();
248 }
249 }
250
251 /**
252 * Calculate the insets for the type {@link WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
253 *
254 * @param cutoutInsets The insets for the cutout.
255 */
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 */
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
chaviw34b3ba02018-09-14 10:01:55 -0700289 mTmpRect.set(mFrame.left, mFrame.top,
290 overrideRightInset ? windowBounds.right : mFrame.right,
291 overrideBottomInset ? windowBounds.bottom : mFrame.bottom);
chaviw9c81e632018-07-31 11:17:52 -0700292
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 */
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
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 */
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 */
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 */
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 */
366 void resetLastContentInsets() {
367 mLastContentInsets.set(-1, -1, -1, -1);
chaviwcdba9a42018-07-19 11:36:42 -0700368 }
369
chaviw553b0212018-07-12 13:37:01 -0700370 public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) {
371 final long token = proto.start(fieldId);
372 mParentFrame.writeToProto(proto, PARENT_FRAME);
373 mContentFrame.writeToProto(proto, CONTENT_FRAME);
374 mDisplayFrame.writeToProto(proto, DISPLAY_FRAME);
375 mOverscanFrame.writeToProto(proto, OVERSCAN_FRAME);
376 mVisibleFrame.writeToProto(proto, VISIBLE_FRAME);
377 mDecorFrame.writeToProto(proto, DECOR_FRAME);
378 mOutsetFrame.writeToProto(proto, OUTSET_FRAME);
379 mContainingFrame.writeToProto(proto, CONTAINING_FRAME);
chaviw492139a2018-07-16 16:07:35 -0700380 mFrame.writeToProto(proto, FRAME);
chaviwcdba9a42018-07-19 11:36:42 -0700381 mDisplayCutout.getDisplayCutout().writeToProto(proto, CUTOUT);
chaviw9c81e632018-07-31 11:17:52 -0700382 mContentInsets.writeToProto(proto, CONTENT_INSETS);
383 mOverscanInsets.writeToProto(proto, OVERSCAN_INSETS);
384 mVisibleInsets.writeToProto(proto, VISIBLE_INSETS);
385 mStableInsets.writeToProto(proto, STABLE_INSETS);
386 mOutsets.writeToProto(proto, OUTSETS);
387
chaviw553b0212018-07-12 13:37:01 -0700388 proto.end(token);
389 }
390
391 public void dump(PrintWriter pw, String prefix) {
chaviwc65fa582018-08-09 15:33:13 -0700392 pw.println(prefix + "Frames: containing="
393 + mContainingFrame.toShortString(sTmpSB)
394 + " parent=" + mParentFrame.toShortString(sTmpSB));
395 pw.println(prefix + " display=" + mDisplayFrame.toShortString(sTmpSB)
396 + " overscan=" + mOverscanFrame.toShortString(sTmpSB));
397 pw.println(prefix + " content=" + mContentFrame.toShortString(sTmpSB)
398 + " visible=" + mVisibleFrame.toShortString(sTmpSB));
399 pw.println(prefix + " decor=" + mDecorFrame.toShortString(sTmpSB));
400 pw.println(prefix + " outset=" + mOutsetFrame.toShortString(sTmpSB));
401 pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB)
402 + " last=" + mLastFrame.toShortString(sTmpSB));
403 pw.println(prefix + " cutout=" + mDisplayCutout.getDisplayCutout()
404 + " last=" + mLastDisplayCutout.getDisplayCutout());
chaviw9c81e632018-07-31 11:17:52 -0700405 pw.print(prefix + "Cur insets: overscan=" + mOverscanInsets.toShortString(sTmpSB)
406 + " content=" + mContentInsets.toShortString(sTmpSB)
407 + " visible=" + mVisibleInsets.toShortString(sTmpSB)
408 + " stable=" + mStableInsets.toShortString(sTmpSB)
409 + " outsets=" + mOutsets.toShortString(sTmpSB));
410 pw.println(prefix + "Lst insets: overscan=" + mLastOverscanInsets.toShortString(sTmpSB)
411 + " content=" + mLastContentInsets.toShortString(sTmpSB)
412 + " visible=" + mLastVisibleInsets.toShortString(sTmpSB)
413 + " stable=" + mLastStableInsets.toShortString(sTmpSB)
414 + " outset=" + mLastOutsets.toShortString(sTmpSB));
415 }
416
417 String getInsetsInfo() {
418 return "ci=" + mContentInsets.toShortString()
419 + " vi=" + mVisibleInsets.toShortString()
420 + " si=" + mStableInsets.toShortString()
421 + " of=" + mOutsets.toShortString();
422 }
423
424 String getInsetsChangedInfo() {
425 return "contentInsetsChanged=" + mContentInsetsChanged
426 + " " + mContentInsets.toShortString()
427 + " visibleInsetsChanged=" + mVisibleInsetsChanged
428 + " " + mVisibleInsets.toShortString()
429 + " stableInsetsChanged=" + mStableInsetsChanged
430 + " " + mStableInsets.toShortString()
431 + " outsetsChanged=" + mOutsetsChanged
432 + " " + mOutsets.toShortString()
433 + " displayCutoutChanged=" + mDisplayCutoutChanged;
chaviw553b0212018-07-12 13:37:01 -0700434 }
chaviw553b0212018-07-12 13:37:01 -0700435}