blob: 20a874b7d0e83a6bbdb3d012ddd0c92402629548 [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;
39
chaviw9c81e632018-07-31 11:17:52 -070040import com.android.server.wm.utils.InsetUtils;
chaviwcdba9a42018-07-19 11:36:42 -070041import com.android.server.wm.utils.WmDisplayCutout;
chaviw553b0212018-07-12 13:37:01 -070042
chaviwc65fa582018-08-09 15:33:13 -070043import java.io.PrintWriter;
44
chaviw553b0212018-07-12 13:37:01 -070045/**
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 */
50public class WindowFrames {
chaviwc65fa582018-08-09 15:33:13 -070051 private static final StringBuilder sTmpSB = new StringBuilder();
chaviw553b0212018-07-12 13:37:01 -070052
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}
chaviw9c81e632018-07-31 11:17:52 -070069 */
chaviw553b0212018-07-12 13:37:01 -070070 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
chaviw492139a2018-07-16 16:07:35 -0700117 /**
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
chaviw9c81e632018-07-31 11:17:52 -0700127 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
chaviwcdba9a42018-07-19 11:36:42 -0700133 /**
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 */
chaviw9c81e632018-07-31 11:17:52 -0700146 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();
chaviwcdba9a42018-07-19 11:36:42 -0700192
chaviw1454b392018-08-06 09:54:04 -0700193 private boolean mHasOutsets;
194
195 private boolean mContentChanged;
196
chaviw553b0212018-07-12 13:37:01 -0700197 public WindowFrames() {
198 }
199
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
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
chaviwcdba9a42018-07-19 11:36:42 -0700219 public void setParentFrameWasClippedByDisplayCutout(
220 boolean parentFrameWasClippedByDisplayCutout) {
221 mParentFrameWasClippedByDisplayCutout = parentFrameWasClippedByDisplayCutout;
222 }
223
224 boolean parentFrameWasClippedByDisplayCutout() {
225 return mParentFrameWasClippedByDisplayCutout;
226 }
227
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 */
chaviw9c81e632018-07-31 11:17:52 -0700235 private boolean didFrameSizeChange() {
chaviwcdba9a42018-07-19 11:36:42 -0700236 return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
237 }
238
239 /**
chaviw9c81e632018-07-31 11:17:52 -0700240 * 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.
chaviwcdba9a42018-07-19 11:36:42 -0700243 */
chaviw1454b392018-08-06 09:54:04 -0700244 void calculateOutsets() {
245 if (mHasOutsets) {
chaviw9c81e632018-07-31 11:17:52 -0700246 InsetUtils.insetsBetweenFrames(mOutsetFrame, mContentFrame, mOutsets);
247 } else {
248 mOutsets.setEmpty();
249 }
250 }
251
252 /**
chaviw1454b392018-08-06 09:54:04 -0700253 * Calculate the insets for the type
254 * {@link android.view.WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
chaviw9c81e632018-07-31 11:17:52 -0700255 *
256 * @param cutoutInsets The insets for the cutout.
257 */
258 void calculateDockedDividerInsets(Rect cutoutInsets) {
259 // For the docked divider, we calculate the stable insets like a full-screen window
260 // so it can use it to calculate the snap positions.
261 mTmpRect.set(mDisplayFrame);
262 mTmpRect.inset(cutoutInsets);
263 mTmpRect.intersectUnchecked(mStableFrame);
264 InsetUtils.insetsBetweenFrames(mDisplayFrame, mTmpRect, mStableInsets);
265
266 // The divider doesn't care about insets in any case, so set it to empty so we don't
267 // trigger a relayout when moving it.
268 mContentInsets.setEmpty();
269 mVisibleInsets.setEmpty();
270 mDisplayCutout = WmDisplayCutout.NO_CUTOUT;
271 }
272
273 /**
274 * Calculate the insets for a window.
275 *
276 * @param windowsAreFloating Whether the window is in a floating task such as pinned or
277 * freeform
278 * @param inFullscreenContainer Whether the window is in a container that takes up the screen's
279 * entire space
280 * @param windowBounds The bounds for the window
281 */
282 void calculateInsets(boolean windowsAreFloating, boolean inFullscreenContainer,
283 Rect windowBounds) {
284 // Override right and/or bottom insets in case if the frame doesn't fit the screen in
285 // non-fullscreen mode.
286 boolean overrideRightInset = !windowsAreFloating && !inFullscreenContainer
287 && mFrame.right > windowBounds.right;
288 boolean overrideBottomInset = !windowsAreFloating && !inFullscreenContainer
289 && mFrame.bottom > windowBounds.bottom;
290
chaviw34b3ba02018-09-14 10:01:55 -0700291 mTmpRect.set(mFrame.left, mFrame.top,
292 overrideRightInset ? windowBounds.right : mFrame.right,
293 overrideBottomInset ? windowBounds.bottom : mFrame.bottom);
chaviw9c81e632018-07-31 11:17:52 -0700294
295 InsetUtils.insetsBetweenFrames(mTmpRect, mContentFrame, mContentInsets);
296 InsetUtils.insetsBetweenFrames(mTmpRect, mVisibleFrame, mVisibleInsets);
297 InsetUtils.insetsBetweenFrames(mTmpRect, mStableFrame, mStableInsets);
298 }
299
300 /**
301 * Scales all the insets by a specific amount.
302 *
303 * @param scale The amount to scale the insets by.
304 */
305 void scaleInsets(float scale) {
306 mOverscanInsets.scale(scale);
307 mContentInsets.scale(scale);
308 mVisibleInsets.scale(scale);
309 mStableInsets.scale(scale);
310 mOutsets.scale(scale);
311 }
312
313 void offsetFrames(int layoutXDiff, int layoutYDiff) {
314 mFrame.offset(layoutXDiff, layoutYDiff);
315 mContentFrame.offset(layoutXDiff, layoutYDiff);
316 mVisibleFrame.offset(layoutXDiff, layoutYDiff);
317 mStableFrame.offset(layoutXDiff, layoutYDiff);
318 }
319
320 /**
321 * Updates info about whether the size of the window has changed since last reported.
322 *
323 * @return true if info about size has changed since last reported.
324 */
325 boolean setReportResizeHints() {
326 mOverscanInsetsChanged |= !mLastOverscanInsets.equals(mOverscanInsets);
327 mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
328 mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets);
329 mStableInsetsChanged |= !mLastStableInsets.equals(mStableInsets);
330 mOutsetsChanged |= !mLastOutsets.equals(mOutsets);
331 mFrameSizeChanged |= didFrameSizeChange();
332 mDisplayCutoutChanged |= !mLastDisplayCutout.equals(mDisplayCutout);
333 return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged
334 || mStableInsetsChanged || mOutsetsChanged || mFrameSizeChanged
335 || mDisplayCutoutChanged;
336 }
337
338 /**
339 * Resets the insets changed flags so they're all set to false again. This should be called
340 * after the insets are reported to client.
341 */
342 void resetInsetsChanged() {
343 mOverscanInsetsChanged = false;
344 mContentInsetsChanged = false;
345 mVisibleInsetsChanged = false;
346 mStableInsetsChanged = false;
347 mOutsetsChanged = false;
348 mFrameSizeChanged = false;
349 mDisplayCutoutChanged = false;
350 }
351
352 /**
353 * Copy over inset values as the last insets that were sent to the client.
354 */
355 void updateLastInsetValues() {
356 mLastOverscanInsets.set(mOverscanInsets);
357 mLastContentInsets.set(mContentInsets);
358 mLastVisibleInsets.set(mVisibleInsets);
359 mLastStableInsets.set(mStableInsets);
360 mLastOutsets.set(mOutsets);
361 mLastDisplayCutout = mDisplayCutout;
362 }
363
364 /**
365 * Sets the last content insets as (-1, -1, -1, -1) to force the next layout pass to update
366 * the client.
367 */
368 void resetLastContentInsets() {
369 mLastContentInsets.set(-1, -1, -1, -1);
chaviwcdba9a42018-07-19 11:36:42 -0700370 }
371
chaviw1454b392018-08-06 09:54:04 -0700372 /**
373 * Sets whether the frame has outsets.
374 */
375 public void setHasOutsets(boolean hasOutsets) {
376 mHasOutsets = hasOutsets;
377 }
378
379 /**
380 * Sets whether the content has changed. This means that either the size or parent frame has
381 * changed.
382 */
383 public void setContentChanged(boolean contentChanged) {
384 mContentChanged = contentChanged;
385 }
386
387 /**
388 * @see #setContentChanged(boolean)
389 */
390 boolean hasContentChanged() {
391 return mContentChanged;
392 }
393
chaviw553b0212018-07-12 13:37:01 -0700394 public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) {
395 final long token = proto.start(fieldId);
396 mParentFrame.writeToProto(proto, PARENT_FRAME);
397 mContentFrame.writeToProto(proto, CONTENT_FRAME);
398 mDisplayFrame.writeToProto(proto, DISPLAY_FRAME);
399 mOverscanFrame.writeToProto(proto, OVERSCAN_FRAME);
400 mVisibleFrame.writeToProto(proto, VISIBLE_FRAME);
401 mDecorFrame.writeToProto(proto, DECOR_FRAME);
402 mOutsetFrame.writeToProto(proto, OUTSET_FRAME);
403 mContainingFrame.writeToProto(proto, CONTAINING_FRAME);
chaviw492139a2018-07-16 16:07:35 -0700404 mFrame.writeToProto(proto, FRAME);
chaviwcdba9a42018-07-19 11:36:42 -0700405 mDisplayCutout.getDisplayCutout().writeToProto(proto, CUTOUT);
chaviw9c81e632018-07-31 11:17:52 -0700406 mContentInsets.writeToProto(proto, CONTENT_INSETS);
407 mOverscanInsets.writeToProto(proto, OVERSCAN_INSETS);
408 mVisibleInsets.writeToProto(proto, VISIBLE_INSETS);
409 mStableInsets.writeToProto(proto, STABLE_INSETS);
410 mOutsets.writeToProto(proto, OUTSETS);
411
chaviw553b0212018-07-12 13:37:01 -0700412 proto.end(token);
413 }
414
415 public void dump(PrintWriter pw, String prefix) {
chaviwc65fa582018-08-09 15:33:13 -0700416 pw.println(prefix + "Frames: containing="
417 + mContainingFrame.toShortString(sTmpSB)
418 + " parent=" + mParentFrame.toShortString(sTmpSB));
419 pw.println(prefix + " display=" + mDisplayFrame.toShortString(sTmpSB)
420 + " overscan=" + mOverscanFrame.toShortString(sTmpSB));
421 pw.println(prefix + " content=" + mContentFrame.toShortString(sTmpSB)
422 + " visible=" + mVisibleFrame.toShortString(sTmpSB));
423 pw.println(prefix + " decor=" + mDecorFrame.toShortString(sTmpSB));
424 pw.println(prefix + " outset=" + mOutsetFrame.toShortString(sTmpSB));
425 pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB)
426 + " last=" + mLastFrame.toShortString(sTmpSB));
427 pw.println(prefix + " cutout=" + mDisplayCutout.getDisplayCutout()
428 + " last=" + mLastDisplayCutout.getDisplayCutout());
chaviw9c81e632018-07-31 11:17:52 -0700429 pw.print(prefix + "Cur insets: overscan=" + mOverscanInsets.toShortString(sTmpSB)
430 + " content=" + mContentInsets.toShortString(sTmpSB)
431 + " visible=" + mVisibleInsets.toShortString(sTmpSB)
432 + " stable=" + mStableInsets.toShortString(sTmpSB)
433 + " outsets=" + mOutsets.toShortString(sTmpSB));
434 pw.println(prefix + "Lst insets: overscan=" + mLastOverscanInsets.toShortString(sTmpSB)
435 + " content=" + mLastContentInsets.toShortString(sTmpSB)
436 + " visible=" + mLastVisibleInsets.toShortString(sTmpSB)
437 + " stable=" + mLastStableInsets.toShortString(sTmpSB)
438 + " outset=" + mLastOutsets.toShortString(sTmpSB));
439 }
440
441 String getInsetsInfo() {
442 return "ci=" + mContentInsets.toShortString()
443 + " vi=" + mVisibleInsets.toShortString()
444 + " si=" + mStableInsets.toShortString()
445 + " of=" + mOutsets.toShortString();
446 }
447
448 String getInsetsChangedInfo() {
449 return "contentInsetsChanged=" + mContentInsetsChanged
450 + " " + mContentInsets.toShortString()
451 + " visibleInsetsChanged=" + mVisibleInsetsChanged
452 + " " + mVisibleInsets.toShortString()
453 + " stableInsetsChanged=" + mStableInsetsChanged
454 + " " + mStableInsets.toShortString()
455 + " outsetsChanged=" + mOutsetsChanged
456 + " " + mOutsets.toShortString()
457 + " displayCutoutChanged=" + mDisplayCutoutChanged;
chaviw553b0212018-07-12 13:37:01 -0700458 }
chaviw553b0212018-07-12 13:37:01 -0700459}