blob: 97186b4e9cda473edf0dd5d3be21c5e4844e64c8 [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;
chaviw553b0212018-07-12 13:37:01 -070026import static com.android.server.wm.WindowFramesProto.PARENT_FRAME;
chaviw9c81e632018-07-31 11:17:52 -070027import static com.android.server.wm.WindowFramesProto.STABLE_INSETS;
chaviw553b0212018-07-12 13:37:01 -070028import static com.android.server.wm.WindowFramesProto.VISIBLE_FRAME;
chaviw9c81e632018-07-31 11:17:52 -070029import static com.android.server.wm.WindowFramesProto.VISIBLE_INSETS;
chaviw553b0212018-07-12 13:37:01 -070030
31import android.annotation.NonNull;
32import android.graphics.Rect;
33import android.util.proto.ProtoOutputStream;
chaviwcdba9a42018-07-19 11:36:42 -070034import android.view.DisplayCutout;
35
chaviw9c81e632018-07-31 11:17:52 -070036import com.android.server.wm.utils.InsetUtils;
chaviwcdba9a42018-07-19 11:36:42 -070037import com.android.server.wm.utils.WmDisplayCutout;
chaviw553b0212018-07-12 13:37:01 -070038
chaviwc65fa582018-08-09 15:33:13 -070039import java.io.PrintWriter;
40
chaviw553b0212018-07-12 13:37:01 -070041/**
42 * Container class for all the window frames that affect how windows are laid out.
43 *
44 * TODO(b/111611553): Investigate which frames are still needed and which are duplicates
45 */
46public class WindowFrames {
chaviwc65fa582018-08-09 15:33:13 -070047 private static final StringBuilder sTmpSB = new StringBuilder();
chaviw553b0212018-07-12 13:37:01 -070048
49 /**
50 * In most cases, this is the area of the entire screen.
51 *
52 * TODO(b/111611553): The name is unclear and most likely should be swapped with
53 * {@link #mDisplayFrame}
54 * TODO(b/111611553): In some cases, it also includes top insets, like for IME. Determine
55 * whether this is still necessary to do.
56 */
57 public final Rect mParentFrame = new Rect();
58
59 /**
Louis Changdc077272019-11-12 16:52:56 +080060 * The entire screen area of the {@link ActivityStack} this window is in. Usually equal to the
chaviw553b0212018-07-12 13:37:01 -070061 * screen area of the device.
62 *
63 * TODO(b/111611553): The name is unclear and most likely should be swapped with
64 * {@link #mParentFrame}
chaviw9c81e632018-07-31 11:17:52 -070065 */
chaviw553b0212018-07-12 13:37:01 -070066 public final Rect mDisplayFrame = new Rect();
67
68 /**
chaviw553b0212018-07-12 13:37:01 -070069 * Legacy stuff. Generally equal to the content frame expect when the IME for older apps
70 * displays hint text.
71 */
72 public final Rect mVisibleFrame = new Rect();
73
74 /**
75 * The area not occupied by the status and navigation bars. So, if both status and navigation
76 * bars are visible, the decor frame is equal to the stable frame.
77 */
78 public final Rect mDecorFrame = new Rect();
79
80 /**
81 * Equal to the decor frame if the IME (e.g. keyboard) is not present. Equal to the decor frame
82 * minus the area occupied by the IME if the IME is present.
83 */
84 public final Rect mContentFrame = new Rect();
85
86 /**
87 * The display frame minus the stable insets. This value is always constant regardless of if
88 * the status bar or navigation bar is visible.
89 */
90 public final Rect mStableFrame = new Rect();
91
92 /**
chaviw553b0212018-07-12 13:37:01 -070093 * Similar to {@link #mDisplayFrame}
94 *
95 * TODO: Why is this different than mDisplayFrame
96 */
97 final Rect mContainingFrame = new Rect();
98
chaviw492139a2018-07-16 16:07:35 -070099 /**
100 * "Real" frame that the application sees, in display coordinate space.
101 */
102 final Rect mFrame = new Rect();
103
104 /**
105 * The last real frame that was reported to the client.
106 */
107 final Rect mLastFrame = new Rect();
108
Evan Rosky70213702019-11-05 10:26:24 -0800109 /**
110 * mFrame but relative to the parent container.
111 */
112 final Rect mRelFrame = new Rect();
113
114 /**
115 * mLastFrame but relative to the parent container
116 */
117 final Rect mLastRelFrame = new Rect();
118
chaviw9c81e632018-07-31 11:17:52 -0700119 private boolean mFrameSizeChanged = false;
120
121 // Frame that is scaled to the application's coordinate space when in
122 // screen size compatibility mode.
123 final Rect mCompatFrame = new Rect();
124
chaviwcdba9a42018-07-19 11:36:42 -0700125 /**
126 * Whether the parent frame would have been different if there was no display cutout.
127 */
128 private boolean mParentFrameWasClippedByDisplayCutout;
129
130 /**
131 * Part of the display that has been cut away. See {@link DisplayCutout}.
132 */
133 WmDisplayCutout mDisplayCutout = WmDisplayCutout.NO_CUTOUT;
134
135 /**
136 * The last cutout that has been reported to the client.
137 */
chaviw9c81e632018-07-31 11:17:52 -0700138 private WmDisplayCutout mLastDisplayCutout = WmDisplayCutout.NO_CUTOUT;
139
140 private boolean mDisplayCutoutChanged;
141
142 /**
chaviw9c81e632018-07-31 11:17:52 -0700143 * Insets that determine the area covered by the stable system windows. These are in the
144 * application's coordinate space (without compatibility scale applied).
145 */
146 final Rect mStableInsets = new Rect();
147 final Rect mLastStableInsets = new Rect();
148 private boolean mStableInsetsChanged;
149
150 /**
chaviw9c81e632018-07-31 11:17:52 -0700151 * Insets that determine the actually visible area. These are in the application's
152 * coordinate space (without compatibility scale applied).
153 */
154 final Rect mVisibleInsets = new Rect();
155 final Rect mLastVisibleInsets = new Rect();
156 private boolean mVisibleInsetsChanged;
157
158 /**
159 * Insets that are covered by system windows (such as the status bar) and
160 * transient docking windows (such as the IME). These are in the application's
161 * coordinate space (without compatibility scale applied).
162 */
163 final Rect mContentInsets = new Rect();
164 final Rect mLastContentInsets = new Rect();
165 private boolean mContentInsetsChanged;
166
167 private final Rect mTmpRect = new Rect();
chaviwcdba9a42018-07-19 11:36:42 -0700168
chaviw1454b392018-08-06 09:54:04 -0700169 private boolean mContentChanged;
170
chaviw553b0212018-07-12 13:37:01 -0700171 public WindowFrames() {
172 }
173
Jorim Jaggif081f062019-10-24 16:24:54 +0200174 public WindowFrames(Rect parentFrame, Rect displayFrame, Rect contentFrame,
175 Rect visibleFrame, Rect decorFrame, Rect stableFrame) {
176 setFrames(parentFrame, displayFrame, contentFrame, visibleFrame, decorFrame,
177 stableFrame);
chaviw553b0212018-07-12 13:37:01 -0700178 }
179
Jorim Jaggif081f062019-10-24 16:24:54 +0200180 public void setFrames(Rect parentFrame, Rect displayFrame,
181 Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame) {
chaviw553b0212018-07-12 13:37:01 -0700182 mParentFrame.set(parentFrame);
183 mDisplayFrame.set(displayFrame);
chaviw553b0212018-07-12 13:37:01 -0700184 mContentFrame.set(contentFrame);
185 mVisibleFrame.set(visibleFrame);
186 mDecorFrame.set(decorFrame);
187 mStableFrame.set(stableFrame);
chaviw553b0212018-07-12 13:37:01 -0700188 }
189
chaviwcdba9a42018-07-19 11:36:42 -0700190 public void setParentFrameWasClippedByDisplayCutout(
191 boolean parentFrameWasClippedByDisplayCutout) {
192 mParentFrameWasClippedByDisplayCutout = parentFrameWasClippedByDisplayCutout;
193 }
194
195 boolean parentFrameWasClippedByDisplayCutout() {
196 return mParentFrameWasClippedByDisplayCutout;
197 }
198
199 public void setDisplayCutout(WmDisplayCutout displayCutout) {
200 mDisplayCutout = displayCutout;
201 }
202
203 /**
204 * @return true if the width or height has changed since last reported to the client.
205 */
chaviw9c81e632018-07-31 11:17:52 -0700206 private boolean didFrameSizeChange() {
chaviwcdba9a42018-07-19 11:36:42 -0700207 return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
208 }
209
Tiger Huang4a7835f2019-11-06 00:07:56 +0800210 // TODO(b/118118435): Remove after migration.
chaviwcdba9a42018-07-19 11:36:42 -0700211 /**
chaviw1454b392018-08-06 09:54:04 -0700212 * Calculate the insets for the type
213 * {@link android.view.WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
chaviw9c81e632018-07-31 11:17:52 -0700214 *
215 * @param cutoutInsets The insets for the cutout.
216 */
217 void calculateDockedDividerInsets(Rect cutoutInsets) {
218 // For the docked divider, we calculate the stable insets like a full-screen window
219 // so it can use it to calculate the snap positions.
220 mTmpRect.set(mDisplayFrame);
221 mTmpRect.inset(cutoutInsets);
222 mTmpRect.intersectUnchecked(mStableFrame);
223 InsetUtils.insetsBetweenFrames(mDisplayFrame, mTmpRect, mStableInsets);
224
225 // The divider doesn't care about insets in any case, so set it to empty so we don't
226 // trigger a relayout when moving it.
227 mContentInsets.setEmpty();
228 mVisibleInsets.setEmpty();
229 mDisplayCutout = WmDisplayCutout.NO_CUTOUT;
230 }
231
232 /**
233 * Calculate the insets for a window.
234 *
235 * @param windowsAreFloating Whether the window is in a floating task such as pinned or
236 * freeform
237 * @param inFullscreenContainer Whether the window is in a container that takes up the screen's
238 * entire space
239 * @param windowBounds The bounds for the window
240 */
241 void calculateInsets(boolean windowsAreFloating, boolean inFullscreenContainer,
242 Rect windowBounds) {
243 // Override right and/or bottom insets in case if the frame doesn't fit the screen in
244 // non-fullscreen mode.
245 boolean overrideRightInset = !windowsAreFloating && !inFullscreenContainer
246 && mFrame.right > windowBounds.right;
247 boolean overrideBottomInset = !windowsAreFloating && !inFullscreenContainer
248 && mFrame.bottom > windowBounds.bottom;
249
chaviw34b3ba02018-09-14 10:01:55 -0700250 mTmpRect.set(mFrame.left, mFrame.top,
251 overrideRightInset ? windowBounds.right : mFrame.right,
252 overrideBottomInset ? windowBounds.bottom : mFrame.bottom);
chaviw9c81e632018-07-31 11:17:52 -0700253
254 InsetUtils.insetsBetweenFrames(mTmpRect, mContentFrame, mContentInsets);
255 InsetUtils.insetsBetweenFrames(mTmpRect, mVisibleFrame, mVisibleInsets);
256 InsetUtils.insetsBetweenFrames(mTmpRect, mStableFrame, mStableInsets);
257 }
258
259 /**
260 * Scales all the insets by a specific amount.
261 *
262 * @param scale The amount to scale the insets by.
263 */
264 void scaleInsets(float scale) {
chaviw9c81e632018-07-31 11:17:52 -0700265 mContentInsets.scale(scale);
266 mVisibleInsets.scale(scale);
267 mStableInsets.scale(scale);
chaviw9c81e632018-07-31 11:17:52 -0700268 }
269
270 void offsetFrames(int layoutXDiff, int layoutYDiff) {
271 mFrame.offset(layoutXDiff, layoutYDiff);
272 mContentFrame.offset(layoutXDiff, layoutYDiff);
273 mVisibleFrame.offset(layoutXDiff, layoutYDiff);
274 mStableFrame.offset(layoutXDiff, layoutYDiff);
275 }
276
277 /**
278 * Updates info about whether the size of the window has changed since last reported.
279 *
280 * @return true if info about size has changed since last reported.
281 */
282 boolean setReportResizeHints() {
chaviw9c81e632018-07-31 11:17:52 -0700283 mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
284 mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets);
285 mStableInsetsChanged |= !mLastStableInsets.equals(mStableInsets);
chaviw9c81e632018-07-31 11:17:52 -0700286 mFrameSizeChanged |= didFrameSizeChange();
287 mDisplayCutoutChanged |= !mLastDisplayCutout.equals(mDisplayCutout);
Jorim Jaggif081f062019-10-24 16:24:54 +0200288 return mContentInsetsChanged || mVisibleInsetsChanged
289 || mStableInsetsChanged || mFrameSizeChanged
chaviw9c81e632018-07-31 11:17:52 -0700290 || mDisplayCutoutChanged;
291 }
292
293 /**
294 * Resets the insets changed flags so they're all set to false again. This should be called
295 * after the insets are reported to client.
296 */
297 void resetInsetsChanged() {
chaviw9c81e632018-07-31 11:17:52 -0700298 mContentInsetsChanged = false;
299 mVisibleInsetsChanged = false;
300 mStableInsetsChanged = false;
chaviw9c81e632018-07-31 11:17:52 -0700301 mFrameSizeChanged = false;
302 mDisplayCutoutChanged = false;
303 }
304
305 /**
306 * Copy over inset values as the last insets that were sent to the client.
307 */
308 void updateLastInsetValues() {
chaviw9c81e632018-07-31 11:17:52 -0700309 mLastContentInsets.set(mContentInsets);
310 mLastVisibleInsets.set(mVisibleInsets);
311 mLastStableInsets.set(mStableInsets);
chaviw9c81e632018-07-31 11:17:52 -0700312 mLastDisplayCutout = mDisplayCutout;
313 }
314
315 /**
316 * Sets the last content insets as (-1, -1, -1, -1) to force the next layout pass to update
317 * the client.
318 */
319 void resetLastContentInsets() {
320 mLastContentInsets.set(-1, -1, -1, -1);
chaviwcdba9a42018-07-19 11:36:42 -0700321 }
322
chaviw1454b392018-08-06 09:54:04 -0700323 /**
chaviw1454b392018-08-06 09:54:04 -0700324 * Sets whether the content has changed. This means that either the size or parent frame has
325 * changed.
326 */
327 public void setContentChanged(boolean contentChanged) {
328 mContentChanged = contentChanged;
329 }
330
331 /**
332 * @see #setContentChanged(boolean)
333 */
334 boolean hasContentChanged() {
335 return mContentChanged;
336 }
337
Jeffrey Huangcb782852019-12-05 11:28:11 -0800338 public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) {
chaviw553b0212018-07-12 13:37:01 -0700339 final long token = proto.start(fieldId);
Jeffrey Huangcb782852019-12-05 11:28:11 -0800340 mParentFrame.dumpDebug(proto, PARENT_FRAME);
341 mContentFrame.dumpDebug(proto, CONTENT_FRAME);
342 mDisplayFrame.dumpDebug(proto, DISPLAY_FRAME);
343 mVisibleFrame.dumpDebug(proto, VISIBLE_FRAME);
344 mDecorFrame.dumpDebug(proto, DECOR_FRAME);
345 mContainingFrame.dumpDebug(proto, CONTAINING_FRAME);
346 mFrame.dumpDebug(proto, FRAME);
347 mDisplayCutout.getDisplayCutout().dumpDebug(proto, CUTOUT);
348 mContentInsets.dumpDebug(proto, CONTENT_INSETS);
349 mVisibleInsets.dumpDebug(proto, VISIBLE_INSETS);
350 mStableInsets.dumpDebug(proto, STABLE_INSETS);
chaviw9c81e632018-07-31 11:17:52 -0700351
chaviw553b0212018-07-12 13:37:01 -0700352 proto.end(token);
353 }
354
355 public void dump(PrintWriter pw, String prefix) {
chaviwc65fa582018-08-09 15:33:13 -0700356 pw.println(prefix + "Frames: containing="
357 + mContainingFrame.toShortString(sTmpSB)
358 + " parent=" + mParentFrame.toShortString(sTmpSB));
Jorim Jaggif081f062019-10-24 16:24:54 +0200359 pw.println(prefix + " display=" + mDisplayFrame.toShortString(sTmpSB));
chaviwc65fa582018-08-09 15:33:13 -0700360 pw.println(prefix + " content=" + mContentFrame.toShortString(sTmpSB)
361 + " visible=" + mVisibleFrame.toShortString(sTmpSB));
362 pw.println(prefix + " decor=" + mDecorFrame.toShortString(sTmpSB));
chaviwc65fa582018-08-09 15:33:13 -0700363 pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB)
364 + " last=" + mLastFrame.toShortString(sTmpSB));
365 pw.println(prefix + " cutout=" + mDisplayCutout.getDisplayCutout()
366 + " last=" + mLastDisplayCutout.getDisplayCutout());
Jorim Jaggif081f062019-10-24 16:24:54 +0200367 pw.print(prefix + "Cur insets: content=" + mContentInsets.toShortString(sTmpSB)
chaviw9c81e632018-07-31 11:17:52 -0700368 + " visible=" + mVisibleInsets.toShortString(sTmpSB)
Jorim Jaggif081f062019-10-24 16:24:54 +0200369 + " stable=" + mStableInsets.toShortString(sTmpSB));
370 pw.println(prefix + "Lst insets: content=" + mLastContentInsets.toShortString(sTmpSB)
chaviw9c81e632018-07-31 11:17:52 -0700371 + " visible=" + mLastVisibleInsets.toShortString(sTmpSB)
Jorim Jaggif081f062019-10-24 16:24:54 +0200372 + " stable=" + mLastStableInsets.toShortString(sTmpSB));
chaviw9c81e632018-07-31 11:17:52 -0700373 }
374
375 String getInsetsInfo() {
376 return "ci=" + mContentInsets.toShortString()
377 + " vi=" + mVisibleInsets.toShortString()
Jorim Jaggif081f062019-10-24 16:24:54 +0200378 + " si=" + mStableInsets.toShortString();
chaviw9c81e632018-07-31 11:17:52 -0700379 }
380
381 String getInsetsChangedInfo() {
382 return "contentInsetsChanged=" + mContentInsetsChanged
383 + " " + mContentInsets.toShortString()
384 + " visibleInsetsChanged=" + mVisibleInsetsChanged
385 + " " + mVisibleInsets.toShortString()
386 + " stableInsetsChanged=" + mStableInsetsChanged
387 + " " + mStableInsets.toShortString()
chaviw9c81e632018-07-31 11:17:52 -0700388 + " displayCutoutChanged=" + mDisplayCutoutChanged;
chaviw553b0212018-07-12 13:37:01 -0700389 }
chaviw553b0212018-07-12 13:37:01 -0700390}