blob: f8c1ad951fc3a85ad555c11087d2e23e353d6dc9 [file] [log] [blame]
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001/*
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
Tiger Huang7c610aa2018-10-27 00:01:01 +080019import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
Tiger Huangd5f0b9a2019-10-10 10:34:57 +020020import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
Tiger Huang7c610aa2018-10-27 00:01:01 +080021import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
24import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Tiger Huang7c610aa2018-10-27 00:01:01 +080025import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
26import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
Tiger Huang43b8fc22019-04-26 11:49:29 +080027import static android.view.Display.TYPE_BUILT_IN;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020028import static android.view.InsetsState.TYPE_TOP_BAR;
Adrian Roos11dfd272019-03-25 19:21:26 +010029import static android.view.InsetsState.TYPE_TOP_GESTURES;
30import static android.view.InsetsState.TYPE_TOP_TAPPABLE_ELEMENT;
Jorim Jaggid6490572019-04-16 14:57:56 +020031import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +080032import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
Jorim Jaggi956ca412019-01-07 14:49:14 +010033import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
Jorim Jaggi648e5882019-01-24 13:24:02 +010034import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
Jorim Jaggi956ca412019-01-07 14:49:14 +010035import static android.view.WindowInsetsController.APPEARANCE_LIGHT_TOP_BAR;
36import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
37import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080038import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
39import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
40import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
41import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
42import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
43import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
44import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
45import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
46import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
47import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
48import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
49import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
Adrian Roos11dfd272019-03-25 19:21:26 +010050import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080051import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
52import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
53import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
54import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
Tiger Huang7c610aa2018-10-27 00:01:01 +080055import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
Arthur Hung20479922019-02-27 17:13:22 +080056import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
Jorim Jaggia6aabac2019-03-11 14:23:16 -070057import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
Tiger Huang7c610aa2018-10-27 00:01:01 +080058import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +080059import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
60import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
61import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +080062import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
63import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
64import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
65import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
66import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
67import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
68import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
69import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
70import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
Charles Chen64172bb2019-04-22 17:30:29 +080071import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
Tiger Huang7c610aa2018-10-27 00:01:01 +080072import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
73import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
74import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
75import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
76import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
77import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
78import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
79import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
80import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
81import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
82import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
83import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
84import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
85import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
86import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
87import static android.view.WindowManagerGlobal.ADD_OKAY;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080088import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
89import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080090import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
91import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
92import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
93
94import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
95import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
96import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
97import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
98import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
99import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
100import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800101import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800102import static com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200103import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800104import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
105import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800106import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
107import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
108
Jorim Jaggi4981f152019-03-26 18:58:45 +0100109import android.Manifest.permission;
Issei Suzukia5dbf522019-02-01 17:58:15 +0100110import android.annotation.NonNull;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800111import android.annotation.Nullable;
Jorim Jaggi4981f152019-03-26 18:58:45 +0100112import android.annotation.Px;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800113import android.app.ActivityManager;
114import android.app.ActivityThread;
Winson Chungda20fec2019-04-10 12:19:59 -0700115import android.app.LoadedApk;
116import android.app.ResourcesManager;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800117import android.app.StatusBarManager;
118import android.content.Context;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800119import android.content.Intent;
Jorim Jaggi4981f152019-03-26 18:58:45 +0100120import android.content.pm.PackageManager;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800121import android.content.res.Resources;
Issei Suzukia5dbf522019-02-01 17:58:15 +0100122import android.graphics.Insets;
Arthur Hung20479922019-02-27 17:13:22 +0800123import android.graphics.PixelFormat;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800124import android.graphics.Rect;
Winson Chung36941632019-04-19 15:21:38 -0700125import android.graphics.Region;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800126import android.hardware.input.InputManager;
127import android.hardware.power.V1_0.PowerHint;
128import android.os.Handler;
129import android.os.Looper;
130import android.os.Message;
131import android.os.SystemClock;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800132import android.os.SystemProperties;
133import android.os.UserHandle;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800134import android.util.ArraySet;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100135import android.util.IntArray;
Tarandeep Singhe439dec2019-04-22 12:28:43 -0700136import android.util.Pair;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800137import android.util.PrintWriterPrinter;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800138import android.util.Slog;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800139import android.view.DisplayCutout;
140import android.view.Gravity;
141import android.view.IApplicationToken;
142import android.view.InputChannel;
143import android.view.InputDevice;
144import android.view.InputEvent;
145import android.view.InputEventReceiver;
Tiger Huang0dbd5372019-10-26 00:24:22 +0800146import android.view.InsetsFlags;
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200147import android.view.InsetsState;
Tiger Huang0dbd5372019-10-26 00:24:22 +0800148import android.view.InsetsState.InternalInsetType;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800149import android.view.MotionEvent;
150import android.view.PointerIcon;
151import android.view.Surface;
152import android.view.View;
Jorim Jaggi648e5882019-01-24 13:24:02 +0100153import android.view.ViewRootImpl;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100154import android.view.WindowInsets;
Tiger Huang0dbd5372019-10-26 00:24:22 +0800155import android.view.WindowInsetsController.Appearance;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800156import android.view.WindowManager;
157import android.view.WindowManager.LayoutParams;
158import android.view.WindowManagerGlobal;
159import android.view.WindowManagerPolicyConstants;
160import android.view.accessibility.AccessibilityManager;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800161
Tiger Huang7c610aa2018-10-27 00:01:01 +0800162import com.android.internal.R;
163import com.android.internal.annotations.GuardedBy;
164import com.android.internal.annotations.VisibleForTesting;
Tiger Huang43b8fc22019-04-26 11:49:29 +0800165import com.android.internal.policy.ScreenDecorationsUtils;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800166import com.android.internal.util.ScreenshotHelper;
Adrian Roos11dfd272019-03-25 19:21:26 +0100167import com.android.internal.util.function.TriConsumer;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100168import com.android.internal.view.AppearanceRegion;
Arthur Hung20479922019-02-27 17:13:22 +0800169import com.android.internal.widget.PointerLocationView;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800170import com.android.server.LocalServices;
171import com.android.server.UiThread;
172import com.android.server.policy.WindowManagerPolicy;
173import com.android.server.policy.WindowManagerPolicy.InputConsumer;
174import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800175import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
176import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800177import com.android.server.policy.WindowOrientationListener;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200178import com.android.server.protolog.common.ProtoLog;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800179import com.android.server.statusbar.StatusBarManagerInternal;
wilsonshih643bf132019-02-27 12:49:19 +0800180import com.android.server.wallpaper.WallpaperManagerInternal;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800181import com.android.server.wm.utils.InsetUtils;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800182
183import java.io.PrintWriter;
184
185/**
186 * The policy that provides the basic behaviors and states of a display to show UI.
187 */
188public class DisplayPolicy {
189 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800190 private static final boolean DEBUG = false;
191
192 private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
193
194 // The panic gesture may become active only after the keyguard is dismissed and the immersive
195 // app shows again. If that doesn't happen for 30s we drop the gesture.
196 private static final long PANIC_GESTURE_EXPIRATION = 30000;
197
198 // Controls navigation bar opacity depending on which workspace stacks are currently
199 // visible.
200 // Nav bar is always opaque when either the freeform stack or docked stack is visible.
201 private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
202 // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
203 private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
Adrian Roosfaba4062019-05-14 15:27:17 +0200204 // Nav bar is never forced opaque.
205 private static final int NAV_BAR_FORCE_TRANSPARENT = 2;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800206
Riddle Hsu2ca561b2019-10-08 21:58:58 +0800207 /** Don't apply window animation (see {@link #selectAnimation}). */
208 static final int ANIMATION_NONE = -1;
209 /** Use the transit animation in style resource (see {@link #selectAnimation}). */
210 static final int ANIMATION_STYLEABLE = 0;
211
Tiger Huang7c610aa2018-10-27 00:01:01 +0800212 /**
213 * These are the system UI flags that, when changing, can cause the layout
214 * of the screen to change.
215 */
216 private static final int SYSTEM_UI_CHANGING_LAYOUT =
217 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
218 | View.SYSTEM_UI_FLAG_FULLSCREEN
219 | View.STATUS_BAR_TRANSLUCENT
220 | View.NAVIGATION_BAR_TRANSLUCENT
221 | View.STATUS_BAR_TRANSPARENT
222 | View.NAVIGATION_BAR_TRANSPARENT;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800223
224 private final WindowManagerService mService;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800225 private final Context mContext;
226 private final DisplayContent mDisplayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800227 private final Object mLock;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800228 private final Handler mHandler;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800229
Winson Chungda20fec2019-04-10 12:19:59 -0700230 private Resources mCurrentUserResources;
231
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800232 private final boolean mCarDockEnablesAccelerometer;
233 private final boolean mDeskDockEnablesAccelerometer;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800234 private final AccessibilityManager mAccessibilityManager;
235 private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
236 private final ScreenshotHelper mScreenshotHelper;
237
238 private final Object mServiceAcquireLock = new Object();
239 private StatusBarManagerInternal mStatusBarManagerInternal;
240
Adrian Roos11dfd272019-03-25 19:21:26 +0100241 @Px
242 private int mBottomGestureAdditionalInset;
243 @Px
244 private int mSideGestureInset;
Adrian Roos11dfd272019-03-25 19:21:26 +0100245
Jorim Jaggi956ca412019-01-07 14:49:14 +0100246 StatusBarManagerInternal getStatusBarManagerInternal() {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800247 synchronized (mServiceAcquireLock) {
248 if (mStatusBarManagerInternal == null) {
249 mStatusBarManagerInternal =
250 LocalServices.getService(StatusBarManagerInternal.class);
251 }
252 return mStatusBarManagerInternal;
253 }
254 }
255
Tiger Huang7c610aa2018-10-27 00:01:01 +0800256 private final SystemGesturesPointerEventListener mSystemGestures;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800257
258 private volatile int mLidState = LID_ABSENT;
259 private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
260 private volatile boolean mHdmiPlugged;
261
Louis Changfc64c832018-12-04 11:38:26 +0800262 private volatile boolean mHasStatusBar;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800263 private volatile boolean mHasNavigationBar;
264 // Can the navigation bar ever move to the side?
265 private volatile boolean mNavigationBarCanMove;
Winson Chung36941632019-04-19 15:21:38 -0700266 private volatile boolean mNavigationBarLetsThroughTaps;
267 private volatile boolean mNavigationBarAlwaysShowOnSideGesture;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800268
269 // Written by vr manager thread, only read in this class.
270 private volatile boolean mPersistentVrModeEnabled;
271
272 private volatile boolean mAwake;
273 private volatile boolean mScreenOnEarly;
274 private volatile boolean mScreenOnFully;
275 private volatile ScreenOnListener mScreenOnListener;
276
277 private volatile boolean mKeyguardDrawComplete;
278 private volatile boolean mWindowManagerDrawComplete;
279
Tiger Huang7c610aa2018-10-27 00:01:01 +0800280 private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
281 private WindowState mStatusBar = null;
282 private final int[] mStatusBarHeightForRotation = new int[4];
283 private WindowState mNavigationBar = null;
284 @NavigationBarPosition
285 private int mNavigationBarPosition = NAV_BAR_BOTTOM;
286 private int[] mNavigationBarHeightForRotationDefault = new int[4];
287 private int[] mNavigationBarWidthForRotationDefault = new int[4];
288 private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
289 private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
290
Matthew Nga7f24bc2019-04-09 17:06:41 -0700291 /** See {@link #getNavigationBarFrameHeight} */
292 private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
293
HEO SEUNG22d3ec22019-05-30 20:28:53 +0900294 private boolean mIsFreeformWindowOverlappingWithNavBar;
295
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800296 private final StatusBarController mStatusBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800297
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800298 private final BarController mNavigationBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800299
300 private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
301 new BarController.OnBarVisibilityChangedListener() {
302 @Override
303 public void onBarVisibilityChanged(boolean visible) {
304 if (mAccessibilityManager == null) {
305 return;
306 }
307 mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
308 }
309 };
310
Tiger Huang7c610aa2018-10-27 00:01:01 +0800311 @GuardedBy("mHandler")
312 private SleepToken mDreamingSleepToken;
313
314 @GuardedBy("mHandler")
315 private SleepToken mWindowSleepToken;
316
317 private final Runnable mAcquireSleepTokenRunnable;
318 private final Runnable mReleaseSleepTokenRunnable;
319
320 // The windows we were told about in focusChanged.
321 private WindowState mFocusedWindow;
322 private WindowState mLastFocusedWindow;
323
324 IApplicationToken mFocusedApp;
325
326 int mLastSystemUiFlags;
327 // Bits that we are in the process of clearing, so we want to prevent
328 // them from being set by applications until everything has been updated
329 // to have them clear.
330 private int mResettingSystemUiFlags = 0;
331 // Bits that we are currently always keeping cleared.
332 private int mForceClearedSystemUiFlags = 0;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100333 private int mLastAppearance;
334 private int mLastFullscreenAppearance;
335 private int mLastDockedAppearance;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800336 private final Rect mNonDockedStackBounds = new Rect();
337 private final Rect mDockedStackBounds = new Rect();
338 private final Rect mLastNonDockedStackBounds = new Rect();
339 private final Rect mLastDockedStackBounds = new Rect();
340
Jorim Jaggi956ca412019-01-07 14:49:14 +0100341 // What we last reported to system UI about whether the focused window is fullscreen/immersive.
342 private boolean mLastFocusIsFullscreen = false;
343 private boolean mLastFocusIsImmersive = false;
344
Tiger Huang7c610aa2018-10-27 00:01:01 +0800345 // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
346 private long mPendingPanicGestureUptime;
347
348 private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
349 private static final Rect sTmpRect = new Rect();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800350 private static final Rect sTmpNavFrame = new Rect();
351 private static final Rect sTmpLastParentFrame = new Rect();
352
353 private WindowState mTopFullscreenOpaqueWindowState;
354 private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
355 private WindowState mTopDockedOpaqueWindowState;
356 private WindowState mTopDockedOpaqueOrDimmingWindowState;
357 private boolean mTopIsFullscreen;
358 private boolean mForceStatusBar;
359 private boolean mForceStatusBarFromKeyguard;
360 private boolean mForceStatusBarTransparent;
361 private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
362 private boolean mForcingShowNavBar;
363 private int mForcingShowNavBarLayer;
364 private boolean mForceShowSystemBars;
365
Brad Stenninge0573692019-03-11 13:52:46 -0700366 /**
367 * Force the display of system bars regardless of other settings.
368 */
369 private boolean mForceShowSystemBarsFromExternal;
370
Tiger Huang7c610aa2018-10-27 00:01:01 +0800371 private boolean mShowingDream;
372 private boolean mLastShowingDream;
373 private boolean mDreamingLockscreen;
374 private boolean mDreamingSleepTokenNeeded;
375 private boolean mWindowSleepTokenNeeded;
376 private boolean mLastWindowSleepTokenNeeded;
377 private boolean mAllowLockscreenWhenOn;
378
379 private InputConsumer mInputConsumer = null;
380
Arthur Hung20479922019-02-27 17:13:22 +0800381 private PointerLocationView mPointerLocationView;
382
Issei Suzukia5dbf522019-02-01 17:58:15 +0100383 /**
384 * The area covered by system windows which belong to another display. Forwarded insets is set
385 * in case this is a virtual display, this is displayed on another display that has insets, and
386 * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
387 * displayed on the host display, and it covers a part of this virtual display.)
388 * The forwarded insets is used to compute display frames of this virtual display, which will
389 * be then used to layout windows in the virtual display.
390 */
391 @NonNull private Insets mForwardedInsets = Insets.NONE;
392
Ady Abrahamf3e05312019-05-13 18:04:59 -0700393 private RefreshRatePolicy mRefreshRatePolicy;
394
Tiger Huang7c610aa2018-10-27 00:01:01 +0800395 // -------- PolicyHandler --------
396 private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
397 private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
398 private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
Arthur Hung20479922019-02-27 17:13:22 +0800399 private static final int MSG_ENABLE_POINTER_LOCATION = 4;
400 private static final int MSG_DISABLE_POINTER_LOCATION = 5;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800401
402 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
403 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
404
405 private class PolicyHandler extends Handler {
406
407 PolicyHandler(Looper looper) {
408 super(looper);
409 }
410
411 @Override
412 public void handleMessage(Message msg) {
413 switch (msg.what) {
414 case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
415 updateDreamingSleepToken(msg.arg1 != 0);
416 break;
417 case MSG_REQUEST_TRANSIENT_BARS:
418 WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
419 ? mStatusBar : mNavigationBar;
420 if (targetBar != null) {
421 requestTransientBars(targetBar);
422 }
423 break;
424 case MSG_DISPOSE_INPUT_CONSUMER:
425 disposeInputConsumer((InputConsumer) msg.obj);
426 break;
Arthur Hung20479922019-02-27 17:13:22 +0800427 case MSG_ENABLE_POINTER_LOCATION:
428 enablePointerLocation();
429 break;
430 case MSG_DISABLE_POINTER_LOCATION:
431 disablePointerLocation();
432 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800433 }
434 }
435 }
436
437 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800438 mService = service;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800439 mContext = displayContent.isDefaultDisplay ? service.mContext
440 : service.mContext.createDisplayContext(displayContent.getDisplay());
441 mDisplayContent = displayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800442 mLock = service.getWindowManagerLock();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800443
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800444 final int displayId = displayContent.getDisplayId();
445 mStatusBarController = new StatusBarController(displayId);
446 mNavigationBarController = new BarController("NavigationBar",
447 displayId,
448 View.NAVIGATION_BAR_TRANSIENT,
449 View.NAVIGATION_BAR_UNHIDE,
450 View.NAVIGATION_BAR_TRANSLUCENT,
451 StatusBarManager.WINDOW_NAVIGATION_BAR,
452 FLAG_TRANSLUCENT_NAVIGATION,
453 View.NAVIGATION_BAR_TRANSPARENT);
454
Tiger Huang7c610aa2018-10-27 00:01:01 +0800455 final Resources r = mContext.getResources();
456 mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
457 mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
Brad Stenninge0573692019-03-11 13:52:46 -0700458 mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800459
460 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
461 Context.ACCESSIBILITY_SERVICE);
462 if (!displayContent.isDefaultDisplay) {
463 mAwake = true;
464 mScreenOnEarly = true;
465 mScreenOnFully = true;
466 }
467
468 final Looper looper = UiThread.getHandler().getLooper();
469 mHandler = new PolicyHandler(looper);
470 mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
471 new SystemGesturesPointerEventListener.Callbacks() {
472 @Override
473 public void onSwipeFromTop() {
474 if (mStatusBar != null) {
475 requestTransientBars(mStatusBar);
476 }
477 }
478
479 @Override
480 public void onSwipeFromBottom() {
Winson Chung36941632019-04-19 15:21:38 -0700481 if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800482 requestTransientBars(mNavigationBar);
483 }
484 }
485
486 @Override
487 public void onSwipeFromRight() {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200488 final Region excludedRegion = Region.obtain();
Jeff Chang3cf3e562019-06-18 11:51:25 +0800489 synchronized (mLock) {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200490 mDisplayContent.calculateSystemGestureExclusion(
491 excludedRegion, null /* outUnrestricted */);
Jeff Chang3cf3e562019-06-18 11:51:25 +0800492 }
Winson Chung36941632019-04-19 15:21:38 -0700493 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
494 || mNavigationBarPosition == NAV_BAR_RIGHT;
495 if (mNavigationBar != null && sideAllowed
496 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800497 requestTransientBars(mNavigationBar);
498 }
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200499 excludedRegion.recycle();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800500 }
501
502 @Override
503 public void onSwipeFromLeft() {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200504 final Region excludedRegion = Region.obtain();
Jeff Chang3cf3e562019-06-18 11:51:25 +0800505 synchronized (mLock) {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200506 mDisplayContent.calculateSystemGestureExclusion(
507 excludedRegion, null /* outUnrestricted */);
Jeff Chang3cf3e562019-06-18 11:51:25 +0800508 }
Winson Chung36941632019-04-19 15:21:38 -0700509 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
510 || mNavigationBarPosition == NAV_BAR_LEFT;
511 if (mNavigationBar != null && sideAllowed
512 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800513 requestTransientBars(mNavigationBar);
514 }
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200515 excludedRegion.recycle();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800516 }
517
518 @Override
519 public void onFling(int duration) {
520 if (mService.mPowerManagerInternal != null) {
521 mService.mPowerManagerInternal.powerHint(
522 PowerHint.INTERACTION, duration);
523 }
524 }
525
526 @Override
527 public void onDebug() {
528 // no-op
529 }
530
531 private WindowOrientationListener getOrientationListener() {
532 final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
533 return rotation != null ? rotation.getOrientationListener() : null;
534 }
535
536 @Override
537 public void onDown() {
538 final WindowOrientationListener listener = getOrientationListener();
539 if (listener != null) {
540 listener.onTouchStart();
541 }
542 }
543
544 @Override
545 public void onUpOrCancel() {
546 final WindowOrientationListener listener = getOrientationListener();
547 if (listener != null) {
548 listener.onTouchEnd();
549 }
550 }
551
552 @Override
553 public void onMouseHoverAtTop() {
554 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
555 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
556 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
557 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
558 }
559
560 @Override
561 public void onMouseHoverAtBottom() {
562 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
563 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
564 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
565 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
566 }
567
568 @Override
569 public void onMouseLeaveFromEdge() {
570 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
571 }
572 });
573 displayContent.registerPointerEventListener(mSystemGestures);
574 displayContent.mAppTransition.registerListenerLocked(
575 mStatusBarController.getAppTransitionListener());
576 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
577 mService.mVrModeEnabled);
578 mAcquireSleepTokenRunnable = () -> {
579 if (mWindowSleepToken != null) {
580 return;
581 }
Tiger Huang7c610aa2018-10-27 00:01:01 +0800582 mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
583 "WindowSleepTokenOnDisplay" + displayId, displayId);
584 };
585 mReleaseSleepTokenRunnable = () -> {
586 if (mWindowSleepToken == null) {
587 return;
588 }
589 mWindowSleepToken.release();
590 mWindowSleepToken = null;
591 };
592
593 // TODO: Make it can take screenshot on external display
594 mScreenshotHelper = displayContent.isDefaultDisplay
595 ? new ScreenshotHelper(mContext) : null;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800596
Tiger Huang7c610aa2018-10-27 00:01:01 +0800597 if (mDisplayContent.isDefaultDisplay) {
Louis Changfc64c832018-12-04 11:38:26 +0800598 mHasStatusBar = true;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800599 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800600
Tiger Huang7c610aa2018-10-27 00:01:01 +0800601 // Allow a system property to override this. Used by the emulator.
602 // See also hasNavigationBar().
603 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
604 if ("1".equals(navBarOverride)) {
605 mHasNavigationBar = false;
606 } else if ("0".equals(navBarOverride)) {
607 mHasNavigationBar = true;
608 }
609 } else {
Louis Changfc64c832018-12-04 11:38:26 +0800610 mHasStatusBar = false;
Andrii Kuliandd989612019-02-21 12:13:28 -0800611 mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800612 }
Ady Abrahamf3e05312019-05-13 18:04:59 -0700613
614 mRefreshRatePolicy = new RefreshRatePolicy(mService,
615 mDisplayContent.getDisplayInfo(),
616 mService.mHighRefreshRateBlacklist);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800617 }
618
Charles Chen5bdd3e22018-12-18 17:51:56 +0800619 void systemReady() {
620 mSystemGestures.systemReady();
Arthur Hung20479922019-02-27 17:13:22 +0800621 if (mService.mPointerLocationEnabled) {
622 setPointerLocationEnabled(true);
623 }
Charles Chen5bdd3e22018-12-18 17:51:56 +0800624 }
625
626 private int getDisplayId() {
627 return mDisplayContent.getDisplayId();
628 }
629
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800630 public void setHdmiPlugged(boolean plugged) {
631 setHdmiPlugged(plugged, false /* force */);
632 }
633
634 public void setHdmiPlugged(boolean plugged, boolean force) {
635 if (force || mHdmiPlugged != plugged) {
636 mHdmiPlugged = plugged;
637 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
638 final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
639 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
640 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800641 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800642 }
643 }
644
645 boolean isHdmiPlugged() {
646 return mHdmiPlugged;
647 }
648
649 boolean isCarDockEnablesAccelerometer() {
650 return mCarDockEnablesAccelerometer;
651 }
652
653 boolean isDeskDockEnablesAccelerometer() {
654 return mDeskDockEnablesAccelerometer;
655 }
656
657 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
658 mPersistentVrModeEnabled = persistentVrModeEnabled;
659 }
660
661 public boolean isPersistentVrModeEnabled() {
662 return mPersistentVrModeEnabled;
663 }
664
665 public void setDockMode(int dockMode) {
666 mDockMode = dockMode;
667 }
668
669 public int getDockMode() {
670 return mDockMode;
671 }
672
Brad Stenninge0573692019-03-11 13:52:46 -0700673 /**
674 * @see WindowManagerService.setForceShowSystemBars
675 */
676 void setForceShowSystemBars(boolean forceShowSystemBars) {
677 mForceShowSystemBarsFromExternal = forceShowSystemBars;
678 }
679
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800680 public boolean hasNavigationBar() {
681 return mHasNavigationBar;
682 }
683
Louis Changfc64c832018-12-04 11:38:26 +0800684 public boolean hasStatusBar() {
685 return mHasStatusBar;
686 }
687
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200688 boolean hasSideGestures() {
689 return mHasNavigationBar && mSideGestureInset > 0;
690 }
691
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800692 public boolean navigationBarCanMove() {
693 return mNavigationBarCanMove;
694 }
695
696 public void setLidState(int lidState) {
697 mLidState = lidState;
698 }
699
700 public int getLidState() {
701 return mLidState;
702 }
703
704 public void setAwake(boolean awake) {
705 mAwake = awake;
706 }
707
708 public boolean isAwake() {
709 return mAwake;
710 }
711
712 public boolean isScreenOnEarly() {
713 return mScreenOnEarly;
714 }
715
716 public boolean isScreenOnFully() {
717 return mScreenOnFully;
718 }
719
720 public boolean isKeyguardDrawComplete() {
721 return mKeyguardDrawComplete;
722 }
723
724 public boolean isWindowManagerDrawComplete() {
725 return mWindowManagerDrawComplete;
726 }
727
728 public ScreenOnListener getScreenOnListener() {
729 return mScreenOnListener;
730 }
731
732 public void screenTurnedOn(ScreenOnListener screenOnListener) {
733 synchronized (mLock) {
734 mScreenOnEarly = true;
735 mScreenOnFully = false;
736 mKeyguardDrawComplete = false;
737 mWindowManagerDrawComplete = false;
738 mScreenOnListener = screenOnListener;
739 }
740 }
741
742 public void screenTurnedOff() {
743 synchronized (mLock) {
744 mScreenOnEarly = false;
745 mScreenOnFully = false;
746 mKeyguardDrawComplete = false;
747 mWindowManagerDrawComplete = false;
748 mScreenOnListener = null;
749 }
750 }
751
752 /** Return false if we are not awake yet or we have already informed of this event. */
753 public boolean finishKeyguardDrawn() {
754 synchronized (mLock) {
755 if (!mScreenOnEarly || mKeyguardDrawComplete) {
756 return false;
757 }
758
759 mKeyguardDrawComplete = true;
760 mWindowManagerDrawComplete = false;
761 }
762 return true;
763 }
764
765 /** Return false if screen is not turned on or we did already handle this case earlier. */
766 public boolean finishWindowsDrawn() {
767 synchronized (mLock) {
768 if (!mScreenOnEarly || mWindowManagerDrawComplete) {
769 return false;
770 }
771
772 mWindowManagerDrawComplete = true;
773 }
774 return true;
775 }
776
777 /** Return false if it is not ready to turn on. */
778 public boolean finishScreenTurningOn() {
779 synchronized (mLock) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200780 ProtoLog.d(WM_DEBUG_SCREEN_ON,
781 "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, "
782 + "mScreenOnFully=%b, mKeyguardDrawComplete=%b, "
783 + "mWindowManagerDrawComplete=%b",
784 mAwake, mScreenOnEarly, mScreenOnFully, mKeyguardDrawComplete,
785 mWindowManagerDrawComplete);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800786
787 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
788 || (mAwake && !mKeyguardDrawComplete)) {
789 return false;
790 }
791
Adrian Roosb125e0b2019-10-02 14:55:14 +0200792 ProtoLog.i(WM_DEBUG_SCREEN_ON, "Finished screen turning on...");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800793 mScreenOnListener = null;
794 mScreenOnFully = true;
795 }
796 return true;
797 }
798
Jorim Jaggi4981f152019-03-26 18:58:45 +0100799 private boolean hasStatusBarServicePermission(int pid, int uid) {
800 return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
801 == PackageManager.PERMISSION_GRANTED;
802 }
803
Tiger Huang7c610aa2018-10-27 00:01:01 +0800804 /**
805 * Sanitize the layout parameters coming from a client. Allows the policy
806 * to do things like ensure that windows of a specific type can't take
807 * input focus.
808 *
809 * @param attrs The window layout parameters to be modified. These values
810 * are modified in-place.
811 */
812 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
Jorim Jaggi4981f152019-03-26 18:58:45 +0100813 int callingPid, int callingUid) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800814
815 final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
816 if (mScreenDecorWindows.contains(win)) {
817 if (!isScreenDecor) {
818 // No longer has the flag set, so remove from the set.
819 mScreenDecorWindows.remove(win);
820 }
Jorim Jaggi4981f152019-03-26 18:58:45 +0100821 } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800822 mScreenDecorWindows.add(win);
823 }
824
825 switch (attrs.type) {
826 case TYPE_SYSTEM_OVERLAY:
827 case TYPE_SECURE_SYSTEM_OVERLAY:
828 // These types of windows can't receive input events.
829 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
830 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
831 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
832 break;
833 case TYPE_DREAM:
834 case TYPE_WALLPAPER:
835 // Dreams and wallpapers don't have an app window token and can thus not be
836 // letterboxed. Hence always let them extend under the cutout.
Arthur Hung20479922019-02-27 17:13:22 +0800837 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800838 break;
839 case TYPE_STATUS_BAR:
840
841 // If the Keyguard is in a hidden state (occluded by another window), we force to
842 // remove the wallpaper and keyguard flag so that any change in-flight after setting
843 // the keyguard as occluded wouldn't set these flags again.
844 // See {@link #processKeyguardSetHiddenResultLw}.
845 if (mService.mPolicy.isKeyguardOccluded()) {
846 attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
847 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
848 }
849 break;
850
851 case TYPE_SCREENSHOT:
852 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
853 break;
854
855 case TYPE_TOAST:
856 // While apps should use the dedicated toast APIs to add such windows
857 // it possible legacy apps to add the window directly. Therefore, we
858 // make windows added directly by the app behave as a toast as much
859 // as possible in terms of timeout and animation.
860 if (attrs.hideTimeoutMilliseconds < 0
861 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
862 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
863 }
Rhed Jao406d3a22018-11-30 19:28:58 +0800864 // Accessibility users may need longer timeout duration. This api compares
865 // original timeout with user's preference and return longer one. It returns
866 // original timeout if there's no preference.
867 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
868 (int) attrs.hideTimeoutMilliseconds,
869 AccessibilityManager.FLAG_CONTENT_TEXT);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800870 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
Jeff Changb10fac72019-04-09 17:28:30 +0800871 // Toast can show with below conditions when the screen is locked.
872 if (canToastShowWhenLocked(callingPid)) {
873 attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
874 }
Bernardo Rufino974de952019-10-22 11:53:42 +0100875 // Toasts can't be clickable
876 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800877 break;
878 }
879
880 if (attrs.type != TYPE_STATUS_BAR) {
881 // The status bar is the only window allowed to exhibit keyguard behavior.
882 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
883 }
884 }
885
886 /**
Jeff Changb10fac72019-04-09 17:28:30 +0800887 * @return {@code true} if the calling activity initiate toast and is visible with
888 * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
889 */
890 boolean canToastShowWhenLocked(int callingPid) {
891 return mDisplayContent.forAllWindows(w -> {
892 return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
893 }, true /* traverseTopToBottom */);
894 }
895
896 /**
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800897 * Check if a window can be added to the system.
Tiger Huang7c610aa2018-10-27 00:01:01 +0800898 *
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800899 * Currently enforces that two window types are singletons per display:
Tiger Huang7c610aa2018-10-27 00:01:01 +0800900 * <ul>
901 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
902 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
903 * </ul>
904 *
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800905 * @param attrs Information about the window to be added.
Tiger Huang7c610aa2018-10-27 00:01:01 +0800906 *
907 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
908 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
909 */
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800910 int validateAddingWindowLw(WindowManager.LayoutParams attrs) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800911 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
912 mContext.enforceCallingOrSelfPermission(
913 android.Manifest.permission.STATUS_BAR_SERVICE,
914 "DisplayPolicy");
Tiger Huang7c610aa2018-10-27 00:01:01 +0800915 }
916
917 switch (attrs.type) {
918 case TYPE_STATUS_BAR:
919 mContext.enforceCallingOrSelfPermission(
920 android.Manifest.permission.STATUS_BAR_SERVICE,
921 "DisplayPolicy");
922 if (mStatusBar != null) {
923 if (mStatusBar.isAlive()) {
924 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
925 }
926 }
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800927 break;
928 case TYPE_NAVIGATION_BAR:
929 mContext.enforceCallingOrSelfPermission(
930 android.Manifest.permission.STATUS_BAR_SERVICE,
931 "DisplayPolicy");
932 if (mNavigationBar != null) {
933 if (mNavigationBar.isAlive()) {
934 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
935 }
936 }
937 break;
938 case TYPE_NAVIGATION_BAR_PANEL:
939 case TYPE_STATUS_BAR_PANEL:
940 case TYPE_STATUS_BAR_SUB_PANEL:
941 case TYPE_VOICE_INTERACTION_STARTING:
942 mContext.enforceCallingOrSelfPermission(
943 android.Manifest.permission.STATUS_BAR_SERVICE,
944 "DisplayPolicy");
945 break;
946 }
947 return ADD_OKAY;
948 }
949
950 /**
951 * Called when a window is being added to the system. Must not throw an exception.
952 *
953 * @param win The window being added.
954 * @param attrs Information about the window to be added.
955 */
956 void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
957 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
958 mScreenDecorWindows.add(win);
959 }
960
961 switch (attrs.type) {
962 case TYPE_STATUS_BAR:
Tiger Huang7c610aa2018-10-27 00:01:01 +0800963 mStatusBar = win;
964 mStatusBarController.setWindow(win);
965 if (mDisplayContent.isDefaultDisplay) {
966 mService.mPolicy.setKeyguardCandidateLw(win);
967 }
Adrian Roos11dfd272019-03-25 19:21:26 +0100968 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200969 (displayFrames, windowState, rect) -> {
970 rect.top = 0;
971 rect.bottom = getStatusBarHeight(displayFrames);
Adrian Roos11dfd272019-03-25 19:21:26 +0100972 };
973 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, frameProvider);
974 mDisplayContent.setInsetProvider(TYPE_TOP_GESTURES, win, frameProvider);
975 mDisplayContent.setInsetProvider(TYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800976 break;
977 case TYPE_NAVIGATION_BAR:
Tiger Huang7c610aa2018-10-27 00:01:01 +0800978 mNavigationBar = win;
979 mNavigationBarController.setWindow(win);
980 mNavigationBarController.setOnBarVisibilityChangedListener(
981 mNavBarVisibilityListener, true);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200982 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR,
983 win, null /* frameProvider */);
Adrian Roos11dfd272019-03-25 19:21:26 +0100984 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_GESTURES, win,
985 (displayFrames, windowState, inOutFrame) -> {
986 inOutFrame.top -= mBottomGestureAdditionalInset;
987 });
988 mDisplayContent.setInsetProvider(InsetsState.TYPE_LEFT_GESTURES, win,
989 (displayFrames, windowState, inOutFrame) -> {
990 inOutFrame.left = 0;
991 inOutFrame.top = 0;
992 inOutFrame.bottom = displayFrames.mDisplayHeight;
993 inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
994 });
995 mDisplayContent.setInsetProvider(InsetsState.TYPE_RIGHT_GESTURES, win,
996 (displayFrames, windowState, inOutFrame) -> {
997 inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
998 inOutFrame.top = 0;
999 inOutFrame.bottom = displayFrames.mDisplayHeight;
1000 inOutFrame.right = displayFrames.mDisplayWidth;
1001 });
1002 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_TAPPABLE_ELEMENT, win,
1003 (displayFrames, windowState, inOutFrame) -> {
1004 if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
1005 || mNavigationBarLetsThroughTaps) {
1006 inOutFrame.setEmpty();
1007 }
1008 });
Tiger Huang7c610aa2018-10-27 00:01:01 +08001009 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
1010 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001011 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001012 }
1013
1014 /**
1015 * Called when a window is being removed from a window manager. Must not
1016 * throw an exception -- clean up as much as possible.
1017 *
1018 * @param win The window being removed.
1019 */
Tiger Huang5f6cbca2019-07-18 19:00:01 +08001020 void removeWindowLw(WindowState win) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001021 if (mStatusBar == win) {
1022 mStatusBar = null;
1023 mStatusBarController.setWindow(null);
1024 if (mDisplayContent.isDefaultDisplay) {
1025 mService.mPolicy.setKeyguardCandidateLw(null);
1026 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001027 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001028 } else if (mNavigationBar == win) {
1029 mNavigationBar = null;
1030 mNavigationBarController.setWindow(null);
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001031 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001032 }
1033 if (mLastFocusedWindow == win) {
1034 mLastFocusedWindow = null;
1035 }
1036 mScreenDecorWindows.remove(win);
1037 }
1038
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001039 private int getStatusBarHeight(DisplayFrames displayFrames) {
1040 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1041 displayFrames.mDisplayCutoutSafe.top);
1042 }
1043
Jorim Jaggi28620472019-01-02 23:21:49 +01001044 WindowState getStatusBar() {
1045 return mStatusBar;
1046 }
1047
1048 WindowState getNavigationBar() {
1049 return mNavigationBar;
1050 }
1051
Tiger Huang7c610aa2018-10-27 00:01:01 +08001052 /**
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001053 * Control the animation to run when a window's state changes. Return a positive number to
1054 * force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the
1055 * style resource defining the animation, or {@link #ANIMATION_NONE} for no animation.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001056 *
1057 * @param win The window that is changing.
1058 * @param transit What is happening to the window:
1059 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1060 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1061 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1062 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1063 *
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001064 * @return Resource ID of the actual animation to use, or {@link #ANIMATION_NONE} for none.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001065 */
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001066 int selectAnimation(WindowState win, int transit) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001067 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1068 + ": transit=" + transit);
1069 if (win == mStatusBar) {
1070 final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
1071 final boolean expanded = win.getAttrs().height == MATCH_PARENT
1072 && win.getAttrs().width == MATCH_PARENT;
1073 if (isKeyguard || expanded) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001074 return ANIMATION_NONE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001075 }
1076 if (transit == TRANSIT_EXIT
1077 || transit == TRANSIT_HIDE) {
1078 return R.anim.dock_top_exit;
1079 } else if (transit == TRANSIT_ENTER
1080 || transit == TRANSIT_SHOW) {
1081 return R.anim.dock_top_enter;
1082 }
1083 } else if (win == mNavigationBar) {
1084 if (win.getAttrs().windowAnimations != 0) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001085 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001086 }
1087 // This can be on either the bottom or the right or the left.
1088 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1089 if (transit == TRANSIT_EXIT
1090 || transit == TRANSIT_HIDE) {
1091 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1092 return R.anim.dock_bottom_exit_keyguard;
1093 } else {
1094 return R.anim.dock_bottom_exit;
1095 }
1096 } else if (transit == TRANSIT_ENTER
1097 || transit == TRANSIT_SHOW) {
1098 return R.anim.dock_bottom_enter;
1099 }
1100 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1101 if (transit == TRANSIT_EXIT
1102 || transit == TRANSIT_HIDE) {
1103 return R.anim.dock_right_exit;
1104 } else if (transit == TRANSIT_ENTER
1105 || transit == TRANSIT_SHOW) {
1106 return R.anim.dock_right_enter;
1107 }
1108 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1109 if (transit == TRANSIT_EXIT
1110 || transit == TRANSIT_HIDE) {
1111 return R.anim.dock_left_exit;
1112 } else if (transit == TRANSIT_ENTER
1113 || transit == TRANSIT_SHOW) {
1114 return R.anim.dock_left_enter;
1115 }
1116 }
1117 } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001118 return selectDockedDividerAnimation(win, transit);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001119 }
1120
1121 if (transit == TRANSIT_PREVIEW_DONE) {
1122 if (win.hasAppShownWindows()) {
1123 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1124 return R.anim.app_starting_exit;
1125 }
1126 } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
1127 && transit == TRANSIT_ENTER) {
1128 // Special case: we are animating in a dream, while the keyguard
1129 // is shown. We don't want an animation on the dream, because
1130 // we need it shown immediately with the keyguard animating away
1131 // to reveal it.
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001132 return ANIMATION_NONE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001133 }
1134
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001135 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001136 }
1137
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001138 private int selectDockedDividerAnimation(WindowState win, int transit) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001139 int insets = mDisplayContent.getDockedDividerController().getContentInsets();
1140
1141 // If the divider is behind the navigation bar, don't animate.
1142 final Rect frame = win.getFrameLw();
1143 final boolean behindNavBar = mNavigationBar != null
1144 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
1145 && frame.top + insets >= mNavigationBar.getFrameLw().top)
1146 || (mNavigationBarPosition == NAV_BAR_RIGHT
1147 && frame.left + insets >= mNavigationBar.getFrameLw().left)
1148 || (mNavigationBarPosition == NAV_BAR_LEFT
1149 && frame.right - insets <= mNavigationBar.getFrameLw().right));
1150 final boolean landscape = frame.height() > frame.width();
1151 final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
1152 || frame.left + insets >= win.getDisplayFrameLw().right);
1153 final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
1154 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1155 final boolean offscreen = offscreenLandscape || offscreenPortrait;
1156 if (behindNavBar || offscreen) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001157 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001158 }
1159 if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1160 return R.anim.fade_in;
1161 } else if (transit == TRANSIT_EXIT) {
1162 return R.anim.fade_out;
1163 } else {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001164 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001165 }
1166 }
1167
1168 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08001169 * Called when a new system UI visibility is being reported, allowing
1170 * the policy to adjust what is actually reported.
1171 * @param visibility The raw visibility reported by the status bar.
1172 * @return The new desired visibility.
1173 */
1174 public int adjustSystemUiVisibilityLw(int visibility) {
1175 mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1176 mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1177
1178 // Reset any bits in mForceClearingStatusBarVisibility that
1179 // are now clear.
1180 mResettingSystemUiFlags &= visibility;
1181 // Clear any bits in the new visibility that are currently being
1182 // force cleared, before reporting it.
1183 return visibility & ~mResettingSystemUiFlags
1184 & ~mForceClearedSystemUiFlags;
1185 }
1186
1187 /**
Brad Stenninge0573692019-03-11 13:52:46 -07001188 * @return true if the system bars are forced to stay visible
Tiger Huang7c610aa2018-10-27 00:01:01 +08001189 */
Brad Stenninge0573692019-03-11 13:52:46 -07001190 public boolean areSystemBarsForcedShownLw(WindowState windowState) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001191 return mForceShowSystemBars;
1192 }
1193
1194 // TODO: Should probably be moved into DisplayFrames.
1195 /**
1196 * Return the layout hints for a newly added window. These values are computed on the
1197 * most recent layout, so they are not guaranteed to be correct.
1198 *
1199 * @param attrs The LayoutParams of the window.
1200 * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1201 * associated with the window.
1202 * @param displayFrames display frames.
1203 * @param floatingStack Whether the window's stack is floating.
1204 * @param outFrame The frame of the window.
1205 * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1206 * @param outStableInsets The areas covered by stable system windows irrespective of their
1207 * current visibility. Expressed as positive insets.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001208 * @param outDisplayCutout The area that has been cut away from the display.
Brad Stenninge0573692019-03-11 13:52:46 -07001209 * @return Whether to always consume the system bars.
1210 * See {@link #areSystemBarsForcedShownLw(WindowState)}.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001211 */
1212 public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1213 DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1214 Rect outContentInsets, Rect outStableInsets,
Jorim Jaggif081f062019-10-24 16:24:54 +02001215 DisplayCutout.ParcelableWrapper outDisplayCutout) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001216 final int fl = PolicyControl.getWindowFlags(null, attrs);
1217 final int pfl = attrs.privateFlags;
1218 final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1219 final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001220
1221 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1222 final boolean layoutInScreenAndInsetDecor = layoutInScreen
1223 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1224 final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1225
1226 if (layoutInScreenAndInsetDecor && !screenDecor) {
Jorim Jaggid6490572019-04-16 14:57:56 +02001227 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001228 outFrame.set(displayFrames.mUnrestricted);
1229 } else {
1230 outFrame.set(displayFrames.mRestricted);
1231 }
1232
1233 final Rect sf;
1234 if (floatingStack) {
1235 sf = null;
1236 } else {
1237 sf = displayFrames.mStable;
1238 }
1239
1240 final Rect cf;
1241 if (floatingStack) {
1242 cf = null;
1243 } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1244 if ((fl & FLAG_FULLSCREEN) != 0) {
1245 cf = displayFrames.mStableFullscreen;
1246 } else {
1247 cf = displayFrames.mStable;
1248 }
Jorim Jaggif081f062019-10-24 16:24:54 +02001249 } else if ((fl & FLAG_FULLSCREEN) != 0) {
1250 cf = displayFrames.mUnrestricted;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001251 } else {
1252 cf = displayFrames.mCurrent;
1253 }
1254
1255 if (taskBounds != null) {
1256 outFrame.intersect(taskBounds);
1257 }
1258 InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1259 InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1260 outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1261 .getDisplayCutout());
1262 return mForceShowSystemBars;
1263 } else {
1264 if (layoutInScreen) {
1265 outFrame.set(displayFrames.mUnrestricted);
1266 } else {
1267 outFrame.set(displayFrames.mStable);
1268 }
1269 if (taskBounds != null) {
1270 outFrame.intersect(taskBounds);
1271 }
1272
1273 outContentInsets.setEmpty();
1274 outStableInsets.setEmpty();
1275 outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1276 return mForceShowSystemBars;
1277 }
1278 }
1279
1280 private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1281 int impliedFlags = 0;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001282 final boolean forceWindowDrawsBarBackgrounds =
1283 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1284 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001285 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001286 || forceWindowDrawsBarBackgrounds) {
Jorim Jaggid6490572019-04-16 14:57:56 +02001287 impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001288 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1289 }
1290 return impliedFlags;
1291 }
1292
Tiger Huang7c610aa2018-10-27 00:01:01 +08001293 private final Runnable mClearHideNavigationFlag = new Runnable() {
1294 @Override
1295 public void run() {
1296 synchronized (mLock) {
1297 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1298 mDisplayContent.reevaluateStatusBarVisibility();
1299 }
1300 }
1301 };
1302
1303 /**
1304 * Input handler used while nav bar is hidden. Captures any touch on the screen,
1305 * to determine when the nav bar should be shown and prevent applications from
1306 * receiving those touches.
1307 */
1308 private final class HideNavInputEventReceiver extends InputEventReceiver {
1309 HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1310 super(inputChannel, looper);
1311 }
1312
1313 @Override
1314 public void onInputEvent(InputEvent event) {
1315 try {
1316 if (event instanceof MotionEvent
1317 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1318 final MotionEvent motionEvent = (MotionEvent) event;
1319 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1320 // When the user taps down, we re-show the nav bar.
1321 boolean changed = false;
1322 synchronized (mLock) {
1323 if (mInputConsumer == null) {
1324 return;
1325 }
1326 // Any user activity always causes us to show the
1327 // navigation controls, if they had been hidden.
1328 // We also clear the low profile and only content
1329 // flags so that tapping on the screen will atomically
1330 // restore all currently hidden screen decorations.
1331 int newVal = mResettingSystemUiFlags
1332 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1333 | View.SYSTEM_UI_FLAG_LOW_PROFILE
1334 | View.SYSTEM_UI_FLAG_FULLSCREEN;
1335 if (mResettingSystemUiFlags != newVal) {
1336 mResettingSystemUiFlags = newVal;
1337 changed = true;
1338 }
1339 // We don't allow the system's nav bar to be hidden
1340 // again for 1 second, to prevent applications from
1341 // spamming us and keeping it from being shown.
1342 newVal = mForceClearedSystemUiFlags
1343 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1344 if (mForceClearedSystemUiFlags != newVal) {
1345 mForceClearedSystemUiFlags = newVal;
1346 changed = true;
1347 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1348 }
1349 if (changed) {
1350 mDisplayContent.reevaluateStatusBarVisibility();
1351 }
1352 }
1353 }
1354 }
1355 } finally {
1356 finishInputEvent(event, false /* handled */);
1357 }
1358 }
1359 }
1360
1361 /**
1362 * Called when layout of the windows is about to start.
1363 *
1364 * @param displayFrames frames of the display we are doing layout on.
1365 * @param uiMode The current uiMode in configuration.
1366 */
1367 public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1368 displayFrames.onBeginLayout();
1369 mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1370 mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1371
1372 // For purposes of putting out fake window up to steal focus, we will
1373 // drive nav being hidden only by whether it is requested.
1374 final int sysui = mLastSystemUiFlags;
1375 boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
1376 boolean navTranslucent = (sysui
1377 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
1378 boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
1379 boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
1380 boolean navAllowedHidden = immersive || immersiveSticky;
1381 navTranslucent &= !immersiveSticky; // transient trumps translucent
1382 boolean isKeyguardShowing = isStatusBarKeyguard()
1383 && !mService.mPolicy.isKeyguardOccluded();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001384 boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
1385 && (mStatusBar.getAttrs().privateFlags
1386 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1387
1388 // When the navigation bar isn't visible, we put up a fake input window to catch all
1389 // touch events. This way we can detect when the user presses anywhere to bring back the
1390 // nav bar and ensure the application doesn't see the event.
1391 if (navVisible || navAllowedHidden) {
1392 if (mInputConsumer != null) {
1393 mHandler.sendMessage(
1394 mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1395 mInputConsumer = null;
1396 }
1397 } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1398 mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1399 INPUT_CONSUMER_NAVIGATION,
1400 HideNavInputEventReceiver::new,
1401 displayFrames.mDisplayId);
1402 // As long as mInputConsumer is active, hover events are not dispatched to the app
1403 // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1404 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1405 }
1406
1407 // For purposes of positioning and showing the nav bar, if we have decided that it can't
1408 // be hidden (because of the screen aspect ratio), then take that into account.
1409 navVisible |= !canHideNavigationBar();
1410
1411 boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
1412 navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
1413 if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1414 updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1415 if (updateSysUiVisibility) {
1416 updateSystemUiVisibilityLw();
1417 }
1418 layoutScreenDecorWindows(displayFrames);
1419
1420 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1421 // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1422 // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1423 // bar.
1424 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1425 displayFrames.mStable.top);
1426 }
Issei Suzukia5dbf522019-02-01 17:58:15 +01001427
1428 // In case this is a virtual display, and the host display has insets that overlap this
1429 // virtual display, apply the insets of the overlapped area onto the current and content
1430 // frame of this virtual display. This let us layout windows in the virtual display as
1431 // expected when the window needs to avoid overlap with the system windows.
1432 // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1433 // IME.
1434 displayFrames.mCurrent.inset(mForwardedInsets);
1435 displayFrames.mContent.inset(mForwardedInsets);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001436 }
1437
1438 private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1439 if (mScreenDecorWindows.isEmpty()) {
1440 return;
1441 }
1442
1443 sTmpRect.setEmpty();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001444 final int displayId = displayFrames.mDisplayId;
1445 final Rect dockFrame = displayFrames.mDock;
1446 final int displayHeight = displayFrames.mDisplayHeight;
1447 final int displayWidth = displayFrames.mDisplayWidth;
1448
1449 for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1450 final WindowState w = mScreenDecorWindows.valueAt(i);
1451 if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1452 // Skip if not on the same display or not visible.
1453 continue;
1454 }
1455
chaviw0d833762019-06-20 17:09:53 -07001456 w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1457 displayFrames.mUnrestricted /* displayFrame */,
chaviw0d833762019-06-20 17:09:53 -07001458 displayFrames.mUnrestricted /* contentFrame */,
1459 displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001460 displayFrames.mUnrestricted /* stableFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001461 w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1462 w.computeFrameLw();
1463 final Rect frame = w.getFrameLw();
1464
1465 if (frame.left <= 0 && frame.top <= 0) {
1466 // Docked at left or top.
1467 if (frame.bottom >= displayHeight) {
1468 // Docked left.
1469 dockFrame.left = Math.max(frame.right, dockFrame.left);
1470 } else if (frame.right >= displayWidth) {
1471 // Docked top.
1472 dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1473 } else {
1474 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1475 + " not docked on left or top of display. frame=" + frame
1476 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1477 }
1478 } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1479 // Docked at right or bottom.
1480 if (frame.top <= 0) {
1481 // Docked right.
1482 dockFrame.right = Math.min(frame.left, dockFrame.right);
1483 } else if (frame.left <= 0) {
1484 // Docked bottom.
1485 dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1486 } else {
1487 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1488 + " not docked on right or bottom" + " of display. frame=" + frame
1489 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1490 }
1491 } else {
1492 // Screen decor windows are required to be docked on one of the sides of the screen.
1493 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1494 + " not docked on one of the sides of the display. frame=" + frame
1495 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1496 }
1497 }
1498
1499 displayFrames.mRestricted.set(dockFrame);
1500 displayFrames.mCurrent.set(dockFrame);
1501 displayFrames.mVoiceContent.set(dockFrame);
1502 displayFrames.mSystem.set(dockFrame);
1503 displayFrames.mContent.set(dockFrame);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001504 }
1505
1506 private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1507 boolean isKeyguardShowing) {
1508 // decide where the status bar goes ahead of time
1509 if (mStatusBar == null) {
1510 return false;
1511 }
1512 // apply any navigation bar insets
1513 sTmpRect.setEmpty();
Jorim Jaggi4981f152019-03-26 18:58:45 +01001514 final WindowFrames windowFrames = mStatusBar.getWindowFrames();
1515 windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001516 displayFrames.mUnrestricted /* displayFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001517 displayFrames.mStable /* contentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001518 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001519 displayFrames.mStable /* stableFrame */);
Jorim Jaggi4981f152019-03-26 18:58:45 +01001520 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001521
1522 // Let the status bar determine its size.
1523 mStatusBar.computeFrameLw();
1524
1525 // For layout, the status bar is always at the top with our fixed height.
1526 displayFrames.mStable.top = displayFrames.mUnrestricted.top
1527 + mStatusBarHeightForRotation[displayFrames.mRotation];
1528 // Make sure the status bar covers the entire cutout height
1529 displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1530 displayFrames.mDisplayCutoutSafe.top);
1531
1532 // Tell the bar controller where the collapsed status bar content is
1533 sTmpRect.set(mStatusBar.getContentFrameLw());
1534 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1535 sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
1536 sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
1537 mStatusBarController.setContentFrame(sTmpRect);
1538
1539 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
1540 boolean statusBarTranslucent = (sysui
1541 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001542
1543 // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1544 if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1545 // Status bar may go away, so the screen area it occupies is available to apps but just
1546 // covering them when the status bar is visible.
1547 final Rect dockFrame = displayFrames.mDock;
1548 dockFrame.top = displayFrames.mStable.top;
1549 displayFrames.mContent.set(dockFrame);
1550 displayFrames.mVoiceContent.set(dockFrame);
1551 displayFrames.mCurrent.set(dockFrame);
1552
1553 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1554 "dock=%s content=%s cur=%s", dockFrame.toString(),
1555 displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1556
Jorim Jaggi4981f152019-03-26 18:58:45 +01001557 if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
1558 && !mStatusBar.isAnimatingLw()) {
1559
Tiger Huang7c610aa2018-10-27 00:01:01 +08001560 // If the opaque status bar is currently requested to be visible, and not in the
1561 // process of animating on or off, then we can tell the app that it is covered by
1562 // it.
1563 displayFrames.mSystem.top = displayFrames.mStable.top;
1564 }
1565 }
1566 return mStatusBarController.checkHiddenLw();
1567 }
1568
1569 private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1570 boolean navTranslucent, boolean navAllowedHidden,
1571 boolean statusBarForcesShowingNavigation) {
1572 if (mNavigationBar == null) {
1573 return false;
1574 }
1575
1576 final Rect navigationFrame = sTmpNavFrame;
1577 boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1578 // Force the navigation bar to its appropriate place and size. We need to do this directly,
1579 // instead of relying on it to bubble up from the nav bar, because this needs to change
1580 // atomically with screen rotations.
1581 final int rotation = displayFrames.mRotation;
1582 final int displayHeight = displayFrames.mDisplayHeight;
1583 final int displayWidth = displayFrames.mDisplayWidth;
1584 final Rect dockFrame = displayFrames.mDock;
1585 mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1586
1587 final Rect cutoutSafeUnrestricted = sTmpRect;
1588 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1589 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1590
1591 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1592 // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1593 final int top = cutoutSafeUnrestricted.bottom
1594 - getNavigationBarHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001595 final int topNavBar = cutoutSafeUnrestricted.bottom
Matthew Nga7f24bc2019-04-09 17:06:41 -07001596 - getNavigationBarFrameHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001597 navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001598 displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1599 if (transientNavBarShowing) {
1600 mNavigationBarController.setBarShowingLw(true);
1601 } else if (navVisible) {
1602 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001603 dockFrame.bottom = displayFrames.mRestricted.bottom = top;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001604 } else {
1605 // We currently want to hide the navigation UI - unless we expanded the status bar.
1606 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1607 }
1608 if (navVisible && !navTranslucent && !navAllowedHidden
1609 && !mNavigationBar.isAnimatingLw()
1610 && !mNavigationBarController.wasRecentlyTranslucent()) {
1611 // If the opaque nav bar is currently requested to be visible and not in the process
1612 // of animating on or off, then we can tell the app that it is covered by it.
1613 displayFrames.mSystem.bottom = top;
1614 }
1615 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1616 // Landscape screen; nav bar goes to the right.
1617 final int left = cutoutSafeUnrestricted.right
1618 - getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001619 navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001620 displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1621 if (transientNavBarShowing) {
1622 mNavigationBarController.setBarShowingLw(true);
1623 } else if (navVisible) {
1624 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001625 dockFrame.right = displayFrames.mRestricted.right = left;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001626 } else {
1627 // We currently want to hide the navigation UI - unless we expanded the status bar.
1628 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1629 }
1630 if (navVisible && !navTranslucent && !navAllowedHidden
1631 && !mNavigationBar.isAnimatingLw()
1632 && !mNavigationBarController.wasRecentlyTranslucent()) {
1633 // If the nav bar is currently requested to be visible, and not in the process of
1634 // animating on or off, then we can tell the app that it is covered by it.
1635 displayFrames.mSystem.right = left;
1636 }
1637 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1638 // Seascape screen; nav bar goes to the left.
1639 final int right = cutoutSafeUnrestricted.left
1640 + getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001641 navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001642 displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1643 if (transientNavBarShowing) {
1644 mNavigationBarController.setBarShowingLw(true);
1645 } else if (navVisible) {
1646 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001647 dockFrame.left = displayFrames.mRestricted.left = right;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001648 } else {
1649 // We currently want to hide the navigation UI - unless we expanded the status bar.
1650 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1651 }
1652 if (navVisible && !navTranslucent && !navAllowedHidden
1653 && !mNavigationBar.isAnimatingLw()
1654 && !mNavigationBarController.wasRecentlyTranslucent()) {
1655 // If the nav bar is currently requested to be visible, and not in the process of
1656 // animating on or off, then we can tell the app that it is covered by it.
1657 displayFrames.mSystem.left = right;
1658 }
1659 }
1660
1661 // Make sure the content and current rectangles are updated to account for the restrictions
1662 // from the navigation bar.
1663 displayFrames.mCurrent.set(dockFrame);
1664 displayFrames.mVoiceContent.set(dockFrame);
1665 displayFrames.mContent.set(dockFrame);
1666 // And compute the final frame.
1667 sTmpRect.setEmpty();
1668 mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001669 navigationFrame /* displayFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001670 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1671 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001672 navigationFrame /* stableFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001673 mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1674 mNavigationBar.computeFrameLw();
1675 mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1676
1677 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1678 return mNavigationBarController.checkHiddenLw();
1679 }
1680
1681 private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
Jorim Jaggif081f062019-10-24 16:24:54 +02001682 boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001683 DisplayFrames displayFrames) {
1684 if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1685 // Here's a special case: if the child window is not the 'dock window'
1686 // or input method target, and the window it is attached to is below
1687 // the dock window, then the frames we computed for the window it is
1688 // attached to can not be used because the dock is effectively part
1689 // of the underlying window and the attached window is floating on top
1690 // of the whole thing. So, we ignore the attached window and explicitly
1691 // compute the frames that would be appropriate without the dock.
1692 vf.set(displayFrames.mDock);
1693 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001694 df.set(displayFrames.mDock);
1695 } else {
Jorim Jaggid6490572019-04-16 14:57:56 +02001696
Jorim Jaggif081f062019-10-24 16:24:54 +02001697 // In case we forced the window to draw behind the navigation bar, restrict df to
1698 // DF.Restricted to simulate old compat behavior.
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001699 Rect parentDisplayFrame = attached.getDisplayFrameLw();
Jorim Jaggid6490572019-04-16 14:57:56 +02001700 final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
1701 if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1702 && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1703 && (attachedAttrs.systemUiVisibility
1704 & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001705 parentDisplayFrame = new Rect(parentDisplayFrame);
Jorim Jaggif081f062019-10-24 16:24:54 +02001706 parentDisplayFrame.intersect(displayFrames.mRestricted);
Jorim Jaggid6490572019-04-16 14:57:56 +02001707 }
1708
Tiger Huang7c610aa2018-10-27 00:01:01 +08001709 // The effective display frame of the attached window depends on whether it is taking
1710 // care of insetting its content. If not, we need to use the parent's content frame so
1711 // that the entire window is positioned within that content. Otherwise we can use the
Jorim Jaggif081f062019-10-24 16:24:54 +02001712 // parent display frame and let the attached window take care of positioning its content
Tiger Huang7c610aa2018-10-27 00:01:01 +08001713 // appropriately.
1714 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1715 // Set the content frame of the attached window to the parent's decor frame
1716 // (same as content frame when IME isn't present) if specifically requested by
1717 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1718 // Otherwise, use the overscan frame.
1719 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
Jorim Jaggif081f062019-10-24 16:24:54 +02001720 ? attached.getContentFrameLw() : parentDisplayFrame);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001721 } else {
1722 // If the window is resizing, then we want to base the content frame on our attached
1723 // content frame to resize...however, things can be tricky if the attached window is
1724 // NOT in resize mode, in which case its content frame will be larger.
1725 // Ungh. So to deal with that, make sure the content frame we end up using is not
1726 // covering the IM dock.
1727 cf.set(attached.getContentFrameLw());
1728 if (attached.isVoiceInteraction()) {
1729 cf.intersectUnchecked(displayFrames.mVoiceContent);
1730 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1731 cf.intersectUnchecked(displayFrames.mContent);
1732 }
1733 }
Jorim Jaggid6490572019-04-16 14:57:56 +02001734 df.set(insetDecors ? parentDisplayFrame : cf);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001735 vf.set(attached.getVisibleFrameLw());
1736 }
1737 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1738 // positioned relative to its parent or the entire screen.
1739 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1740 }
1741
1742 private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1743 if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1744 return;
1745 }
1746 // If app is requesting a stable layout, don't let the content insets go below the stable
1747 // values.
1748 if ((fl & FLAG_FULLSCREEN) != 0) {
1749 r.intersectUnchecked(displayFrames.mStableFullscreen);
1750 } else {
1751 r.intersectUnchecked(displayFrames.mStable);
1752 }
1753 }
1754
1755 private boolean canReceiveInput(WindowState win) {
1756 boolean notFocusable =
1757 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1758 boolean altFocusableIm =
1759 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1760 boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1761 return !notFocusableForIm;
1762 }
1763
1764 /**
1765 * Called for each window attached to the window manager as layout is proceeding. The
1766 * implementation of this function must take care of setting the window's frame, either here or
1767 * in finishLayout().
1768 *
1769 * @param win The window being positioned.
1770 * @param attached For sub-windows, the window it is attached to; this
1771 * window will already have had layoutWindow() called on it
1772 * so you can use its Rect. Otherwise null.
1773 * @param displayFrames The display frames.
1774 */
1775 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1776 // We've already done the navigation bar, status bar, and all screen decor windows. If the
1777 // status bar can receive input, we need to layout it again to accommodate for the IME
1778 // window.
1779 if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1780 || mScreenDecorWindows.contains(win)) {
1781 return;
1782 }
1783 final WindowManager.LayoutParams attrs = win.getAttrs();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001784
1785 final int type = attrs.type;
1786 final int fl = PolicyControl.getWindowFlags(win, attrs);
1787 final int pfl = attrs.privateFlags;
1788 final int sim = attrs.softInputMode;
1789 final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1790 final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1791
1792 final WindowFrames windowFrames = win.getWindowFrames();
1793
Tiger Huang7c610aa2018-10-27 00:01:01 +08001794 sTmpLastParentFrame.set(windowFrames.mParentFrame);
1795 final Rect pf = windowFrames.mParentFrame;
1796 final Rect df = windowFrames.mDisplayFrame;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001797 final Rect cf = windowFrames.mContentFrame;
1798 final Rect vf = windowFrames.mVisibleFrame;
1799 final Rect dcf = windowFrames.mDecorFrame;
1800 final Rect sf = windowFrames.mStableFrame;
1801 dcf.setEmpty();
1802 windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1803 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1804
1805 final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1806 && mNavigationBar.isVisibleLw();
1807
1808 final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1809
1810 final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
1811 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
1812
1813 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1814 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1815
1816 sf.set(displayFrames.mStable);
1817
1818 if (type == TYPE_INPUT_METHOD) {
1819 vf.set(displayFrames.mDock);
1820 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001821 df.set(displayFrames.mDock);
1822 windowFrames.mParentFrame.set(displayFrames.mDock);
1823 // IM dock windows layout below the nav bar...
Jorim Jaggif081f062019-10-24 16:24:54 +02001824 pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001825 // ...with content insets above the nav bar
1826 cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1827 if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1828 // The status bar forces the navigation bar while it's visible. Make sure the IME
1829 // avoids the navigation bar in that case.
1830 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001831 pf.right = df.right = cf.right = vf.right =
Tiger Huang7c610aa2018-10-27 00:01:01 +08001832 displayFrames.mStable.right;
1833 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001834 pf.left = df.left = cf.left = vf.left = displayFrames.mStable.left;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001835 }
1836 }
1837
Matthew Nga7f24bc2019-04-09 17:06:41 -07001838 // In case the navigation bar is on the bottom, we use the frame height instead of the
1839 // regular height for the insets we send to the IME as we need some space to show
1840 // additional buttons in SystemUI when the IME is up.
1841 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1842 final int rotation = displayFrames.mRotation;
1843 final int uimode = mService.mPolicy.getUiMode();
1844 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
1845 - getNavigationBarHeight(rotation, uimode);
1846 if (navHeightOffset > 0) {
1847 cf.bottom -= navHeightOffset;
1848 sf.bottom -= navHeightOffset;
1849 vf.bottom -= navHeightOffset;
1850 dcf.bottom -= navHeightOffset;
1851 }
1852 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001853
1854 // IM dock windows always go to the bottom of the screen.
1855 attrs.gravity = Gravity.BOTTOM;
1856 } else if (type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001857 df.set(displayFrames.mUnrestricted);
1858 pf.set(displayFrames.mUnrestricted);
1859 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1860 cf.set(displayFrames.mDock);
1861 } else {
1862 cf.set(displayFrames.mContent);
1863 }
1864 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1865 vf.set(displayFrames.mCurrent);
1866 } else {
1867 vf.set(cf);
1868 }
1869 } else if (type == TYPE_WALLPAPER) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001870 layoutWallpaper(displayFrames, pf, df, cf);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001871 } else if (win == mStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001872 df.set(displayFrames.mUnrestricted);
1873 pf.set(displayFrames.mUnrestricted);
1874 cf.set(displayFrames.mStable);
1875 vf.set(displayFrames.mStable);
1876
1877 if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7fe7f682019-10-26 01:11:23 +08001878 // cf.bottom should not be below the stable bottom, or the content might be obscured
1879 // by the navigation bar.
1880 if (cf.bottom > displayFrames.mContent.bottom) {
1881 cf.bottom = displayFrames.mContent.bottom;
1882 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001883 } else {
Tiger Huang7fe7f682019-10-26 01:11:23 +08001884 if (cf.bottom > displayFrames.mDock.bottom) {
1885 cf.bottom = displayFrames.mDock.bottom;
1886 }
1887 if (vf.bottom > displayFrames.mContent.bottom) {
1888 vf.bottom = displayFrames.mContent.bottom;
1889 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001890 }
1891 } else {
1892 dcf.set(displayFrames.mSystem);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001893 final boolean isAppWindow =
1894 type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1895 final boolean topAtRest =
1896 win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
Jorim Jaggia2e648e2019-10-25 15:06:53 +02001897 if (isAppWindow && !topAtRest) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001898 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
1899 && (fl & FLAG_FULLSCREEN) == 0
1900 && (fl & FLAG_TRANSLUCENT_STATUS) == 0
1901 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001902 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001903 // Ensure policy decor includes status bar
1904 dcf.top = displayFrames.mStable.top;
1905 }
1906 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
1907 && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001908 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1909 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001910 // Ensure policy decor includes navigation bar
1911 dcf.bottom = displayFrames.mStable.bottom;
1912 dcf.right = displayFrames.mStable.right;
1913 }
1914 }
1915
1916 if (layoutInScreen && layoutInsetDecor) {
1917 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1918 + "): IN_SCREEN, INSET_DECOR");
1919 // This is the case for a normal activity window: we want it to cover all of the
1920 // screen space, and it can take care of moving its contents to account for screen
1921 // decorations that intrude into that space.
1922 if (attached != null) {
1923 // If this window is attached to another, our display
1924 // frame is the same as the one we are attached to.
Jorim Jaggif081f062019-10-24 16:24:54 +02001925 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001926 displayFrames);
1927 } else {
1928 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
1929 // Status bar panels are the only windows who can go on top of the status
1930 // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
1931 // have the same privileges as the status bar itself.
1932 //
1933 // However, they should still dodge the navigation bar if it exists.
1934
Jorim Jaggif081f062019-10-24 16:24:54 +02001935 pf.left = df.left = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08001936 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
Jorim Jaggif081f062019-10-24 16:24:54 +02001937 pf.top = df.top = displayFrames.mUnrestricted.top;
1938 pf.right = df.right = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08001939 ? displayFrames.mRestricted.right
1940 : displayFrames.mUnrestricted.right;
Jorim Jaggif081f062019-10-24 16:24:54 +02001941 pf.bottom = df.bottom = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08001942 ? displayFrames.mRestricted.bottom
1943 : displayFrames.mUnrestricted.bottom;
1944
1945 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
Jorim Jaggid6490572019-04-16 14:57:56 +02001946 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08001947 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
Charles Chen64172bb2019-04-22 17:30:29 +08001948 || type == TYPE_VOLUME_OVERLAY
1949 || type == TYPE_KEYGUARD_DIALOG)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001950 // Asking for layout as if the nav bar is hidden, lets the application
1951 // extend into the unrestricted overscan screen area. We only do this for
1952 // application windows and certain system windows to ensure no window that
1953 // can be above the nav bar can do this.
Jorim Jaggif081f062019-10-24 16:24:54 +02001954 df.set(displayFrames.mUnrestricted);
1955 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001956 } else {
Jorim Jaggif081f062019-10-24 16:24:54 +02001957 df.set(displayFrames.mRestricted);
1958 pf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001959 }
1960
1961 if ((fl & FLAG_FULLSCREEN) == 0) {
1962 if (win.isVoiceInteraction()) {
1963 cf.set(displayFrames.mVoiceContent);
1964 } else {
Jorim Jaggi648e5882019-01-24 13:24:02 +01001965 // IME Insets are handled on the client for ADJUST_RESIZE in the new
1966 // insets world
1967 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
1968 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001969 cf.set(displayFrames.mDock);
1970 } else {
1971 cf.set(displayFrames.mContent);
1972 }
1973 }
1974 } else {
1975 // Full screen windows are always given a layout that is as if the status
1976 // bar and other transient decors are gone. This is to avoid bad states when
1977 // moving from a window that is not hiding the status bar to one that is.
1978 cf.set(displayFrames.mRestricted);
1979 }
1980 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
1981 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1982 vf.set(displayFrames.mCurrent);
1983 } else {
1984 vf.set(cf);
1985 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001986 }
1987 } else if (layoutInScreen || (sysUiFl
1988 & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Jorim Jaggid6490572019-04-16 14:57:56 +02001989 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001990 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1991 + "): IN_SCREEN");
1992 // A window that has requested to fill the entire screen just
1993 // gets everything, period.
1994 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
1995 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001996 df.set(displayFrames.mUnrestricted);
1997 pf.set(displayFrames.mUnrestricted);
1998 if (hasNavBar) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001999 pf.left = df.left = cf.left = displayFrames.mDock.left;
2000 pf.right = df.right = cf.right = displayFrames.mRestricted.right;
2001 pf.bottom = df.bottom = cf.bottom =
Tiger Huang7c610aa2018-10-27 00:01:01 +08002002 displayFrames.mRestricted.bottom;
2003 }
2004 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
2005 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
2006 // The navigation bar has Real Ultimate Power.
Tiger Huang7c610aa2018-10-27 00:01:01 +08002007 df.set(displayFrames.mUnrestricted);
2008 pf.set(displayFrames.mUnrestricted);
2009 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
2010 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
2011 && ((fl & FLAG_FULLSCREEN) != 0)) {
2012 // Fullscreen secure system overlays get what they ask for. Screenshot region
2013 // selection overlay should also expand to full screen.
Jorim Jaggif081f062019-10-24 16:24:54 +02002014 cf.set(displayFrames.mUnrestricted);
2015 df.set(displayFrames.mUnrestricted);
2016 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002017 } else if (type == TYPE_BOOT_PROGRESS) {
2018 // Boot progress screen always covers entire display.
Jorim Jaggif081f062019-10-24 16:24:54 +02002019 cf.set(displayFrames.mUnrestricted);
2020 df.set(displayFrames.mUnrestricted);
2021 pf.set(displayFrames.mUnrestricted);
Jorim Jaggid6490572019-04-16 14:57:56 +02002022 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08002023 && (type == TYPE_STATUS_BAR
2024 || type == TYPE_TOAST
2025 || type == TYPE_DOCK_DIVIDER
2026 || type == TYPE_VOICE_INTERACTION_STARTING
2027 || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
2028 // Asking for layout as if the nav bar is hidden, lets the
2029 // application extend into the unrestricted screen area. We
2030 // only do this for application windows (or toasts) to ensure no window that
2031 // can be above the nav bar can do this.
2032 // XXX This assumes that an app asking for this will also
2033 // ask for layout in only content. We can't currently figure out
2034 // what the screen would be if only laying out to hide the nav bar.
2035 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002036 df.set(displayFrames.mUnrestricted);
2037 pf.set(displayFrames.mUnrestricted);
2038 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002039 df.set(displayFrames.mRestricted);
2040 pf.set(displayFrames.mRestricted);
Jorim Jaggi648e5882019-01-24 13:24:02 +01002041
2042 // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2043 // world
2044 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2045 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002046 cf.set(displayFrames.mDock);
2047 } else {
2048 cf.set(displayFrames.mContent);
2049 }
2050 } else {
2051 cf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002052 df.set(displayFrames.mRestricted);
2053 pf.set(displayFrames.mRestricted);
2054 }
2055
2056 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2057
2058 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2059 vf.set(displayFrames.mCurrent);
2060 } else {
2061 vf.set(cf);
2062 }
2063 } else if (attached != null) {
2064 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2065 + "): attached to " + attached);
2066 // A child window should be placed inside of the same visible
2067 // frame that its parent had.
Jorim Jaggif081f062019-10-24 16:24:54 +02002068 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08002069 displayFrames);
2070 } else {
2071 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2072 + "): normal window");
2073 // Otherwise, a normal window must be placed inside the content
2074 // of all screen decorations.
2075 if (type == TYPE_STATUS_BAR_PANEL) {
2076 // Status bar panels can go on
2077 // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2078 // permission, so they have the same privileges as the status bar itself.
2079 cf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002080 df.set(displayFrames.mRestricted);
2081 pf.set(displayFrames.mRestricted);
Vishnu Nair9ccb1d22019-03-20 16:32:44 +00002082 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002083 // These dialogs are stable to interim decor changes.
2084 cf.set(displayFrames.mStable);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002085 df.set(displayFrames.mStable);
2086 pf.set(displayFrames.mStable);
2087 } else {
2088 pf.set(displayFrames.mContent);
2089 if (win.isVoiceInteraction()) {
2090 cf.set(displayFrames.mVoiceContent);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002091 df.set(displayFrames.mVoiceContent);
2092 } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2093 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002094 df.set(displayFrames.mDock);
2095 } else {
2096 cf.set(displayFrames.mContent);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002097 df.set(displayFrames.mContent);
2098 }
2099 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2100 vf.set(displayFrames.mCurrent);
2101 } else {
2102 vf.set(cf);
2103 }
2104 }
2105 }
2106 }
2107
2108 final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2109 final boolean attachedInParent = attached != null && !layoutInScreen;
2110 final boolean requestedHideNavigation =
2111 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
2112
2113 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2114 // cropped / shifted to the displayFrame in WindowState.
2115 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2116 && type != TYPE_BASE_APPLICATION;
2117
2118 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2119 // the cutout safe zone.
Arthur Hung20479922019-02-27 17:13:22 +08002120 if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002121 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2122 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2123 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2124 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2125 // At the top we have the status bar, so apps that are
2126 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2127 // already expect that there's an inset there and we don't need to exclude
2128 // the window from that area.
2129 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2130 }
2131 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2132 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2133 // Same for the navigation bar.
2134 switch (mNavigationBarPosition) {
2135 case NAV_BAR_BOTTOM:
2136 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2137 break;
2138 case NAV_BAR_RIGHT:
2139 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2140 break;
2141 case NAV_BAR_LEFT:
2142 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2143 break;
2144 }
2145 }
2146 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2147 // The IME can always extend under the bottom cutout if the navbar is there.
2148 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2149 }
2150 // Windows that are attached to a parent and laid out in said parent already avoid
2151 // the cutout according to that parent and don't need to be further constrained.
2152 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2153 // They will later be cropped or shifted using the displayFrame in WindowState,
2154 // which prevents overlap with the DisplayCutout.
2155 if (!attachedInParent && !floatingInScreenWindow) {
2156 sTmpRect.set(pf);
2157 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2158 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2159 }
2160 // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2161 // cutout.
2162 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2163 }
2164
2165 // Content should never appear in the cutout.
2166 cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2167
2168 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2169 // Also, we don't allow windows in multi-window mode to extend out of the screen.
2170 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
Evan Rosky4fb1e912019-03-06 13:54:43 -08002171 && !win.inMultiWindowMode()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002172 df.left = df.top = -10000;
2173 df.right = df.bottom = 10000;
2174 if (type != TYPE_WALLPAPER) {
Jorim Jaggif081f062019-10-24 16:24:54 +02002175 cf.left = cf.top = vf.left = vf.top = -10000;
2176 cf.right = cf.bottom = vf.right = vf.bottom = 10000;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002177 }
2178 }
2179
2180 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2181 + ": sim=#" + Integer.toHexString(sim)
2182 + " attach=" + attached + " type=" + type
2183 + String.format(" flags=0x%08x", fl)
2184 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
Tiger Huang7c610aa2018-10-27 00:01:01 +08002185 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2186 + " dcf=" + dcf.toShortString()
Jorim Jaggif081f062019-10-24 16:24:54 +02002187 + " sf=" + sf.toShortString());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002188
2189 if (!sTmpLastParentFrame.equals(pf)) {
2190 windowFrames.setContentChanged(true);
2191 }
2192
2193 win.computeFrameLw();
2194 // Dock windows carve out the bottom of the screen, so normal windows
2195 // can't appear underneath them.
2196 if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2197 && !win.getGivenInsetsPendingLw()) {
2198 offsetInputMethodWindowLw(win, displayFrames);
2199 }
2200 if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2201 && !win.getGivenInsetsPendingLw()) {
2202 offsetVoiceInputWindowLw(win, displayFrames);
2203 }
2204 }
2205
Jorim Jaggif081f062019-10-24 16:24:54 +02002206 private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect cf) {
2207 // The wallpaper has Real Ultimate Power
2208 df.set(displayFrames.mUnrestricted);
2209 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002210 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002211 }
2212
2213 private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
2214 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2215 top += win.getGivenContentInsetsLw().top;
2216 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
2217 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2218 top = win.getVisibleFrameLw().top;
2219 top += win.getGivenVisibleInsetsLw().top;
2220 displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2221 if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2222 + displayFrames.mDock.bottom + " mContentBottom="
2223 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2224 }
2225
2226 private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2227 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2228 top += win.getGivenContentInsetsLw().top;
2229 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2230 }
2231
Riddle Hsuccf09402019-08-13 00:33:06 +08002232 WindowState getTopFullscreenOpaqueWindow() {
2233 return mTopFullscreenOpaqueWindowState;
2234 }
2235
2236 boolean isTopLayoutFullscreen() {
2237 return mTopIsFullscreen;
2238 }
2239
Tiger Huang7c610aa2018-10-27 00:01:01 +08002240 /**
2241 * Called following layout of all windows before each window has policy applied.
2242 */
2243 public void beginPostLayoutPolicyLw() {
2244 mTopFullscreenOpaqueWindowState = null;
2245 mTopFullscreenOpaqueOrDimmingWindowState = null;
2246 mTopDockedOpaqueWindowState = null;
2247 mTopDockedOpaqueOrDimmingWindowState = null;
2248 mForceStatusBar = false;
2249 mForceStatusBarFromKeyguard = false;
2250 mForceStatusBarTransparent = false;
2251 mForcingShowNavBar = false;
2252 mForcingShowNavBarLayer = -1;
2253
2254 mAllowLockscreenWhenOn = false;
2255 mShowingDream = false;
2256 mWindowSleepTokenNeeded = false;
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002257 mIsFreeformWindowOverlappingWithNavBar = false;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002258 }
2259
2260 /**
2261 * Called following layout of all window to apply policy to each window.
2262 *
2263 * @param win The window being positioned.
2264 * @param attrs The LayoutParams of the window.
2265 * @param attached For sub-windows, the window it is attached to. Otherwise null.
2266 */
2267 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2268 WindowState attached, WindowState imeTarget) {
2269 final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2270 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2271 mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2272 final int fl = PolicyControl.getWindowFlags(win, attrs);
2273 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2274 && attrs.type == TYPE_INPUT_METHOD) {
2275 mForcingShowNavBar = true;
2276 mForcingShowNavBarLayer = win.getSurfaceLayer();
2277 }
2278 if (attrs.type == TYPE_STATUS_BAR) {
2279 if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
2280 mForceStatusBarFromKeyguard = true;
2281 }
2282 if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
2283 mForceStatusBarTransparent = true;
2284 }
2285 }
2286
2287 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2288 && attrs.type < FIRST_SYSTEM_WINDOW;
2289 final int windowingMode = win.getWindowingMode();
2290 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2291 windowingMode == WINDOWING_MODE_FULLSCREEN
2292 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2293 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2294 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2295 mForceStatusBar = true;
2296 }
2297 if (attrs.type == TYPE_DREAM) {
2298 // If the lockscreen was showing when the dream started then wait
2299 // for the dream to draw before hiding the lockscreen.
2300 if (!mDreamingLockscreen
2301 || (win.isVisibleLw() && win.hasDrawnLw())) {
2302 mShowingDream = true;
2303 appWindow = true;
2304 }
2305 }
2306
2307 // For app windows that are not attached, we decide if all windows in the app they
2308 // represent should be hidden or if we should hide the lockscreen. For attached app
2309 // windows we defer the decision to the window it is attached to.
2310 if (appWindow && attached == null) {
2311 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2312 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2313 mTopFullscreenOpaqueWindowState = win;
2314 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2315 mTopFullscreenOpaqueOrDimmingWindowState = win;
2316 }
2317 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2318 mAllowLockscreenWhenOn = true;
2319 }
2320 }
2321 }
2322 }
2323
2324 // Voice interaction overrides both top fullscreen and top docked.
Jorim Jaggi50150152019-03-27 23:08:58 +01002325 if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002326 if (mTopFullscreenOpaqueWindowState == null) {
2327 mTopFullscreenOpaqueWindowState = win;
2328 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2329 mTopFullscreenOpaqueOrDimmingWindowState = win;
2330 }
2331 }
2332 if (mTopDockedOpaqueWindowState == null) {
2333 mTopDockedOpaqueWindowState = win;
2334 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2335 mTopDockedOpaqueOrDimmingWindowState = win;
2336 }
2337 }
2338 }
2339
2340 // Keep track of the window if it's dimming but not necessarily fullscreen.
2341 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2342 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2343 mTopFullscreenOpaqueOrDimmingWindowState = win;
2344 }
2345
2346 // We need to keep track of the top "fullscreen" opaque window for the docked stack
2347 // separately, because both the "real fullscreen" opaque window and the one for the docked
2348 // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2349 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2350 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2351 mTopDockedOpaqueWindowState = win;
2352 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2353 mTopDockedOpaqueOrDimmingWindowState = win;
2354 }
2355 }
2356
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002357 // Check if the freeform window overlaps with the navigation bar area.
2358 final WindowState navBarWin = hasNavigationBar() ? mNavigationBar : null;
2359 if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode()
2360 && isOverlappingWithNavBar(win, navBarWin)) {
2361 mIsFreeformWindowOverlappingWithNavBar = true;
2362 }
2363
Tiger Huang7c610aa2018-10-27 00:01:01 +08002364 // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2365 // docked stack.
2366 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2367 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2368 mTopDockedOpaqueOrDimmingWindowState = win;
2369 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002370 }
2371
2372 /**
2373 * Called following layout of all windows and after policy has been applied
2374 * to each window. If in this function you do
2375 * something that may have modified the animation state of another window,
2376 * be sure to return non-zero in order to perform another pass through layout.
2377 *
2378 * @return Return any bit set of
2379 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2380 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2381 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2382 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2383 */
2384 public int finishPostLayoutPolicyLw() {
2385 int changes = 0;
2386 boolean topIsFullscreen = false;
2387
2388 // If we are not currently showing a dream then remember the current
2389 // lockscreen state. We will use this to determine whether the dream
2390 // started while the lockscreen was showing and remember this state
2391 // while the dream is showing.
2392 if (!mShowingDream) {
2393 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2394 if (mDreamingSleepTokenNeeded) {
2395 mDreamingSleepTokenNeeded = false;
2396 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2397 }
2398 } else {
2399 if (!mDreamingSleepTokenNeeded) {
2400 mDreamingSleepTokenNeeded = true;
2401 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2402 }
2403 }
2404
2405 if (mStatusBar != null) {
2406 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
2407 + " forcefkg=" + mForceStatusBarFromKeyguard
2408 + " top=" + mTopFullscreenOpaqueWindowState);
2409 boolean shouldBeTransparent = mForceStatusBarTransparent
2410 && !mForceStatusBar
2411 && !mForceStatusBarFromKeyguard;
2412 if (!shouldBeTransparent) {
2413 mStatusBarController.setShowTransparent(false /* transparent */);
2414 } else if (!mStatusBar.isVisibleLw()) {
2415 mStatusBarController.setShowTransparent(true /* transparent */);
2416 }
2417
2418 boolean statusBarForcesShowingNavigation =
2419 (mStatusBar.getAttrs().privateFlags
2420 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
2421 boolean topAppHidesStatusBar = topAppHidesStatusBar();
2422 if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
2423 || statusBarForcesShowingNavigation) {
2424 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2425 if (mStatusBarController.setBarShowingLw(true)) {
2426 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2427 }
2428 // Maintain fullscreen layout until incoming animation is complete.
2429 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
2430 // Transient status bar is not allowed if status bar is on lockscreen or status bar
2431 // is expecting the navigation keys from the user.
2432 if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
2433 && mStatusBarController.isTransientShowing()) {
2434 mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2435 mLastSystemUiFlags, mLastSystemUiFlags);
2436 }
2437 } else if (mTopFullscreenOpaqueWindowState != null) {
2438 topIsFullscreen = topAppHidesStatusBar;
2439 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2440 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2441 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
2442 // case though.
2443 if (mStatusBarController.isTransientShowing()) {
2444 if (mStatusBarController.setBarShowingLw(true)) {
2445 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2446 }
2447 } else if (topIsFullscreen
Tiger Huang7c610aa2018-10-27 00:01:01 +08002448 && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2449 if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2450 if (mStatusBarController.setBarShowingLw(false)) {
2451 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2452 } else {
2453 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2454 }
2455 } else {
2456 if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2457 if (mStatusBarController.setBarShowingLw(true)) {
2458 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2459 }
2460 topAppHidesStatusBar = false;
2461 }
2462 }
2463 mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2464 }
2465
2466 if (mTopIsFullscreen != topIsFullscreen) {
2467 if (!topIsFullscreen) {
2468 // Force another layout when status bar becomes fully shown.
2469 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2470 }
2471 mTopIsFullscreen = topIsFullscreen;
2472 }
2473
2474 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2475 // If the navigation bar has been hidden or shown, we need to do another
2476 // layout pass to update that window.
2477 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2478 }
2479
2480 if (mShowingDream != mLastShowingDream) {
2481 mLastShowingDream = mShowingDream;
2482 mService.notifyShowingDreamChanged();
2483 }
2484
2485 updateWindowSleepToken();
2486
2487 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2488 return changes;
2489 }
2490
2491 private void updateWindowSleepToken() {
2492 if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2493 mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2494 mHandler.post(mAcquireSleepTokenRunnable);
2495 } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2496 mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2497 mHandler.post(mReleaseSleepTokenRunnable);
2498 }
2499 mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2500 }
2501
2502 /**
2503 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2504 * window.
2505 */
2506 private boolean topAppHidesStatusBar() {
hyok.kim332ccfc2019-07-02 15:39:43 +09002507 if (mTopFullscreenOpaqueWindowState == null || mForceShowSystemBars) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002508 return false;
2509 }
2510 final int fl = PolicyControl.getWindowFlags(null,
2511 mTopFullscreenOpaqueWindowState.getAttrs());
Adam Pardyl8c2d19c2019-09-16 17:15:38 +02002512 if (WindowManagerDebugConfig.DEBUG) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002513 Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2514 Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2515 + " lp.flags=0x" + Integer.toHexString(fl));
2516 }
2517 return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2518 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2519 }
2520
2521 /**
Winson Chungda20fec2019-04-10 12:19:59 -07002522 * Called when the user is switched.
2523 */
2524 public void switchUser() {
2525 updateCurrentUserResources();
2526 }
2527
2528 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002529 * Called when the resource overlays change.
2530 */
2531 public void onOverlayChangedLw() {
Winson Chungda20fec2019-04-10 12:19:59 -07002532 updateCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002533 onConfigurationChanged();
Jeff Changb0a061e2019-03-11 11:39:54 +08002534 mSystemGestures.onConfigurationChanged();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002535 }
2536
2537 /**
2538 * Called when the configuration has changed, and it's safe to load new values from resources.
2539 */
2540 public void onConfigurationChanged() {
2541 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2542
Winson Chungda20fec2019-04-10 12:19:59 -07002543 final Resources res = getCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002544 final int portraitRotation = displayRotation.getPortraitRotation();
2545 final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2546 final int landscapeRotation = displayRotation.getLandscapeRotation();
2547 final int seascapeRotation = displayRotation.getSeascapeRotation();
Matthew Nga7f24bc2019-04-09 17:06:41 -07002548 final int uiMode = mService.mPolicy.getUiMode();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002549
Louis Changfc64c832018-12-04 11:38:26 +08002550 if (hasStatusBar()) {
2551 mStatusBarHeightForRotation[portraitRotation] =
2552 mStatusBarHeightForRotation[upsideDownRotation] =
2553 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2554 mStatusBarHeightForRotation[landscapeRotation] =
2555 mStatusBarHeightForRotation[seascapeRotation] =
2556 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2557 } else {
2558 mStatusBarHeightForRotation[portraitRotation] =
2559 mStatusBarHeightForRotation[upsideDownRotation] =
2560 mStatusBarHeightForRotation[landscapeRotation] =
2561 mStatusBarHeightForRotation[seascapeRotation] = 0;
2562 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002563
2564 // Height of the navigation bar when presented horizontally at bottom
2565 mNavigationBarHeightForRotationDefault[portraitRotation] =
2566 mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2567 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2568 mNavigationBarHeightForRotationDefault[landscapeRotation] =
2569 mNavigationBarHeightForRotationDefault[seascapeRotation] =
2570 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2571
Matthew Nga7f24bc2019-04-09 17:06:41 -07002572 // Height of the navigation bar frame when presented horizontally at bottom
2573 mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2574 mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2575 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2576 mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2577 mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2578 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2579
Tiger Huang7c610aa2018-10-27 00:01:01 +08002580 // Width of the navigation bar when presented vertically along one side
2581 mNavigationBarWidthForRotationDefault[portraitRotation] =
2582 mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2583 mNavigationBarWidthForRotationDefault[landscapeRotation] =
2584 mNavigationBarWidthForRotationDefault[seascapeRotation] =
2585 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2586
2587 if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2588 // Height of the navigation bar when presented horizontally at bottom
2589 mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2590 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2591 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2592 mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2593 mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2594 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2595
2596 // Width of the navigation bar when presented vertically along one side
2597 mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2598 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2599 mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2600 mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2601 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2602 }
2603
Winson Chung4723b4e2019-03-25 16:49:36 -07002604 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002605 mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
2606 mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
Winson Chung36941632019-04-19 15:21:38 -07002607 mNavigationBarAlwaysShowOnSideGesture =
2608 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
Winson Chung4723b4e2019-03-25 16:49:36 -07002609
Matthew Nga7f24bc2019-04-09 17:06:41 -07002610 // This should calculate how much above the frame we accept gestures.
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002611 mBottomGestureAdditionalInset =
Matthew Nga7f24bc2019-04-09 17:06:41 -07002612 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002613 - getNavigationBarFrameHeight(portraitRotation, uiMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002614
Winson Chung4723b4e2019-03-25 16:49:36 -07002615 updateConfigurationAndScreenSizeDependentBehaviors();
2616 }
2617
2618 void updateConfigurationAndScreenSizeDependentBehaviors() {
Winson Chungda20fec2019-04-10 12:19:59 -07002619 final Resources res = getCurrentUserResources();
Winson Chung4723b4e2019-03-25 16:49:36 -07002620 mNavigationBarCanMove =
2621 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2622 && res.getBoolean(R.bool.config_navBarCanMove);
Riddle Hsuccf09402019-08-13 00:33:06 +08002623 mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002624 }
2625
Winson Chungda20fec2019-04-10 12:19:59 -07002626 /**
2627 * Updates the current user's resources to pick up any changes for the current user (including
2628 * overlay paths)
2629 */
2630 private void updateCurrentUserResources() {
2631 final int userId = mService.mAmInternal.getCurrentUserId();
2632 final Context uiContext = getSystemUiContext();
Winson Chung203e1522019-05-02 15:42:22 -07002633
2634 if (userId == UserHandle.USER_SYSTEM) {
2635 // Skip the (expensive) recreation of resources for the system user below and just
2636 // use the resources from the system ui context
2637 mCurrentUserResources = uiContext.getResources();
2638 return;
2639 }
2640
2641 // For non-system users, ensure that the resources are loaded from the current
2642 // user's package info (see ContextImpl.createDisplayContext)
Winson Chungda20fec2019-04-10 12:19:59 -07002643 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2644 uiContext.getPackageName(), null, 0, userId);
Winson Chungda20fec2019-04-10 12:19:59 -07002645 mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2646 pi.getResDir(),
2647 null /* splitResDirs */,
2648 pi.getOverlayDirs(),
2649 pi.getApplicationInfo().sharedLibraryFiles,
2650 mDisplayContent.getDisplayId(),
2651 null /* overrideConfig */,
2652 uiContext.getResources().getCompatibilityInfo(),
2653 null /* classLoader */);
2654 }
2655
Tiger Huang7c610aa2018-10-27 00:01:01 +08002656 @VisibleForTesting
Winson Chungda20fec2019-04-10 12:19:59 -07002657 Resources getCurrentUserResources() {
2658 if (mCurrentUserResources == null) {
2659 updateCurrentUserResources();
2660 }
2661 return mCurrentUserResources;
2662 }
2663
2664 @VisibleForTesting
2665 Context getContext() {
2666 return mContext;
2667 }
2668
2669 private Context getSystemUiContext() {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002670 final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
2671 return mDisplayContent.isDefaultDisplay
2672 ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay());
2673 }
2674
2675 private int getNavigationBarWidth(int rotation, int uiMode) {
2676 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2677 return mNavigationBarWidthForRotationInCarMode[rotation];
2678 } else {
2679 return mNavigationBarWidthForRotationDefault[rotation];
2680 }
2681 }
2682
Charles Chen3dedec32019-01-24 22:19:37 +08002683 void notifyDisplayReady() {
wilsonshih643bf132019-02-27 12:49:19 +08002684 mHandler.post(() -> {
2685 final int displayId = getDisplayId();
2686 getStatusBarManagerInternal().onDisplayReady(displayId);
Felipe Leme34a861a2019-08-05 16:00:12 -07002687 final WallpaperManagerInternal wpMgr = LocalServices
2688 .getService(WallpaperManagerInternal.class);
2689 if (wpMgr != null) {
2690 wpMgr.onDisplayReady(displayId);
2691 }
wilsonshih643bf132019-02-27 12:49:19 +08002692 });
Charles Chen3dedec32019-01-24 22:19:37 +08002693 }
2694
Tiger Huang7c610aa2018-10-27 00:01:01 +08002695 /**
2696 * Return the display width available after excluding any screen
2697 * decorations that could never be removed in Honeycomb. That is, system bar or
2698 * button bar.
2699 */
2700 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2701 DisplayCutout displayCutout) {
2702 int width = fullWidth;
2703 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002704 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2705 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002706 width -= getNavigationBarWidth(rotation, uiMode);
2707 }
2708 }
2709 if (displayCutout != null) {
2710 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2711 }
2712 return width;
2713 }
2714
2715 private int getNavigationBarHeight(int rotation, int uiMode) {
2716 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2717 return mNavigationBarHeightForRotationInCarMode[rotation];
2718 } else {
2719 return mNavigationBarHeightForRotationDefault[rotation];
2720 }
2721 }
2722
2723 /**
Matthew Nga7f24bc2019-04-09 17:06:41 -07002724 * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2725 * is used for spacing to show additional buttons on the navigation bar (such as the ime
2726 * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2727 * height that we send to the app as content insets that can be smaller.
2728 * <p>
2729 * In car mode it will return the same height as {@link #getNavigationBarHeight}
2730 *
2731 * @param rotation specifies rotation to return dimension from
2732 * @param uiMode to determine if in car mode
2733 * @return navigation bar frame height
2734 */
2735 private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2736 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2737 return mNavigationBarHeightForRotationInCarMode[rotation];
2738 } else {
2739 return mNavigationBarFrameHeightForRotationDefault[rotation];
2740 }
2741 }
2742
2743 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002744 * Return the display height available after excluding any screen
2745 * decorations that could never be removed in Honeycomb. That is, system bar or
2746 * button bar.
2747 */
2748 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2749 DisplayCutout displayCutout) {
2750 int height = fullHeight;
2751 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002752 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2753 if (navBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002754 height -= getNavigationBarHeight(rotation, uiMode);
2755 }
2756 }
2757 if (displayCutout != null) {
2758 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2759 }
2760 return height;
2761 }
2762
2763 /**
2764 * Return the available screen width that we should report for the
2765 * configuration. This must be no larger than
2766 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2767 * than that to account for more transient decoration like a status bar.
2768 */
2769 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2770 DisplayCutout displayCutout) {
2771 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2772 }
2773
2774 /**
2775 * Return the available screen height that we should report for the
2776 * configuration. This must be no larger than
2777 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2778 * than that to account for more transient decoration like a status bar.
2779 */
2780 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2781 DisplayCutout displayCutout) {
2782 // There is a separate status bar at the top of the display. We don't count that as part
2783 // of the fixed decor, since it can hide; however, for purposes of configurations,
2784 // we do want to exclude it since applications can't generally use that part
2785 // of the screen.
2786 int statusBarHeight = mStatusBarHeightForRotation[rotation];
2787 if (displayCutout != null) {
2788 // If there is a cutout, it may already have accounted for some part of the status
2789 // bar height.
2790 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2791 }
2792 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2793 - statusBarHeight;
2794 }
2795
Tiger Huang43b8fc22019-04-26 11:49:29 +08002796 /**
2797 * Return corner radius in pixels that should be used on windows in order to cover the display.
2798 * The radius is only valid for built-in displays since the one who configures window corner
2799 * radius cannot know the corner radius of non-built-in display.
2800 */
2801 float getWindowCornerRadius() {
2802 return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN
2803 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2804 }
2805
Tiger Huang7c610aa2018-10-27 00:01:01 +08002806 boolean isShowingDreamLw() {
2807 return mShowingDream;
2808 }
2809
2810 /**
Riddle Hsu61987bc2019-04-03 13:08:47 +08002811 * Calculates the stable insets if we already have the non-decor insets.
2812 *
2813 * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2814 * @param rotation The current display rotation.
2815 */
2816 void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2817 inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2818 }
2819
2820 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002821 * Calculates the stable insets without running a layout.
2822 *
2823 * @param displayRotation the current display rotation
2824 * @param displayWidth the current display width
2825 * @param displayHeight the current display height
2826 * @param displayCutout the current display cutout
2827 * @param outInsets the insets to return
2828 */
2829 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2830 DisplayCutout displayCutout, Rect outInsets) {
2831 outInsets.setEmpty();
2832
2833 // Navigation bar and status bar.
2834 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
Riddle Hsu61987bc2019-04-03 13:08:47 +08002835 convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002836 }
2837
2838 /**
2839 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2840 * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2841 *
2842 * @param displayRotation the current display rotation
2843 * @param displayWidth the current display width
2844 * @param displayHeight the current display height
2845 * @param displayCutout the current display cutout
2846 * @param outInsets the insets to return
2847 */
2848 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2849 DisplayCutout displayCutout, Rect outInsets) {
2850 outInsets.setEmpty();
2851
2852 // Only navigation bar
2853 if (hasNavigationBar()) {
2854 final int uiMode = mService.mPolicy.getUiMode();
2855 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2856 if (position == NAV_BAR_BOTTOM) {
2857 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2858 } else if (position == NAV_BAR_RIGHT) {
2859 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2860 } else if (position == NAV_BAR_LEFT) {
2861 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2862 }
2863 }
2864
2865 if (displayCutout != null) {
2866 outInsets.left += displayCutout.getSafeInsetLeft();
2867 outInsets.top += displayCutout.getSafeInsetTop();
2868 outInsets.right += displayCutout.getSafeInsetRight();
2869 outInsets.bottom += displayCutout.getSafeInsetBottom();
2870 }
2871 }
2872
Issei Suzukia5dbf522019-02-01 17:58:15 +01002873 /**
2874 * @see IWindowManager#setForwardedInsets
2875 */
2876 public void setForwardedInsets(@NonNull Insets forwardedInsets) {
2877 mForwardedInsets = forwardedInsets;
2878 }
2879
2880 @NonNull
2881 public Insets getForwardedInsets() {
2882 return mForwardedInsets;
2883 }
2884
Tiger Huang7c610aa2018-10-27 00:01:01 +08002885 @NavigationBarPosition
2886 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
2887 if (navigationBarCanMove() && displayWidth > displayHeight) {
2888 if (displayRotation == Surface.ROTATION_270) {
2889 return NAV_BAR_LEFT;
2890 } else if (displayRotation == Surface.ROTATION_90) {
2891 return NAV_BAR_RIGHT;
2892 }
2893 }
2894 return NAV_BAR_BOTTOM;
2895 }
2896
2897 /**
2898 * @return The side of the screen where navigation bar is positioned.
2899 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
2900 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
2901 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
2902 */
2903 @NavigationBarPosition
2904 public int getNavBarPosition() {
2905 return mNavigationBarPosition;
2906 }
2907
2908 /**
2909 * A new window has been focused.
2910 */
2911 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
2912 mFocusedWindow = newFocus;
2913 mLastFocusedWindow = lastFocus;
Issei Suzuki9f840c72018-12-07 15:09:30 -08002914 if (mDisplayContent.isDefaultDisplay) {
2915 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
2916 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002917 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2918 // If the navigation bar has been hidden or shown, we need to do another
2919 // layout pass to update that window.
2920 return FINISH_LAYOUT_REDO_LAYOUT;
2921 }
2922 return 0;
2923 }
2924
2925 /**
2926 * Return true if it is okay to perform animations for an app transition
2927 * that is about to occur. You may return false for this if, for example,
2928 * the dream window is currently displayed so the switch should happen
2929 * immediately.
2930 */
2931 public boolean allowAppAnimationsLw() {
2932 return !mShowingDream;
2933 }
2934
2935 private void updateDreamingSleepToken(boolean acquire) {
2936 if (acquire) {
2937 final int displayId = getDisplayId();
2938 if (mDreamingSleepToken == null) {
2939 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
2940 "DreamOnDisplay" + displayId, displayId);
2941 }
2942 } else {
2943 if (mDreamingSleepToken != null) {
2944 mDreamingSleepToken.release();
2945 mDreamingSleepToken = null;
2946 }
2947 }
2948 }
2949
2950 private void requestTransientBars(WindowState swipeTarget) {
2951 synchronized (mLock) {
2952 if (!mService.mPolicy.isUserSetupComplete()) {
2953 // Swipe-up for navigation bar is disabled during setup
2954 return;
2955 }
Jorim Jaggi956ca412019-01-07 14:49:14 +01002956 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
2957 if (swipeTarget == mNavigationBar
2958 && !getInsetsPolicy().isHidden(InsetsState.TYPE_NAVIGATION_BAR)) {
2959 // Don't show status bar when swiping on already visible navigation bar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002960 return;
2961 }
Jorim Jaggi956ca412019-01-07 14:49:14 +01002962 final InsetsControlTarget controlTarget =
2963 swipeTarget.getControllableInsetProvider().getControlTarget();
2964 if (controlTarget == null) {
2965 return;
2966 }
2967 if (controlTarget.canShowTransient()) {
2968 mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
2969 new int[]{TYPE_TOP_BAR, InsetsState.TYPE_NAVIGATION_BAR}));
2970 } else {
2971 controlTarget.showInsets(WindowInsets.Type.systemBars(), false);
2972 }
2973 } else {
2974 boolean sb = mStatusBarController.checkShowTransientBarLw();
2975 boolean nb = mNavigationBarController.checkShowTransientBarLw()
2976 && !isNavBarEmpty(mLastSystemUiFlags);
2977 if (sb || nb) {
2978 // Don't show status bar when swiping on already visible navigation bar
2979 if (!nb && swipeTarget == mNavigationBar) {
2980 if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
2981 return;
2982 }
2983 if (sb) mStatusBarController.showTransient();
2984 if (nb) mNavigationBarController.showTransient();
2985 updateSystemUiVisibilityLw();
2986 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002987 mImmersiveModeConfirmation.confirmCurrentPrompt();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002988 }
2989 }
2990 }
2991
2992 private void disposeInputConsumer(InputConsumer inputConsumer) {
2993 if (inputConsumer != null) {
2994 inputConsumer.dismiss();
2995 }
2996 }
2997
2998 private boolean isStatusBarKeyguard() {
2999 return mStatusBar != null
3000 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
3001 }
3002
3003 private boolean isKeyguardOccluded() {
3004 // TODO (b/113840485): Handle per display keyguard.
3005 return mService.mPolicy.isKeyguardOccluded();
3006 }
3007
Jorim Jaggi956ca412019-01-07 14:49:14 +01003008 InsetsPolicy getInsetsPolicy() {
3009 return mDisplayContent.getInsetsPolicy();
3010 }
3011
Tiger Huang7c610aa2018-10-27 00:01:01 +08003012 void resetSystemUiVisibilityLw() {
3013 mLastSystemUiFlags = 0;
3014 updateSystemUiVisibilityLw();
3015 }
3016
3017 private int updateSystemUiVisibilityLw() {
3018 // If there is no window focused, there will be nobody to handle the events
3019 // anyway, so just hang on in whatever state we're in until things settle down.
3020 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
3021 : mTopFullscreenOpaqueWindowState;
3022 if (winCandidate == null) {
3023 return 0;
3024 }
3025
3026 // The immersive mode confirmation should never affect the system bar visibility, otherwise
3027 // it will unhide the navigation bar and hide itself.
3028 if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
3029
3030 // The immersive mode confirmation took the focus from mLastFocusedWindow which was
3031 // controlling the system ui visibility. So if mLastFocusedWindow can still receive
3032 // keys, we let it keep controlling the visibility.
3033 final boolean lastFocusCanReceiveKeys =
3034 (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
3035 winCandidate = isStatusBarKeyguard() ? mStatusBar
3036 : lastFocusCanReceiveKeys ? mLastFocusedWindow
3037 : mTopFullscreenOpaqueWindowState;
3038 if (winCandidate == null) {
3039 return 0;
3040 }
3041 }
3042 final WindowState win = winCandidate;
3043 if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) {
3044 // We are updating at a point where the keyguard has gotten
3045 // focus, but we were last in a state where the top window is
3046 // hiding it. This is probably because the keyguard as been
3047 // shown while the top window was displayed, so we want to ignore
3048 // it here because this is just a very transient change and it
3049 // will quickly lose focus once it correctly gets hidden.
3050 return 0;
3051 }
3052
Jorim Jaggi28620472019-01-02 23:21:49 +01003053 mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
Jorim Jaggib6030952018-10-23 18:31:52 +02003054
Tiger Huang7c610aa2018-10-27 00:01:01 +08003055 int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
3056 & ~mResettingSystemUiFlags
3057 & ~mForceClearedSystemUiFlags;
3058 if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
3059 tmpVisibility
3060 &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
3061 }
3062
Jorim Jaggi956ca412019-01-07 14:49:14 +01003063 final int fullscreenAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
3064 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
3065 final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
3066 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003067 mService.getStackBounds(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003068 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003069 final boolean inSplitScreen = !mDockedStackBounds.isEmpty();
3070 mService.getStackBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
3071 : WINDOWING_MODE_FULLSCREEN,
Tiger Huangd5f0b9a2019-10-10 10:34:57 +02003072 ACTIVITY_TYPE_UNDEFINED, mNonDockedStackBounds);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003073 final Pair<Integer, Boolean> result =
3074 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
3075 final int visibility = result.first;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003076 final int appearance = win.mAttrs.insetsFlags.appearance
3077 | InsetsFlags.getAppearance(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003078 final int diff = visibility ^ mLastSystemUiFlags;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003079 final InsetsPolicy insetsPolicy = getInsetsPolicy();
3080 final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
3081 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) != 0
3082 || (PolicyControl.getWindowFlags(win, win.mAttrs) & FLAG_FULLSCREEN) != 0
3083 || (mStatusBar != null && insetsPolicy.isHidden(TYPE_TOP_BAR))
3084 || (mNavigationBar != null && insetsPolicy.isHidden(
3085 InsetsState.TYPE_NAVIGATION_BAR));
3086 final int behavior = win.mAttrs.insetsFlags.behavior;
3087 final boolean isImmersive = (visibility & (View.SYSTEM_UI_FLAG_IMMERSIVE
3088 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)) != 0
3089 || behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
3090 || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003091 if (diff == 0
Jorim Jaggi956ca412019-01-07 14:49:14 +01003092 && mLastAppearance == appearance
3093 && mLastFullscreenAppearance == fullscreenAppearance
3094 && mLastDockedAppearance == dockedAppearance
3095 && mLastFocusIsFullscreen == isFullscreen
3096 && mLastFocusIsImmersive == isImmersive
Tiger Huang7c610aa2018-10-27 00:01:01 +08003097 && mFocusedApp == win.getAppToken()
3098 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
3099 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
3100 return 0;
3101 }
Tiger Huang0dbd5372019-10-26 00:24:22 +08003102
3103 // Obtains which types should show transient and which types should abort transient.
3104 // If there is no transient state change, this pair will contain two empty arrays.
3105 final Pair<int[], int[]> transientState = getTransientState(visibility, mLastSystemUiFlags);
3106
Tiger Huang7c610aa2018-10-27 00:01:01 +08003107 mLastSystemUiFlags = visibility;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003108 mLastAppearance = appearance;
3109 mLastFullscreenAppearance = fullscreenAppearance;
3110 mLastDockedAppearance = dockedAppearance;
3111 mLastFocusIsFullscreen = isFullscreen;
3112 mLastFocusIsImmersive = isImmersive;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003113 mFocusedApp = win.getAppToken();
Riddle Hsu4d6a63f2019-03-29 19:14:43 +08003114 mLastNonDockedStackBounds.set(mNonDockedStackBounds);
3115 mLastDockedStackBounds.set(mDockedStackBounds);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003116 final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
3117 final Rect dockedStackBounds = new Rect(mDockedStackBounds);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003118 final AppearanceRegion[] appearanceRegions = inSplitScreen
3119 ? new AppearanceRegion[]{
3120 new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds),
3121 new AppearanceRegion(dockedAppearance, dockedStackBounds)}
3122 : new AppearanceRegion[]{
3123 new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds)};
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003124 final boolean isNavbarColorManagedByIme = result.second;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003125 mHandler.post(() -> {
3126 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
3127 if (statusBar != null) {
3128 final int displayId = getDisplayId();
Tiger Huang0dbd5372019-10-26 00:24:22 +08003129 statusBar.setDisableFlags(displayId, visibility & StatusBarManager.DISABLE_MASK,
3130 win.toString());
3131 if (transientState.first.length > 0) {
3132 statusBar.showTransient(displayId, transientState.first);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003133 }
Tiger Huang0dbd5372019-10-26 00:24:22 +08003134 if (transientState.second.length > 0) {
3135 statusBar.abortTransient(displayId, transientState.second);
3136 }
3137 statusBar.onSystemBarAppearanceChanged(displayId, appearance,
3138 appearanceRegions, isNavbarColorManagedByIme);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003139 statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive);
3140
3141 // TODO(b/118118435): Remove this after removing system UI visibilities.
Tiger Huang1d739fb2019-10-22 21:05:16 +08003142 mDisplayContent.statusBarVisibilityChanged(
3143 visibility & ~(View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE));
Tiger Huang7c610aa2018-10-27 00:01:01 +08003144 }
3145 });
3146 return diff;
3147 }
3148
Tiger Huang0dbd5372019-10-26 00:24:22 +08003149 private static Pair<int[], int[]> getTransientState(int vis, int oldVis) {
3150 final IntArray typesToShow = new IntArray(0);
3151 final IntArray typesToAbort = new IntArray(0);
3152 updateTransientState(vis, oldVis, View.STATUS_BAR_TRANSIENT, TYPE_TOP_BAR, typesToShow,
3153 typesToAbort);
3154 updateTransientState(vis, oldVis, View.NAVIGATION_BAR_TRANSIENT,
3155 InsetsState.TYPE_NAVIGATION_BAR, typesToShow, typesToAbort);
3156 return Pair.create(typesToShow.toArray(), typesToAbort.toArray());
Tiger Huang7c610aa2018-10-27 00:01:01 +08003157 }
3158
Tiger Huang0dbd5372019-10-26 00:24:22 +08003159 private static void updateTransientState(int vis, int oldVis, int transientFlag,
3160 @InternalInsetType int type, IntArray typesToShow, IntArray typesToAbort) {
3161 final boolean wasTransient = (oldVis & transientFlag) != 0;
3162 final boolean isTransient = (vis & transientFlag) != 0;
3163 if (!wasTransient && isTransient) {
3164 typesToShow.add(type);
3165 } else if (wasTransient && !isTransient) {
3166 typesToAbort.add(type);
3167 }
3168 }
3169
3170 private int updateLightStatusBarAppearanceLw(@Appearance int appearance, WindowState opaque,
Jorim Jaggi956ca412019-01-07 14:49:14 +01003171 WindowState opaqueOrDimming) {
3172 final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded();
3173 final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
3174 if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
3175 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
3176 // its light flag.
3177 appearance &= ~APPEARANCE_LIGHT_TOP_BAR;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003178 final int legacyAppearance = InsetsFlags.getAppearance(
3179 PolicyControl.getSystemUiVisibility(statusColorWin, null));
3180 appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance)
3181 & APPEARANCE_LIGHT_TOP_BAR;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003182 } else if (statusColorWin != null && statusColorWin.isDimming()) {
3183 // Otherwise if it's dimming, clear the light flag.
3184 appearance &= ~APPEARANCE_LIGHT_TOP_BAR;
3185 }
3186 return appearance;
3187 }
3188
Tiger Huang7c610aa2018-10-27 00:01:01 +08003189 @VisibleForTesting
3190 @Nullable
3191 static WindowState chooseNavigationColorWindowLw(WindowState opaque,
3192 WindowState opaqueOrDimming, WindowState imeWindow,
3193 @NavigationBarPosition int navBarPosition) {
3194 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
3195 // window can be navigation color window.
3196 final boolean imeWindowCanNavColorWindow = imeWindow != null
3197 && imeWindow.isVisibleLw()
3198 && navBarPosition == NAV_BAR_BOTTOM
3199 && (PolicyControl.getWindowFlags(imeWindow, null)
3200 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3201
3202 if (opaque != null && opaqueOrDimming == opaque) {
3203 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
3204 // unless IME window is also eligible, since currently the IME window is always show
3205 // above the opaque fullscreen app window, regardless of the IME target window.
3206 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
3207 return imeWindowCanNavColorWindow ? imeWindow : opaque;
3208 }
3209
3210 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
3211 // No dimming window is involved. Determine the result only with the IME window.
3212 return imeWindowCanNavColorWindow ? imeWindow : null;
3213 }
3214
3215 if (!imeWindowCanNavColorWindow) {
3216 // No IME window is involved. Determine the result only with opaqueOrDimming.
3217 return opaqueOrDimming;
3218 }
3219
3220 // The IME window and the dimming window are competing. Check if the dimming window can be
3221 // IME target or not.
3222 if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3223 // The IME window is above the dimming window.
3224 return imeWindow;
3225 } else {
3226 // The dimming window is above the IME window.
3227 return opaqueOrDimming;
3228 }
3229 }
3230
3231 @VisibleForTesting
3232 static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3233 WindowState imeWindow, WindowState navColorWin) {
3234
3235 if (navColorWin != null) {
3236 if (navColorWin == imeWindow || navColorWin == opaque) {
3237 // Respect the light flag.
3238 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3239 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3240 & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3241 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3242 // Clear the light flag for dimming window.
3243 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3244 }
3245 }
3246 return vis;
3247 }
3248
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003249 private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003250 final boolean dockedStackVisible =
3251 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3252 final boolean freeformStackVisible =
3253 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3254 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3255
3256 // We need to force system bars when the docked stack is visible, when the freeform stack
hyok.kim332ccfc2019-07-02 15:39:43 +09003257 // is focused but also when we are resizing for the transitions when docked stack
Tiger Huang7c610aa2018-10-27 00:01:01 +08003258 // visibility changes.
hyok.kim332ccfc2019-07-02 15:39:43 +09003259 mForceShowSystemBars = dockedStackVisible || win.inFreeformWindowingMode() || resizing
Brad Stenninge0573692019-03-11 13:52:46 -07003260 || mForceShowSystemBarsFromExternal;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003261 final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
3262
3263 // apply translucent bar vis flags
3264 WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded()
3265 ? mStatusBar
3266 : mTopFullscreenOpaqueWindowState;
3267 vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3268 vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
Adrian Roosfaba4062019-05-14 15:27:17 +02003269 int dockedVis = mStatusBarController.applyTranslucentFlagLw(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003270 mTopDockedOpaqueWindowState, 0, 0);
Adrian Roosfaba4062019-05-14 15:27:17 +02003271 dockedVis = mNavigationBarController.applyTranslucentFlagLw(
3272 mTopDockedOpaqueWindowState, dockedVis, 0);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003273
3274 final boolean fullscreenDrawsStatusBarBackground =
3275 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3276 final boolean dockedDrawsStatusBarBackground =
3277 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003278 final boolean fullscreenDrawsNavBarBackground =
3279 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
Adrian Roosfaba4062019-05-14 15:27:17 +02003280 final boolean dockedDrawsNavigationBarBackground =
3281 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003282
3283 // prevent status bar interaction from clearing certain flags
3284 int type = win.getAttrs().type;
3285 boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
3286 if (statusBarHasFocus && !isStatusBarKeyguard()) {
3287 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3288 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3289 | View.SYSTEM_UI_FLAG_IMMERSIVE
3290 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3291 | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3292 if (isKeyguardOccluded()) {
3293 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3294 }
3295 vis = (vis & ~flags) | (oldVis & flags);
3296 }
3297
3298 if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3299 vis |= View.STATUS_BAR_TRANSPARENT;
3300 vis &= ~View.STATUS_BAR_TRANSLUCENT;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003301 } else if (forceOpaqueStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003302 vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3303 }
3304
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003305 vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003306 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003307
3308 // update status bar
3309 boolean immersiveSticky =
3310 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3311 final boolean hideStatusBarWM =
3312 mTopFullscreenOpaqueWindowState != null
3313 && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3314 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3315 final boolean hideStatusBarSysui =
3316 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3317 final boolean hideNavBarSysui =
3318 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3319
3320 final boolean transientStatusBarAllowed = mStatusBar != null
3321 && (statusBarHasFocus || (!mForceShowSystemBars
3322 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3323
3324 final boolean transientNavBarAllowed = mNavigationBar != null
3325 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3326
3327 final long now = SystemClock.uptimeMillis();
3328 final boolean pendingPanic = mPendingPanicGestureUptime != 0
3329 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3330 final DisplayPolicy defaultDisplayPolicy =
3331 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
3332 if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
3333 // TODO (b/111955725): Show keyguard presentation on all external displays
3334 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3335 // The user performed the panic gesture recently, we're about to hide the bars,
3336 // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3337 mPendingPanicGestureUptime = 0;
3338 mStatusBarController.showTransient();
3339 if (!isNavBarEmpty(vis)) {
3340 mNavigationBarController.showTransient();
3341 }
3342 }
3343
3344 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3345 && !transientStatusBarAllowed && hideStatusBarSysui;
3346 final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3347 && !transientNavBarAllowed;
3348 if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3349 // clear the clearable flags instead
3350 clearClearableFlagsLw();
3351 vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3352 }
3353
3354 final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3355 immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3356 final boolean navAllowedHidden = immersive || immersiveSticky;
3357
3358 if (hideNavBarSysui && !navAllowedHidden
3359 && mService.mPolicy.getWindowLayerLw(win)
3360 > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3361 // We can't hide the navbar from this window otherwise the input consumer would not get
3362 // the input events.
3363 vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3364 }
3365
3366 vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3367
3368 // update navigation bar
3369 boolean oldImmersiveMode = isImmersiveMode(oldVis);
3370 boolean newImmersiveMode = isImmersiveMode(vis);
3371 if (oldImmersiveMode != newImmersiveMode) {
3372 final String pkg = win.getOwningPackage();
3373 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3374 mService.mPolicy.isUserSetupComplete(),
3375 isNavBarEmpty(win.getSystemUiVisibility()));
3376 }
3377
3378 vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3379
3380 final WindowState navColorWin = chooseNavigationColorWindowLw(
3381 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3382 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3383 vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3384 mTopFullscreenOpaqueOrDimmingWindowState,
3385 mDisplayContent.mInputMethodWindow, navColorWin);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003386 // Navbar color is controlled by the IME.
3387 final boolean isManagedByIme =
3388 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003389
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003390 return Pair.create(vis, isManagedByIme);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003391 }
3392
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003393 private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
3394 int translucentFlag) {
3395 if (!controller.isTransparentAllowed(win)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003396 return false;
3397 }
3398 if (win == null) {
3399 return true;
3400 }
3401
3402 final boolean drawsSystemBars =
3403 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3404 final boolean forceDrawsSystemBars =
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003405 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003406
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003407 return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
3408 }
3409
3410 private boolean drawsStatusBarBackground(int vis, WindowState win) {
3411 return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
3412 }
3413
3414 private boolean drawsNavigationBarBackground(int vis, WindowState win) {
3415 return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003416 }
3417
3418 /**
3419 * @return the current visibility flags with the nav-bar opacity related flags toggled based
3420 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3421 */
3422 private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003423 boolean freeformStackVisible, boolean isDockedDividerResizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003424 boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
3425 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
3426 if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
3427 visibility = setNavBarTransparentFlag(visibility);
3428 } else if (dockedStackVisible) {
3429 visibility = setNavBarOpaqueFlag(visibility);
3430 }
3431 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003432 if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003433 if (mIsFreeformWindowOverlappingWithNavBar) {
3434 visibility = setNavBarTranslucentFlag(visibility);
3435 } else {
3436 visibility = setNavBarOpaqueFlag(visibility);
3437 }
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003438 } else if (fullscreenDrawsBackground) {
3439 visibility = setNavBarTransparentFlag(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003440 }
3441 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3442 if (isDockedDividerResizing) {
3443 visibility = setNavBarOpaqueFlag(visibility);
3444 } else if (freeformStackVisible) {
3445 visibility = setNavBarTranslucentFlag(visibility);
3446 } else {
3447 visibility = setNavBarOpaqueFlag(visibility);
3448 }
3449 }
3450
Tiger Huang7c610aa2018-10-27 00:01:01 +08003451 return visibility;
3452 }
3453
3454 private int setNavBarOpaqueFlag(int visibility) {
3455 return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3456 }
3457
3458 private int setNavBarTranslucentFlag(int visibility) {
3459 visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3460 return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3461 }
3462
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003463 private int setNavBarTransparentFlag(int visibility) {
3464 visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3465 return visibility | View.NAVIGATION_BAR_TRANSPARENT;
3466 }
3467
Tiger Huang7c610aa2018-10-27 00:01:01 +08003468 private void clearClearableFlagsLw() {
3469 int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3470 if (newVal != mResettingSystemUiFlags) {
3471 mResettingSystemUiFlags = newVal;
3472 mDisplayContent.reevaluateStatusBarVisibility();
3473 }
3474 }
3475
3476 private boolean isImmersiveMode(int vis) {
3477 final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3478 return mNavigationBar != null
3479 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3480 && (vis & flags) != 0
3481 && canHideNavigationBar();
3482 }
3483
3484 /**
3485 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3486 */
3487 private boolean canHideNavigationBar() {
3488 return hasNavigationBar();
3489 }
3490
3491 private static boolean isNavBarEmpty(int systemUiFlags) {
3492 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3493 | View.STATUS_BAR_DISABLE_BACK
3494 | View.STATUS_BAR_DISABLE_RECENT);
3495
3496 return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3497 }
3498
Tiger Huang7c610aa2018-10-27 00:01:01 +08003499 private final Runnable mHiddenNavPanic = new Runnable() {
3500 @Override
3501 public void run() {
3502 synchronized (mLock) {
3503 if (!mService.mPolicy.isUserSetupComplete()) {
3504 // Swipe-up for navigation bar is disabled during setup
3505 return;
3506 }
3507 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3508 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3509 mNavigationBarController.showTransient();
Jorim Jaggi956ca412019-01-07 14:49:14 +01003510 mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
3511 new int[] {InsetsState.TYPE_NAVIGATION_BAR}));
Tiger Huang7c610aa2018-10-27 00:01:01 +08003512 }
3513 }
3514 }
3515 };
3516
3517 void onPowerKeyDown(boolean isScreenOn) {
3518 // Detect user pressing the power button in panic when an application has
3519 // taken over the whole screen.
3520 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3521 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3522 isNavBarEmpty(mLastSystemUiFlags));
3523 if (panic) {
3524 mHandler.post(mHiddenNavPanic);
3525 }
3526 }
3527
3528 void onVrStateChangedLw(boolean enabled) {
3529 mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3530 }
3531
3532 /**
3533 * Called when the state of lock task mode changes. This should be used to disable immersive
3534 * mode confirmation.
3535 *
3536 * @param lockTaskState the new lock task mode state. One of
3537 * {@link ActivityManager#LOCK_TASK_MODE_NONE},
3538 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3539 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3540 */
3541 public void onLockTaskStateChangedLw(int lockTaskState) {
3542 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3543 }
3544
3545 /**
3546 * Request a screenshot be taken.
3547 *
3548 * @param screenshotType The type of screenshot, for example either
3549 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3550 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3551 */
3552 public void takeScreenshot(int screenshotType) {
3553 if (mScreenshotHelper != null) {
3554 mScreenshotHelper.takeScreenshot(screenshotType,
3555 mStatusBar != null && mStatusBar.isVisibleLw(),
James O'Learyfa5bb7a2019-09-05 13:43:29 -04003556 mNavigationBar != null && mNavigationBar.isVisibleLw(),
3557 mHandler, null /* completionConsumer */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003558 }
3559 }
3560
Ady Abrahamf3e05312019-05-13 18:04:59 -07003561 RefreshRatePolicy getRefreshRatePolicy() {
3562 return mRefreshRatePolicy;
3563 }
3564
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003565 void dump(String prefix, PrintWriter pw) {
Riddle Hsuccf09402019-08-13 00:33:06 +08003566 pw.print(prefix); pw.println("DisplayPolicy");
Tiger Huang7c610aa2018-10-27 00:01:01 +08003567 prefix += " ";
3568 pw.print(prefix);
3569 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3570 pw.print(" mDeskDockEnablesAccelerometer=");
3571 pw.println(mDeskDockEnablesAccelerometer);
3572 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3573 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3574 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3575 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3576 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3577 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3578 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3579 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3580 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3581 || mForceClearedSystemUiFlags != 0) {
3582 pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3583 pw.print(Integer.toHexString(mLastSystemUiFlags));
3584 pw.print(" mResettingSystemUiFlags=0x");
3585 pw.print(Integer.toHexString(mResettingSystemUiFlags));
3586 pw.print(" mForceClearedSystemUiFlags=0x");
3587 pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3588 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003589 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3590 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3591 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3592 if (mStatusBar != null) {
3593 pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
3594 pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard());
3595 }
3596 if (mNavigationBar != null) {
3597 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
Winson Chung4723b4e2019-03-25 16:49:36 -07003598 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
3599 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
3600 pw.print(prefix); pw.print("mNavigationBarPosition=");
3601 pw.println(mNavigationBarPosition);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003602 }
3603 if (mFocusedWindow != null) {
3604 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3605 }
3606 if (mFocusedApp != null) {
3607 pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3608 }
3609 if (mTopFullscreenOpaqueWindowState != null) {
3610 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3611 pw.println(mTopFullscreenOpaqueWindowState);
3612 }
3613 if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3614 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3615 pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3616 }
3617 if (mForcingShowNavBar) {
3618 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3619 pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3620 pw.println(mForcingShowNavBarLayer);
3621 }
Riddle Hsuccf09402019-08-13 00:33:06 +08003622 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003623 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
3624 pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
Riddle Hsuccf09402019-08-13 00:33:06 +08003625 pw.print(prefix); pw.print("mForceShowSystemBarsFromExternal=");
3626 pw.print(mForceShowSystemBarsFromExternal);
3627 pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003628 mStatusBarController.dump(pw, prefix);
3629 mNavigationBarController.dump(pw, prefix);
3630
3631 pw.print(prefix); pw.println("Looper state:");
3632 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003633 }
Arthur Hung20479922019-02-27 17:13:22 +08003634
3635 private boolean supportsPointerLocation() {
3636 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
3637 }
3638
3639 void setPointerLocationEnabled(boolean pointerLocationEnabled) {
3640 if (!supportsPointerLocation()) {
3641 return;
3642 }
3643
3644 mHandler.sendEmptyMessage(pointerLocationEnabled
3645 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
3646 }
3647
3648 private void enablePointerLocation() {
3649 if (mPointerLocationView != null) {
3650 return;
3651 }
3652
3653 mPointerLocationView = new PointerLocationView(mContext);
3654 mPointerLocationView.setPrintCoords(false);
3655 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
3656 WindowManager.LayoutParams.MATCH_PARENT,
3657 WindowManager.LayoutParams.MATCH_PARENT);
3658 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3659 lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
3660 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3661 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3662 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3663 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3664 if (ActivityManager.isHighEndGfx()) {
3665 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3666 lp.privateFlags |=
3667 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3668 }
3669 lp.format = PixelFormat.TRANSLUCENT;
3670 lp.setTitle("PointerLocation - display " + getDisplayId());
3671 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3672 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3673 wm.addView(mPointerLocationView, lp);
3674 mDisplayContent.registerPointerEventListener(mPointerLocationView);
3675 }
3676
3677 private void disablePointerLocation() {
3678 if (mPointerLocationView == null) {
3679 return;
3680 }
3681
3682 mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3683 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3684 wm.removeView(mPointerLocationView);
3685 mPointerLocationView = null;
3686 }
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003687
Arthur Hungfbc8f412019-08-01 19:57:54 +08003688 /**
3689 * Check if the window could be excluded from checking if the display has content.
3690 *
3691 * @param w WindowState to check if should be excluded.
3692 * @return True if the window type is PointerLocation which is excluded.
3693 */
3694 boolean isWindowExcludedFromContent(WindowState w) {
3695 if (w != null && mPointerLocationView != null) {
3696 return w.mClient == mPointerLocationView.getWindowToken();
3697 }
3698
3699 return false;
3700 }
3701
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003702 @VisibleForTesting
3703 static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
3704 if (navBarWindow == null || !navBarWindow.isVisibleLw()
Garfield Tane8d84ab2019-10-11 09:49:40 -07003705 || targetWindow.mActivityRecord == null || !targetWindow.isVisibleLw()) {
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003706 return false;
3707 }
3708
3709 return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw());
3710 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003711}