• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.PARENT_FRAME;
27 import static com.android.server.wm.WindowFramesProto.STABLE_INSETS;
28 import static com.android.server.wm.WindowFramesProto.VISIBLE_FRAME;
29 import static com.android.server.wm.WindowFramesProto.VISIBLE_INSETS;
30 
31 import android.annotation.NonNull;
32 import android.graphics.Rect;
33 import android.util.proto.ProtoOutputStream;
34 import android.view.DisplayCutout;
35 
36 import com.android.server.wm.utils.InsetUtils;
37 import com.android.server.wm.utils.WmDisplayCutout;
38 
39 import java.io.PrintWriter;
40 
41 /**
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  */
46 public class WindowFrames {
47     private static final StringBuilder sTmpSB = new StringBuilder();
48 
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     /**
60      * The entire screen area of the {@link ActivityStack} this window is in. Usually equal to the
61      * screen area of the device.
62      *
63      * TODO(b/111611553): The name is unclear and most likely should be swapped with
64      * {@link #mParentFrame}
65      */
66     public final Rect mDisplayFrame = new Rect();
67 
68     /**
69      * 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     /**
93      * Similar to {@link #mDisplayFrame}
94      *
95      * TODO: Why is this different than mDisplayFrame
96      */
97     final Rect mContainingFrame = new Rect();
98 
99     /**
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 
109     /**
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 
119     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 
125     /**
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      */
138     private WmDisplayCutout mLastDisplayCutout = WmDisplayCutout.NO_CUTOUT;
139 
140     private boolean mDisplayCutoutChanged;
141 
142     /**
143      * 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     /**
151      * 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();
168 
169     private boolean mContentChanged;
170 
WindowFrames()171     public WindowFrames() {
172     }
173 
WindowFrames(Rect parentFrame, Rect displayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame)174     public WindowFrames(Rect parentFrame, Rect displayFrame, Rect contentFrame,
175             Rect visibleFrame, Rect decorFrame, Rect stableFrame) {
176         setFrames(parentFrame, displayFrame, contentFrame, visibleFrame, decorFrame,
177                 stableFrame);
178     }
179 
setFrames(Rect parentFrame, Rect displayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame)180     public void setFrames(Rect parentFrame, Rect displayFrame,
181             Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame) {
182         mParentFrame.set(parentFrame);
183         mDisplayFrame.set(displayFrame);
184         mContentFrame.set(contentFrame);
185         mVisibleFrame.set(visibleFrame);
186         mDecorFrame.set(decorFrame);
187         mStableFrame.set(stableFrame);
188     }
189 
setParentFrameWasClippedByDisplayCutout( boolean parentFrameWasClippedByDisplayCutout)190     public void setParentFrameWasClippedByDisplayCutout(
191             boolean parentFrameWasClippedByDisplayCutout) {
192         mParentFrameWasClippedByDisplayCutout = parentFrameWasClippedByDisplayCutout;
193     }
194 
parentFrameWasClippedByDisplayCutout()195     boolean parentFrameWasClippedByDisplayCutout() {
196         return mParentFrameWasClippedByDisplayCutout;
197     }
198 
setDisplayCutout(WmDisplayCutout displayCutout)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      */
didFrameSizeChange()206     private boolean didFrameSizeChange() {
207         return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
208     }
209 
210     // TODO(b/118118435): Remove after migration.
211     /**
212      * Calculate the insets for the type
213      * {@link android.view.WindowManager.LayoutParams#TYPE_DOCK_DIVIDER}
214      *
215      * @param cutoutInsets The insets for the cutout.
216      */
calculateDockedDividerInsets(Rect cutoutInsets)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      */
calculateInsets(boolean windowsAreFloating, boolean inFullscreenContainer, Rect windowBounds)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 
250         mTmpRect.set(mFrame.left, mFrame.top,
251                 overrideRightInset ? windowBounds.right : mFrame.right,
252                 overrideBottomInset ? windowBounds.bottom : mFrame.bottom);
253 
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      */
scaleInsets(float scale)264     void scaleInsets(float scale) {
265         mContentInsets.scale(scale);
266         mVisibleInsets.scale(scale);
267         mStableInsets.scale(scale);
268     }
269 
offsetFrames(int layoutXDiff, int layoutYDiff)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      */
setReportResizeHints()282     boolean setReportResizeHints() {
283         mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
284         mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets);
285         mStableInsetsChanged |= !mLastStableInsets.equals(mStableInsets);
286         mFrameSizeChanged |= didFrameSizeChange();
287         mDisplayCutoutChanged |= !mLastDisplayCutout.equals(mDisplayCutout);
288         return mContentInsetsChanged || mVisibleInsetsChanged
289                 || mStableInsetsChanged || mFrameSizeChanged
290                 || 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      */
resetInsetsChanged()297     void resetInsetsChanged() {
298         mContentInsetsChanged = false;
299         mVisibleInsetsChanged = false;
300         mStableInsetsChanged = false;
301         mFrameSizeChanged = false;
302         mDisplayCutoutChanged = false;
303     }
304 
305     /**
306      * Copy over inset values as the last insets that were sent to the client.
307      */
updateLastInsetValues()308     void updateLastInsetValues() {
309         mLastContentInsets.set(mContentInsets);
310         mLastVisibleInsets.set(mVisibleInsets);
311         mLastStableInsets.set(mStableInsets);
312         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      */
resetLastContentInsets()319     void resetLastContentInsets() {
320         mLastContentInsets.set(-1, -1, -1, -1);
321     }
322 
323     /**
324      * Sets whether the content has changed. This means that either the size or parent frame has
325      * changed.
326      */
setContentChanged(boolean contentChanged)327     public void setContentChanged(boolean contentChanged) {
328         mContentChanged = contentChanged;
329     }
330 
331     /**
332      * @see #setContentChanged(boolean)
333      */
hasContentChanged()334     boolean hasContentChanged() {
335         return mContentChanged;
336     }
337 
dumpDebug(@onNull ProtoOutputStream proto, long fieldId)338     public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) {
339         final long token = proto.start(fieldId);
340         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);
351 
352         proto.end(token);
353     }
354 
dump(PrintWriter pw, String prefix)355     public void dump(PrintWriter pw, String prefix) {
356         pw.println(prefix + "Frames: containing="
357                 + mContainingFrame.toShortString(sTmpSB)
358                 + " parent=" + mParentFrame.toShortString(sTmpSB));
359         pw.println(prefix + "    display=" + mDisplayFrame.toShortString(sTmpSB));
360         pw.println(prefix + "    content=" + mContentFrame.toShortString(sTmpSB)
361                 + " visible=" + mVisibleFrame.toShortString(sTmpSB));
362         pw.println(prefix + "    decor=" + mDecorFrame.toShortString(sTmpSB));
363         pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB)
364                 + " last=" + mLastFrame.toShortString(sTmpSB));
365         pw.println(prefix + " cutout=" + mDisplayCutout.getDisplayCutout()
366                 + " last=" + mLastDisplayCutout.getDisplayCutout());
367         pw.print(prefix + "Cur insets: content=" + mContentInsets.toShortString(sTmpSB)
368                 + " visible=" + mVisibleInsets.toShortString(sTmpSB)
369                 + " stable=" + mStableInsets.toShortString(sTmpSB));
370         pw.println(prefix + "Lst insets: content=" + mLastContentInsets.toShortString(sTmpSB)
371                 + " visible=" + mLastVisibleInsets.toShortString(sTmpSB)
372                 + " stable=" + mLastStableInsets.toShortString(sTmpSB));
373     }
374 
getInsetsInfo()375     String getInsetsInfo() {
376         return "ci=" + mContentInsets.toShortString()
377                 + " vi=" + mVisibleInsets.toShortString()
378                 + " si=" + mStableInsets.toShortString();
379     }
380 
getInsetsChangedInfo()381     String getInsetsChangedInfo() {
382         return "contentInsetsChanged=" + mContentInsetsChanged
383                 + " " + mContentInsets.toShortString()
384                 + " visibleInsetsChanged=" + mVisibleInsetsChanged
385                 + " " + mVisibleInsets.toShortString()
386                 + " stableInsetsChanged=" + mStableInsetsChanged
387                 + " " + mStableInsets.toShortString()
388                 + " displayCutoutChanged=" + mDisplayCutoutChanged;
389     }
390 }
391