1 /*
2  * Copyright (C) 2017 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 android.view.Surface.ROTATION_180;
20 import static android.view.Surface.ROTATION_270;
21 import static android.view.Surface.ROTATION_90;
22 import static com.android.server.wm.DisplayFramesProto.STABLE_BOUNDS;
23 
24 import android.annotation.NonNull;
25 import android.graphics.Rect;
26 import android.util.proto.ProtoOutputStream;
27 import android.view.DisplayCutout;
28 import android.view.DisplayInfo;
29 
30 import com.android.server.wm.utils.WmDisplayCutout;
31 
32 import java.io.PrintWriter;
33 
34 /**
35  * Container class for all the display frames that affect how we do window layout on a display.
36  * @hide
37  */
38 public class DisplayFrames {
39     public final int mDisplayId;
40 
41     /**
42      * The current size of the screen; really; extends into the overscan area of the screen and
43      * doesn't account for any system elements like the status bar.
44      */
45     public final Rect mOverscan = new Rect();
46 
47     /**
48      * The current visible size of the screen; really; (ir)regardless of whether the status bar can
49      * be hidden but not extending into the overscan area.
50      */
51     public final Rect mUnrestricted = new Rect();
52 
53     /** Like mOverscan*, but allowed to move into the overscan region where appropriate. */
54     public final Rect mRestrictedOverscan = new Rect();
55 
56     /**
57      * The current size of the screen; these may be different than (0,0)-(dw,dh) if the status bar
58      * can't be hidden; in that case it effectively carves out that area of the display from all
59      * other windows.
60      */
61     public final Rect mRestricted = new Rect();
62 
63     /**
64      * During layout, the current screen borders accounting for any currently visible system UI
65      * elements.
66      */
67     public final Rect mSystem = new Rect();
68 
69     /** For applications requesting stable content insets, these are them. */
70     public final Rect mStable = new Rect();
71 
72     /**
73      * For applications requesting stable content insets but have also set the fullscreen window
74      * flag, these are the stable dimensions without the status bar.
75      */
76     public final Rect mStableFullscreen = new Rect();
77 
78     /**
79      * During layout, the current screen borders with all outer decoration (status bar, input method
80      * dock) accounted for.
81      */
82     public final Rect mCurrent = new Rect();
83 
84     /**
85      * During layout, the frame in which content should be displayed to the user, accounting for all
86      * screen decoration except for any space they deem as available for other content. This is
87      * usually the same as mCurrent*, but may be larger if the screen decor has supplied content
88      * insets.
89      */
90     public final Rect mContent = new Rect();
91 
92     /**
93      * During layout, the frame in which voice content should be displayed to the user, accounting
94      * for all screen decoration except for any space they deem as available for other content.
95      */
96     public final Rect mVoiceContent = new Rect();
97 
98     /** During layout, the current screen borders along which input method windows are placed. */
99     public final Rect mDock = new Rect();
100 
101     /** The display cutout used for layout (after rotation) */
102     @NonNull public WmDisplayCutout mDisplayCutout = WmDisplayCutout.NO_CUTOUT;
103 
104     /** The cutout as supplied by display info */
105     @NonNull public WmDisplayCutout mDisplayInfoCutout = WmDisplayCutout.NO_CUTOUT;
106 
107     /**
108      * During layout, the frame that is display-cutout safe, i.e. that does not intersect with it.
109      */
110     public final Rect mDisplayCutoutSafe = new Rect();
111 
112     private final Rect mDisplayInfoOverscan = new Rect();
113     private final Rect mRotatedDisplayInfoOverscan = new Rect();
114     public int mDisplayWidth;
115     public int mDisplayHeight;
116 
117     public int mRotation;
118 
DisplayFrames(int displayId, DisplayInfo info, WmDisplayCutout displayCutout)119     public DisplayFrames(int displayId, DisplayInfo info, WmDisplayCutout displayCutout) {
120         mDisplayId = displayId;
121         onDisplayInfoUpdated(info, displayCutout);
122     }
123 
onDisplayInfoUpdated(DisplayInfo info, WmDisplayCutout displayCutout)124     public void onDisplayInfoUpdated(DisplayInfo info, WmDisplayCutout displayCutout) {
125         mDisplayWidth = info.logicalWidth;
126         mDisplayHeight = info.logicalHeight;
127         mRotation = info.rotation;
128         mDisplayInfoOverscan.set(
129                 info.overscanLeft, info.overscanTop, info.overscanRight, info.overscanBottom);
130         mDisplayInfoCutout = displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT;
131     }
132 
onBeginLayout()133     public void onBeginLayout() {
134         switch (mRotation) {
135             case ROTATION_90:
136                 mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.top;
137                 mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.right;
138                 mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.bottom;
139                 mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.left;
140                 break;
141             case ROTATION_180:
142                 mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.right;
143                 mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.bottom;
144                 mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.left;
145                 mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.top;
146                 break;
147             case ROTATION_270:
148                 mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.bottom;
149                 mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.left;
150                 mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.top;
151                 mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.right;
152                 break;
153             default:
154                 mRotatedDisplayInfoOverscan.set(mDisplayInfoOverscan);
155                 break;
156         }
157 
158         mRestrictedOverscan.set(0, 0, mDisplayWidth, mDisplayHeight);
159         mOverscan.set(mRestrictedOverscan);
160         mSystem.set(mRestrictedOverscan);
161         mUnrestricted.set(mRotatedDisplayInfoOverscan);
162         mUnrestricted.right = mDisplayWidth - mUnrestricted.right;
163         mUnrestricted.bottom = mDisplayHeight - mUnrestricted.bottom;
164         mRestricted.set(mUnrestricted);
165         mDock.set(mUnrestricted);
166         mContent.set(mUnrestricted);
167         mVoiceContent.set(mUnrestricted);
168         mStable.set(mUnrestricted);
169         mStableFullscreen.set(mUnrestricted);
170         mCurrent.set(mUnrestricted);
171 
172         mDisplayCutout = mDisplayInfoCutout;
173         mDisplayCutoutSafe.set(Integer.MIN_VALUE, Integer.MIN_VALUE,
174                 Integer.MAX_VALUE, Integer.MAX_VALUE);
175         if (!mDisplayCutout.getDisplayCutout().isEmpty()) {
176             final DisplayCutout c = mDisplayCutout.getDisplayCutout();
177             if (c.getSafeInsetLeft() > 0) {
178                 mDisplayCutoutSafe.left = mRestrictedOverscan.left + c.getSafeInsetLeft();
179             }
180             if (c.getSafeInsetTop() > 0) {
181                 mDisplayCutoutSafe.top = mRestrictedOverscan.top + c.getSafeInsetTop();
182             }
183             if (c.getSafeInsetRight() > 0) {
184                 mDisplayCutoutSafe.right = mRestrictedOverscan.right - c.getSafeInsetRight();
185             }
186             if (c.getSafeInsetBottom() > 0) {
187                 mDisplayCutoutSafe.bottom = mRestrictedOverscan.bottom - c.getSafeInsetBottom();
188             }
189         }
190     }
191 
getInputMethodWindowVisibleHeight()192     public int getInputMethodWindowVisibleHeight() {
193         return mDock.bottom - mCurrent.bottom;
194     }
195 
writeToProto(ProtoOutputStream proto, long fieldId)196     public void writeToProto(ProtoOutputStream proto, long fieldId) {
197         final long token = proto.start(fieldId);
198         mStable.writeToProto(proto, STABLE_BOUNDS);
199         proto.end(token);
200     }
201 
dump(String prefix, PrintWriter pw)202     public void dump(String prefix, PrintWriter pw) {
203         pw.println(prefix + "DisplayFrames w=" + mDisplayWidth + " h=" + mDisplayHeight
204                 + " r=" + mRotation);
205         final String myPrefix = prefix + "  ";
206         dumpFrame(mStable, "mStable", myPrefix, pw);
207         dumpFrame(mStableFullscreen, "mStableFullscreen", myPrefix, pw);
208         dumpFrame(mDock, "mDock", myPrefix, pw);
209         dumpFrame(mCurrent, "mCurrent", myPrefix, pw);
210         dumpFrame(mSystem, "mSystem", myPrefix, pw);
211         dumpFrame(mContent, "mContent", myPrefix, pw);
212         dumpFrame(mVoiceContent, "mVoiceContent", myPrefix, pw);
213         dumpFrame(mOverscan, "mOverscan", myPrefix, pw);
214         dumpFrame(mRestrictedOverscan, "mRestrictedOverscan", myPrefix, pw);
215         dumpFrame(mRestricted, "mRestricted", myPrefix, pw);
216         dumpFrame(mUnrestricted, "mUnrestricted", myPrefix, pw);
217         dumpFrame(mDisplayInfoOverscan, "mDisplayInfoOverscan", myPrefix, pw);
218         dumpFrame(mRotatedDisplayInfoOverscan, "mRotatedDisplayInfoOverscan", myPrefix, pw);
219         pw.println(myPrefix + "mDisplayCutout=" + mDisplayCutout);
220     }
221 
dumpFrame(Rect frame, String name, String prefix, PrintWriter pw)222     private void dumpFrame(Rect frame, String name, String prefix, PrintWriter pw) {
223         pw.print(prefix + name + "="); frame.printShortString(pw); pw.println();
224     }
225 }
226