blob: 67d8acf8daba79596aca571257ca3273a4d8d826 [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;
Tiger Huang332793b2019-10-29 23:21:27 +080028import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
29import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
30import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
31import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
32import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
33import static android.view.InsetsState.ITYPE_STATUS_BAR;
34import static android.view.InsetsState.ITYPE_TOP_GESTURES;
35import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
Tiger Huang4a7835f2019-11-06 00:07:56 +080036import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
Jorim Jaggid6490572019-04-16 14:57:56 +020037import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +080038import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
Jorim Jaggi956ca412019-01-07 14:49:14 +010039import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
Jorim Jaggi648e5882019-01-24 13:24:02 +010040import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
Tiger Huang332793b2019-10-29 23:21:27 +080041import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
Jorim Jaggi956ca412019-01-07 14:49:14 +010042import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
43import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080044import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
45import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
46import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
47import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
48import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
49import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
50import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
51import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
52import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
Tiger Huang7c610aa2018-10-27 00:01:01 +080053import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
54import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
Adrian Roos11dfd272019-03-25 19:21:26 +010055import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080056import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
57import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
58import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
59import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
Tiger Huang7c610aa2018-10-27 00:01:01 +080060import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
shawnlind0e23be2019-12-29 18:56:15 +080061import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
Arthur Hung20479922019-02-27 17:13:22 +080062import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
Jorim Jaggia6aabac2019-03-11 14:23:16 -070063import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
wilsonshihe8321942019-10-18 18:39:46 +080064import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
Tiger Huang7c610aa2018-10-27 00:01:01 +080065import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
Tiger Huang7c610aa2018-10-27 00:01:01 +080066import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +080067import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
68import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
69import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
70import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
71import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
72import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
73import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
74import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
75import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
Charles Chen64172bb2019-04-22 17:30:29 +080076import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
Tiger Huang7c610aa2018-10-27 00:01:01 +080077import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
78import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
wilsonshihe8321942019-10-18 18:39:46 +080079import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080080import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
81import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
82import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
83import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
84import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
85import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
86import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
87import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
88import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
89import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
90import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
91import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
92import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
93import static android.view.WindowManagerGlobal.ADD_OKAY;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080094import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
95import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080096import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
97import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
98import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
99
100import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
101import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
102import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
103import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
104import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
105import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
106import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800107import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800108import static com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200109import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800110import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
111import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800112import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
113import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
114
Jorim Jaggi4981f152019-03-26 18:58:45 +0100115import android.Manifest.permission;
Issei Suzukia5dbf522019-02-01 17:58:15 +0100116import android.annotation.NonNull;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800117import android.annotation.Nullable;
Jorim Jaggi4981f152019-03-26 18:58:45 +0100118import android.annotation.Px;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800119import android.app.ActivityManager;
120import android.app.ActivityThread;
Winson Chungda20fec2019-04-10 12:19:59 -0700121import android.app.LoadedApk;
122import android.app.ResourcesManager;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800123import android.app.StatusBarManager;
124import android.content.Context;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800125import android.content.Intent;
Jorim Jaggi4981f152019-03-26 18:58:45 +0100126import android.content.pm.PackageManager;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800127import android.content.res.Resources;
Issei Suzukia5dbf522019-02-01 17:58:15 +0100128import android.graphics.Insets;
Arthur Hung20479922019-02-27 17:13:22 +0800129import android.graphics.PixelFormat;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800130import android.graphics.Rect;
Winson Chung36941632019-04-19 15:21:38 -0700131import android.graphics.Region;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800132import android.hardware.input.InputManager;
133import android.hardware.power.V1_0.PowerHint;
134import android.os.Handler;
135import android.os.Looper;
136import android.os.Message;
137import android.os.SystemClock;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800138import android.os.SystemProperties;
139import android.os.UserHandle;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800140import android.util.ArraySet;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100141import android.util.IntArray;
Tarandeep Singhe439dec2019-04-22 12:28:43 -0700142import android.util.Pair;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800143import android.util.PrintWriterPrinter;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800144import android.util.Slog;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800145import android.view.DisplayCutout;
146import android.view.Gravity;
147import android.view.IApplicationToken;
148import android.view.InputChannel;
149import android.view.InputDevice;
150import android.view.InputEvent;
151import android.view.InputEventReceiver;
Tiger Huang0dbd5372019-10-26 00:24:22 +0800152import android.view.InsetsFlags;
Tiger Huang4a7835f2019-11-06 00:07:56 +0800153import android.view.InsetsState;
Tiger Huang332793b2019-10-29 23:21:27 +0800154import android.view.InsetsState.InternalInsetsType;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800155import android.view.MotionEvent;
156import android.view.PointerIcon;
157import android.view.Surface;
158import android.view.View;
Jorim Jaggi648e5882019-01-24 13:24:02 +0100159import android.view.ViewRootImpl;
Tiger Huang4a7835f2019-11-06 00:07:56 +0800160import android.view.WindowInsets.Side;
161import android.view.WindowInsets.Side.InsetsSide;
162import android.view.WindowInsets.Type;
163import android.view.WindowInsets.Type.InsetsType;
Tiger Huang0dbd5372019-10-26 00:24:22 +0800164import android.view.WindowInsetsController.Appearance;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800165import android.view.WindowManager;
166import android.view.WindowManager.LayoutParams;
167import android.view.WindowManagerGlobal;
168import android.view.WindowManagerPolicyConstants;
169import android.view.accessibility.AccessibilityManager;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800170
Tiger Huang7c610aa2018-10-27 00:01:01 +0800171import com.android.internal.R;
172import com.android.internal.annotations.GuardedBy;
173import com.android.internal.annotations.VisibleForTesting;
Tiger Huang43b8fc22019-04-26 11:49:29 +0800174import com.android.internal.policy.ScreenDecorationsUtils;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800175import com.android.internal.util.ScreenshotHelper;
Adrian Roos11dfd272019-03-25 19:21:26 +0100176import com.android.internal.util.function.TriConsumer;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100177import com.android.internal.view.AppearanceRegion;
Arthur Hung20479922019-02-27 17:13:22 +0800178import com.android.internal.widget.PointerLocationView;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800179import com.android.server.LocalServices;
180import com.android.server.UiThread;
181import com.android.server.policy.WindowManagerPolicy;
182import com.android.server.policy.WindowManagerPolicy.InputConsumer;
183import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800184import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
185import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800186import com.android.server.policy.WindowOrientationListener;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200187import com.android.server.protolog.common.ProtoLog;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800188import com.android.server.statusbar.StatusBarManagerInternal;
wilsonshih643bf132019-02-27 12:49:19 +0800189import com.android.server.wallpaper.WallpaperManagerInternal;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800190import com.android.server.wm.utils.InsetUtils;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800191
192import java.io.PrintWriter;
193
194/**
195 * The policy that provides the basic behaviors and states of a display to show UI.
196 */
197public class DisplayPolicy {
198 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800199 private static final boolean DEBUG = false;
200
201 private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
202
203 // The panic gesture may become active only after the keyguard is dismissed and the immersive
204 // app shows again. If that doesn't happen for 30s we drop the gesture.
205 private static final long PANIC_GESTURE_EXPIRATION = 30000;
206
207 // Controls navigation bar opacity depending on which workspace stacks are currently
208 // visible.
209 // Nav bar is always opaque when either the freeform stack or docked stack is visible.
210 private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
211 // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
212 private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
Adrian Roosfaba4062019-05-14 15:27:17 +0200213 // Nav bar is never forced opaque.
214 private static final int NAV_BAR_FORCE_TRANSPARENT = 2;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800215
Riddle Hsu2ca561b2019-10-08 21:58:58 +0800216 /** Don't apply window animation (see {@link #selectAnimation}). */
217 static final int ANIMATION_NONE = -1;
218 /** Use the transit animation in style resource (see {@link #selectAnimation}). */
219 static final int ANIMATION_STYLEABLE = 0;
220
Tiger Huang7c610aa2018-10-27 00:01:01 +0800221 /**
222 * These are the system UI flags that, when changing, can cause the layout
223 * of the screen to change.
224 */
225 private static final int SYSTEM_UI_CHANGING_LAYOUT =
226 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
227 | View.SYSTEM_UI_FLAG_FULLSCREEN
228 | View.STATUS_BAR_TRANSLUCENT
229 | View.NAVIGATION_BAR_TRANSLUCENT
230 | View.STATUS_BAR_TRANSPARENT
231 | View.NAVIGATION_BAR_TRANSPARENT;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800232
233 private final WindowManagerService mService;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800234 private final Context mContext;
Charles Chen173ae782019-11-11 20:39:02 +0800235 private final Context mUiContext;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800236 private final DisplayContent mDisplayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800237 private final Object mLock;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800238 private final Handler mHandler;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800239
Winson Chungda20fec2019-04-10 12:19:59 -0700240 private Resources mCurrentUserResources;
241
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800242 private final boolean mCarDockEnablesAccelerometer;
243 private final boolean mDeskDockEnablesAccelerometer;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800244 private final AccessibilityManager mAccessibilityManager;
245 private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
246 private final ScreenshotHelper mScreenshotHelper;
247
248 private final Object mServiceAcquireLock = new Object();
249 private StatusBarManagerInternal mStatusBarManagerInternal;
250
Adrian Roos11dfd272019-03-25 19:21:26 +0100251 @Px
252 private int mBottomGestureAdditionalInset;
253 @Px
254 private int mSideGestureInset;
Adrian Roos11dfd272019-03-25 19:21:26 +0100255
Jorim Jaggi956ca412019-01-07 14:49:14 +0100256 StatusBarManagerInternal getStatusBarManagerInternal() {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800257 synchronized (mServiceAcquireLock) {
258 if (mStatusBarManagerInternal == null) {
259 mStatusBarManagerInternal =
260 LocalServices.getService(StatusBarManagerInternal.class);
261 }
262 return mStatusBarManagerInternal;
263 }
264 }
265
Tiger Huang7c610aa2018-10-27 00:01:01 +0800266 private final SystemGesturesPointerEventListener mSystemGestures;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800267
268 private volatile int mLidState = LID_ABSENT;
269 private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
270 private volatile boolean mHdmiPlugged;
271
Louis Changfc64c832018-12-04 11:38:26 +0800272 private volatile boolean mHasStatusBar;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800273 private volatile boolean mHasNavigationBar;
274 // Can the navigation bar ever move to the side?
275 private volatile boolean mNavigationBarCanMove;
Winson Chung36941632019-04-19 15:21:38 -0700276 private volatile boolean mNavigationBarLetsThroughTaps;
277 private volatile boolean mNavigationBarAlwaysShowOnSideGesture;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800278
279 // Written by vr manager thread, only read in this class.
280 private volatile boolean mPersistentVrModeEnabled;
281
282 private volatile boolean mAwake;
283 private volatile boolean mScreenOnEarly;
284 private volatile boolean mScreenOnFully;
285 private volatile ScreenOnListener mScreenOnListener;
286
287 private volatile boolean mKeyguardDrawComplete;
288 private volatile boolean mWindowManagerDrawComplete;
289
Tiger Huang7c610aa2018-10-27 00:01:01 +0800290 private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
291 private WindowState mStatusBar = null;
wilsonshihe8321942019-10-18 18:39:46 +0800292 private WindowState mNotificationShade = null;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800293 private final int[] mStatusBarHeightForRotation = new int[4];
294 private WindowState mNavigationBar = null;
295 @NavigationBarPosition
296 private int mNavigationBarPosition = NAV_BAR_BOTTOM;
297 private int[] mNavigationBarHeightForRotationDefault = new int[4];
298 private int[] mNavigationBarWidthForRotationDefault = new int[4];
299 private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
300 private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
301
Matthew Nga7f24bc2019-04-09 17:06:41 -0700302 /** See {@link #getNavigationBarFrameHeight} */
303 private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
304
HEO SEUNG22d3ec22019-05-30 20:28:53 +0900305 private boolean mIsFreeformWindowOverlappingWithNavBar;
306
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800307 private final StatusBarController mStatusBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800308
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800309 private final BarController mNavigationBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800310
311 private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
312 new BarController.OnBarVisibilityChangedListener() {
313 @Override
314 public void onBarVisibilityChanged(boolean visible) {
315 if (mAccessibilityManager == null) {
316 return;
317 }
318 mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
319 }
320 };
321
Tiger Huang7c610aa2018-10-27 00:01:01 +0800322 @GuardedBy("mHandler")
323 private SleepToken mDreamingSleepToken;
324
325 @GuardedBy("mHandler")
326 private SleepToken mWindowSleepToken;
327
328 private final Runnable mAcquireSleepTokenRunnable;
329 private final Runnable mReleaseSleepTokenRunnable;
330
331 // The windows we were told about in focusChanged.
332 private WindowState mFocusedWindow;
333 private WindowState mLastFocusedWindow;
334
335 IApplicationToken mFocusedApp;
336
337 int mLastSystemUiFlags;
338 // Bits that we are in the process of clearing, so we want to prevent
339 // them from being set by applications until everything has been updated
340 // to have them clear.
341 private int mResettingSystemUiFlags = 0;
342 // Bits that we are currently always keeping cleared.
343 private int mForceClearedSystemUiFlags = 0;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100344 private int mLastAppearance;
345 private int mLastFullscreenAppearance;
346 private int mLastDockedAppearance;
Tiger Huang4a7835f2019-11-06 00:07:56 +0800347 private int mLastBehavior;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800348 private final Rect mNonDockedStackBounds = new Rect();
349 private final Rect mDockedStackBounds = new Rect();
350 private final Rect mLastNonDockedStackBounds = new Rect();
351 private final Rect mLastDockedStackBounds = new Rect();
352
Jorim Jaggi956ca412019-01-07 14:49:14 +0100353 // What we last reported to system UI about whether the focused window is fullscreen/immersive.
354 private boolean mLastFocusIsFullscreen = false;
355 private boolean mLastFocusIsImmersive = false;
356
Tiger Huang7c610aa2018-10-27 00:01:01 +0800357 // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
358 private long mPendingPanicGestureUptime;
359
360 private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
361 private static final Rect sTmpRect = new Rect();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800362 private static final Rect sTmpNavFrame = new Rect();
363 private static final Rect sTmpLastParentFrame = new Rect();
364
365 private WindowState mTopFullscreenOpaqueWindowState;
366 private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
367 private WindowState mTopDockedOpaqueWindowState;
368 private WindowState mTopDockedOpaqueOrDimmingWindowState;
369 private boolean mTopIsFullscreen;
370 private boolean mForceStatusBar;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800371 private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
372 private boolean mForcingShowNavBar;
373 private int mForcingShowNavBarLayer;
374 private boolean mForceShowSystemBars;
375
Brad Stenninge0573692019-03-11 13:52:46 -0700376 /**
377 * Force the display of system bars regardless of other settings.
378 */
379 private boolean mForceShowSystemBarsFromExternal;
380
Tiger Huang7c610aa2018-10-27 00:01:01 +0800381 private boolean mShowingDream;
382 private boolean mLastShowingDream;
383 private boolean mDreamingLockscreen;
384 private boolean mDreamingSleepTokenNeeded;
385 private boolean mWindowSleepTokenNeeded;
386 private boolean mLastWindowSleepTokenNeeded;
387 private boolean mAllowLockscreenWhenOn;
388
389 private InputConsumer mInputConsumer = null;
390
Arthur Hung20479922019-02-27 17:13:22 +0800391 private PointerLocationView mPointerLocationView;
392
Issei Suzukia5dbf522019-02-01 17:58:15 +0100393 /**
394 * The area covered by system windows which belong to another display. Forwarded insets is set
395 * in case this is a virtual display, this is displayed on another display that has insets, and
396 * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
397 * displayed on the host display, and it covers a part of this virtual display.)
398 * The forwarded insets is used to compute display frames of this virtual display, which will
399 * be then used to layout windows in the virtual display.
400 */
401 @NonNull private Insets mForwardedInsets = Insets.NONE;
402
Ady Abrahamf3e05312019-05-13 18:04:59 -0700403 private RefreshRatePolicy mRefreshRatePolicy;
404
Tiger Huang7c610aa2018-10-27 00:01:01 +0800405 // -------- PolicyHandler --------
406 private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
407 private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
408 private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
Arthur Hung20479922019-02-27 17:13:22 +0800409 private static final int MSG_ENABLE_POINTER_LOCATION = 4;
410 private static final int MSG_DISABLE_POINTER_LOCATION = 5;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800411
412 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
413 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
414
415 private class PolicyHandler extends Handler {
416
417 PolicyHandler(Looper looper) {
418 super(looper);
419 }
420
421 @Override
422 public void handleMessage(Message msg) {
423 switch (msg.what) {
424 case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
425 updateDreamingSleepToken(msg.arg1 != 0);
426 break;
427 case MSG_REQUEST_TRANSIENT_BARS:
428 WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
429 ? mStatusBar : mNavigationBar;
430 if (targetBar != null) {
431 requestTransientBars(targetBar);
432 }
433 break;
434 case MSG_DISPOSE_INPUT_CONSUMER:
435 disposeInputConsumer((InputConsumer) msg.obj);
436 break;
Arthur Hung20479922019-02-27 17:13:22 +0800437 case MSG_ENABLE_POINTER_LOCATION:
438 enablePointerLocation();
439 break;
440 case MSG_DISABLE_POINTER_LOCATION:
441 disablePointerLocation();
442 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800443 }
444 }
445 }
446
447 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800448 mService = service;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800449 mContext = displayContent.isDefaultDisplay ? service.mContext
450 : service.mContext.createDisplayContext(displayContent.getDisplay());
Charles Chen173ae782019-11-11 20:39:02 +0800451 mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
452 : service.mAtmService.mSystemThread
453 .createSystemUiContext(displayContent.getDisplayId());
Tiger Huang7c610aa2018-10-27 00:01:01 +0800454 mDisplayContent = displayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800455 mLock = service.getWindowManagerLock();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800456
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800457 final int displayId = displayContent.getDisplayId();
458 mStatusBarController = new StatusBarController(displayId);
459 mNavigationBarController = new BarController("NavigationBar",
460 displayId,
461 View.NAVIGATION_BAR_TRANSIENT,
462 View.NAVIGATION_BAR_UNHIDE,
463 View.NAVIGATION_BAR_TRANSLUCENT,
464 StatusBarManager.WINDOW_NAVIGATION_BAR,
465 FLAG_TRANSLUCENT_NAVIGATION,
466 View.NAVIGATION_BAR_TRANSPARENT);
467
Tiger Huang7c610aa2018-10-27 00:01:01 +0800468 final Resources r = mContext.getResources();
469 mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
470 mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
Brad Stenninge0573692019-03-11 13:52:46 -0700471 mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800472
473 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
474 Context.ACCESSIBILITY_SERVICE);
475 if (!displayContent.isDefaultDisplay) {
476 mAwake = true;
477 mScreenOnEarly = true;
478 mScreenOnFully = true;
479 }
480
481 final Looper looper = UiThread.getHandler().getLooper();
482 mHandler = new PolicyHandler(looper);
483 mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
484 new SystemGesturesPointerEventListener.Callbacks() {
485 @Override
486 public void onSwipeFromTop() {
487 if (mStatusBar != null) {
488 requestTransientBars(mStatusBar);
489 }
490 }
491
492 @Override
493 public void onSwipeFromBottom() {
Winson Chung36941632019-04-19 15:21:38 -0700494 if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800495 requestTransientBars(mNavigationBar);
496 }
497 }
498
499 @Override
500 public void onSwipeFromRight() {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200501 final Region excludedRegion = Region.obtain();
Jeff Chang3cf3e562019-06-18 11:51:25 +0800502 synchronized (mLock) {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200503 mDisplayContent.calculateSystemGestureExclusion(
504 excludedRegion, null /* outUnrestricted */);
Jeff Chang3cf3e562019-06-18 11:51:25 +0800505 }
Winson Chung36941632019-04-19 15:21:38 -0700506 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
507 || mNavigationBarPosition == NAV_BAR_RIGHT;
508 if (mNavigationBar != null && sideAllowed
509 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800510 requestTransientBars(mNavigationBar);
511 }
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200512 excludedRegion.recycle();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800513 }
514
515 @Override
516 public void onSwipeFromLeft() {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200517 final Region excludedRegion = Region.obtain();
Jeff Chang3cf3e562019-06-18 11:51:25 +0800518 synchronized (mLock) {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200519 mDisplayContent.calculateSystemGestureExclusion(
520 excludedRegion, null /* outUnrestricted */);
Jeff Chang3cf3e562019-06-18 11:51:25 +0800521 }
Winson Chung36941632019-04-19 15:21:38 -0700522 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
523 || mNavigationBarPosition == NAV_BAR_LEFT;
524 if (mNavigationBar != null && sideAllowed
525 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800526 requestTransientBars(mNavigationBar);
527 }
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200528 excludedRegion.recycle();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800529 }
530
531 @Override
532 public void onFling(int duration) {
533 if (mService.mPowerManagerInternal != null) {
534 mService.mPowerManagerInternal.powerHint(
535 PowerHint.INTERACTION, duration);
536 }
537 }
538
539 @Override
540 public void onDebug() {
541 // no-op
542 }
543
544 private WindowOrientationListener getOrientationListener() {
545 final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
546 return rotation != null ? rotation.getOrientationListener() : null;
547 }
548
549 @Override
550 public void onDown() {
551 final WindowOrientationListener listener = getOrientationListener();
552 if (listener != null) {
553 listener.onTouchStart();
554 }
555 }
556
557 @Override
558 public void onUpOrCancel() {
559 final WindowOrientationListener listener = getOrientationListener();
560 if (listener != null) {
561 listener.onTouchEnd();
562 }
563 }
564
565 @Override
566 public void onMouseHoverAtTop() {
567 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
568 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
569 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
570 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
571 }
572
573 @Override
574 public void onMouseHoverAtBottom() {
575 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
576 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
577 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
578 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
579 }
580
581 @Override
582 public void onMouseLeaveFromEdge() {
583 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
584 }
585 });
586 displayContent.registerPointerEventListener(mSystemGestures);
587 displayContent.mAppTransition.registerListenerLocked(
588 mStatusBarController.getAppTransitionListener());
589 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
590 mService.mVrModeEnabled);
591 mAcquireSleepTokenRunnable = () -> {
592 if (mWindowSleepToken != null) {
593 return;
594 }
Tiger Huang7c610aa2018-10-27 00:01:01 +0800595 mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
596 "WindowSleepTokenOnDisplay" + displayId, displayId);
597 };
598 mReleaseSleepTokenRunnable = () -> {
599 if (mWindowSleepToken == null) {
600 return;
601 }
602 mWindowSleepToken.release();
603 mWindowSleepToken = null;
604 };
605
606 // TODO: Make it can take screenshot on external display
607 mScreenshotHelper = displayContent.isDefaultDisplay
608 ? new ScreenshotHelper(mContext) : null;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800609
Tiger Huang7c610aa2018-10-27 00:01:01 +0800610 if (mDisplayContent.isDefaultDisplay) {
Louis Changfc64c832018-12-04 11:38:26 +0800611 mHasStatusBar = true;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800612 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800613
Tiger Huang7c610aa2018-10-27 00:01:01 +0800614 // Allow a system property to override this. Used by the emulator.
615 // See also hasNavigationBar().
616 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
617 if ("1".equals(navBarOverride)) {
618 mHasNavigationBar = false;
619 } else if ("0".equals(navBarOverride)) {
620 mHasNavigationBar = true;
621 }
622 } else {
Louis Changfc64c832018-12-04 11:38:26 +0800623 mHasStatusBar = false;
Andrii Kuliandd989612019-02-21 12:13:28 -0800624 mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800625 }
Ady Abrahamf3e05312019-05-13 18:04:59 -0700626
627 mRefreshRatePolicy = new RefreshRatePolicy(mService,
628 mDisplayContent.getDisplayInfo(),
629 mService.mHighRefreshRateBlacklist);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800630 }
631
Charles Chen5bdd3e22018-12-18 17:51:56 +0800632 void systemReady() {
633 mSystemGestures.systemReady();
Arthur Hung20479922019-02-27 17:13:22 +0800634 if (mService.mPointerLocationEnabled) {
635 setPointerLocationEnabled(true);
636 }
Charles Chen5bdd3e22018-12-18 17:51:56 +0800637 }
638
639 private int getDisplayId() {
640 return mDisplayContent.getDisplayId();
641 }
642
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800643 public void setHdmiPlugged(boolean plugged) {
644 setHdmiPlugged(plugged, false /* force */);
645 }
646
647 public void setHdmiPlugged(boolean plugged, boolean force) {
648 if (force || mHdmiPlugged != plugged) {
649 mHdmiPlugged = plugged;
650 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
651 final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
652 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
653 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800654 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800655 }
656 }
657
658 boolean isHdmiPlugged() {
659 return mHdmiPlugged;
660 }
661
662 boolean isCarDockEnablesAccelerometer() {
663 return mCarDockEnablesAccelerometer;
664 }
665
666 boolean isDeskDockEnablesAccelerometer() {
667 return mDeskDockEnablesAccelerometer;
668 }
669
670 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
671 mPersistentVrModeEnabled = persistentVrModeEnabled;
672 }
673
674 public boolean isPersistentVrModeEnabled() {
675 return mPersistentVrModeEnabled;
676 }
677
678 public void setDockMode(int dockMode) {
679 mDockMode = dockMode;
680 }
681
682 public int getDockMode() {
683 return mDockMode;
684 }
685
Brad Stenninge0573692019-03-11 13:52:46 -0700686 /**
687 * @see WindowManagerService.setForceShowSystemBars
688 */
689 void setForceShowSystemBars(boolean forceShowSystemBars) {
690 mForceShowSystemBarsFromExternal = forceShowSystemBars;
691 }
692
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800693 public boolean hasNavigationBar() {
694 return mHasNavigationBar;
695 }
696
Louis Changfc64c832018-12-04 11:38:26 +0800697 public boolean hasStatusBar() {
698 return mHasStatusBar;
699 }
700
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200701 boolean hasSideGestures() {
702 return mHasNavigationBar && mSideGestureInset > 0;
703 }
704
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800705 public boolean navigationBarCanMove() {
706 return mNavigationBarCanMove;
707 }
708
709 public void setLidState(int lidState) {
710 mLidState = lidState;
711 }
712
713 public int getLidState() {
714 return mLidState;
715 }
716
717 public void setAwake(boolean awake) {
718 mAwake = awake;
719 }
720
721 public boolean isAwake() {
722 return mAwake;
723 }
724
725 public boolean isScreenOnEarly() {
726 return mScreenOnEarly;
727 }
728
729 public boolean isScreenOnFully() {
730 return mScreenOnFully;
731 }
732
733 public boolean isKeyguardDrawComplete() {
734 return mKeyguardDrawComplete;
735 }
736
737 public boolean isWindowManagerDrawComplete() {
738 return mWindowManagerDrawComplete;
739 }
740
741 public ScreenOnListener getScreenOnListener() {
742 return mScreenOnListener;
743 }
744
745 public void screenTurnedOn(ScreenOnListener screenOnListener) {
746 synchronized (mLock) {
747 mScreenOnEarly = true;
748 mScreenOnFully = false;
749 mKeyguardDrawComplete = false;
750 mWindowManagerDrawComplete = false;
751 mScreenOnListener = screenOnListener;
752 }
753 }
754
755 public void screenTurnedOff() {
756 synchronized (mLock) {
757 mScreenOnEarly = false;
758 mScreenOnFully = false;
759 mKeyguardDrawComplete = false;
760 mWindowManagerDrawComplete = false;
761 mScreenOnListener = null;
762 }
763 }
764
765 /** Return false if we are not awake yet or we have already informed of this event. */
766 public boolean finishKeyguardDrawn() {
767 synchronized (mLock) {
768 if (!mScreenOnEarly || mKeyguardDrawComplete) {
769 return false;
770 }
771
772 mKeyguardDrawComplete = true;
773 mWindowManagerDrawComplete = false;
774 }
775 return true;
776 }
777
778 /** Return false if screen is not turned on or we did already handle this case earlier. */
779 public boolean finishWindowsDrawn() {
780 synchronized (mLock) {
781 if (!mScreenOnEarly || mWindowManagerDrawComplete) {
782 return false;
783 }
784
785 mWindowManagerDrawComplete = true;
786 }
787 return true;
788 }
789
790 /** Return false if it is not ready to turn on. */
791 public boolean finishScreenTurningOn() {
792 synchronized (mLock) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200793 ProtoLog.d(WM_DEBUG_SCREEN_ON,
794 "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, "
795 + "mScreenOnFully=%b, mKeyguardDrawComplete=%b, "
796 + "mWindowManagerDrawComplete=%b",
797 mAwake, mScreenOnEarly, mScreenOnFully, mKeyguardDrawComplete,
798 mWindowManagerDrawComplete);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800799
800 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
801 || (mAwake && !mKeyguardDrawComplete)) {
802 return false;
803 }
804
Adrian Roosb125e0b2019-10-02 14:55:14 +0200805 ProtoLog.i(WM_DEBUG_SCREEN_ON, "Finished screen turning on...");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800806 mScreenOnListener = null;
807 mScreenOnFully = true;
808 }
809 return true;
810 }
811
Jorim Jaggi4981f152019-03-26 18:58:45 +0100812 private boolean hasStatusBarServicePermission(int pid, int uid) {
813 return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
814 == PackageManager.PERMISSION_GRANTED;
815 }
816
Tiger Huang7c610aa2018-10-27 00:01:01 +0800817 /**
818 * Sanitize the layout parameters coming from a client. Allows the policy
819 * to do things like ensure that windows of a specific type can't take
820 * input focus.
821 *
822 * @param attrs The window layout parameters to be modified. These values
823 * are modified in-place.
824 */
825 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
Jorim Jaggi4981f152019-03-26 18:58:45 +0100826 int callingPid, int callingUid) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800827
828 final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
829 if (mScreenDecorWindows.contains(win)) {
830 if (!isScreenDecor) {
831 // No longer has the flag set, so remove from the set.
832 mScreenDecorWindows.remove(win);
833 }
Jorim Jaggi4981f152019-03-26 18:58:45 +0100834 } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800835 mScreenDecorWindows.add(win);
836 }
837
838 switch (attrs.type) {
839 case TYPE_SYSTEM_OVERLAY:
840 case TYPE_SECURE_SYSTEM_OVERLAY:
841 // These types of windows can't receive input events.
842 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
843 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
844 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
845 break;
846 case TYPE_DREAM:
847 case TYPE_WALLPAPER:
848 // Dreams and wallpapers don't have an app window token and can thus not be
849 // letterboxed. Hence always let them extend under the cutout.
Arthur Hung20479922019-02-27 17:13:22 +0800850 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800851 break;
wilsonshihe8321942019-10-18 18:39:46 +0800852 case TYPE_NOTIFICATION_SHADE:
Tiger Huang7c610aa2018-10-27 00:01:01 +0800853 // If the Keyguard is in a hidden state (occluded by another window), we force to
854 // remove the wallpaper and keyguard flag so that any change in-flight after setting
855 // the keyguard as occluded wouldn't set these flags again.
856 // See {@link #processKeyguardSetHiddenResultLw}.
857 if (mService.mPolicy.isKeyguardOccluded()) {
858 attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800859 }
860 break;
861
862 case TYPE_SCREENSHOT:
863 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
864 break;
865
866 case TYPE_TOAST:
867 // While apps should use the dedicated toast APIs to add such windows
868 // it possible legacy apps to add the window directly. Therefore, we
869 // make windows added directly by the app behave as a toast as much
870 // as possible in terms of timeout and animation.
871 if (attrs.hideTimeoutMilliseconds < 0
872 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
873 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
874 }
Rhed Jao406d3a22018-11-30 19:28:58 +0800875 // Accessibility users may need longer timeout duration. This api compares
876 // original timeout with user's preference and return longer one. It returns
877 // original timeout if there's no preference.
878 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
879 (int) attrs.hideTimeoutMilliseconds,
880 AccessibilityManager.FLAG_CONTENT_TEXT);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800881 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
Jeff Changb10fac72019-04-09 17:28:30 +0800882 // Toast can show with below conditions when the screen is locked.
883 if (canToastShowWhenLocked(callingPid)) {
884 attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
885 }
Bernardo Rufino974de952019-10-22 11:53:42 +0100886 // Toasts can't be clickable
887 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800888 break;
Jorim Jaggi0da8fd12020-01-10 01:23:21 +0100889
890 case TYPE_BASE_APPLICATION:
891
892 // A non-translucent main app window isn't allowed to fit insets, as it would create
893 // a hole on the display!
894 if (attrs.isFullscreen() && win.mActivityRecord != null
895 && win.mActivityRecord.fillsParent()
896 && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
Tiger Huang52724442020-01-20 21:38:42 +0800897 && attrs.getFitInsetsTypes() != 0) {
Jorim Jaggi0da8fd12020-01-10 01:23:21 +0100898 throw new RuntimeException("Illegal attributes: Main activity window that isn't"
899 + " translucent trying to fit insets: "
Tiger Huang52724442020-01-20 21:38:42 +0800900 + attrs.getFitInsetsTypes()
Jorim Jaggi0da8fd12020-01-10 01:23:21 +0100901 + " attrs=" + attrs);
902 }
903 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800904 }
Tiger Huang7c610aa2018-10-27 00:01:01 +0800905 }
906
907 /**
Jeff Changb10fac72019-04-09 17:28:30 +0800908 * @return {@code true} if the calling activity initiate toast and is visible with
909 * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
910 */
911 boolean canToastShowWhenLocked(int callingPid) {
912 return mDisplayContent.forAllWindows(w -> {
913 return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
914 }, true /* traverseTopToBottom */);
915 }
916
917 /**
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800918 * Check if a window can be added to the system.
Tiger Huang7c610aa2018-10-27 00:01:01 +0800919 *
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800920 * Currently enforces that two window types are singletons per display:
Tiger Huang7c610aa2018-10-27 00:01:01 +0800921 * <ul>
922 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
wilsonshihe8321942019-10-18 18:39:46 +0800923 * <li>{@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}</li>
Tiger Huang7c610aa2018-10-27 00:01:01 +0800924 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
925 * </ul>
926 *
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800927 * @param attrs Information about the window to be added.
Tiger Huang7c610aa2018-10-27 00:01:01 +0800928 *
929 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
930 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
931 */
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800932 int validateAddingWindowLw(WindowManager.LayoutParams attrs) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800933 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
934 mContext.enforceCallingOrSelfPermission(
935 android.Manifest.permission.STATUS_BAR_SERVICE,
936 "DisplayPolicy");
Tiger Huang7c610aa2018-10-27 00:01:01 +0800937 }
938
939 switch (attrs.type) {
940 case TYPE_STATUS_BAR:
941 mContext.enforceCallingOrSelfPermission(
942 android.Manifest.permission.STATUS_BAR_SERVICE,
943 "DisplayPolicy");
944 if (mStatusBar != null) {
945 if (mStatusBar.isAlive()) {
946 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
947 }
948 }
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800949 break;
wilsonshihe8321942019-10-18 18:39:46 +0800950 case TYPE_NOTIFICATION_SHADE:
951 mContext.enforceCallingOrSelfPermission(
952 android.Manifest.permission.STATUS_BAR_SERVICE,
953 "DisplayPolicy");
954 if (mNotificationShade != null) {
955 if (mNotificationShade.isAlive()) {
956 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
957 }
958 }
959 break;
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800960 case TYPE_NAVIGATION_BAR:
961 mContext.enforceCallingOrSelfPermission(
962 android.Manifest.permission.STATUS_BAR_SERVICE,
963 "DisplayPolicy");
964 if (mNavigationBar != null) {
965 if (mNavigationBar.isAlive()) {
966 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
967 }
968 }
969 break;
970 case TYPE_NAVIGATION_BAR_PANEL:
971 case TYPE_STATUS_BAR_PANEL:
972 case TYPE_STATUS_BAR_SUB_PANEL:
973 case TYPE_VOICE_INTERACTION_STARTING:
974 mContext.enforceCallingOrSelfPermission(
975 android.Manifest.permission.STATUS_BAR_SERVICE,
976 "DisplayPolicy");
977 break;
978 }
979 return ADD_OKAY;
980 }
981
982 /**
983 * Called when a window is being added to the system. Must not throw an exception.
984 *
985 * @param win The window being added.
986 * @param attrs Information about the window to be added.
987 */
988 void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
989 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
990 mScreenDecorWindows.add(win);
991 }
992
993 switch (attrs.type) {
wilsonshihe8321942019-10-18 18:39:46 +0800994 case TYPE_NOTIFICATION_SHADE:
995 mNotificationShade = win;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800996 if (mDisplayContent.isDefaultDisplay) {
997 mService.mPolicy.setKeyguardCandidateLw(win);
998 }
wilsonshihe8321942019-10-18 18:39:46 +0800999 break;
1000 case TYPE_STATUS_BAR:
1001 mStatusBar = win;
1002 mStatusBarController.setWindow(win);
Adrian Roos11dfd272019-03-25 19:21:26 +01001003 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001004 (displayFrames, windowState, rect) -> {
1005 rect.top = 0;
1006 rect.bottom = getStatusBarHeight(displayFrames);
Adrian Roos11dfd272019-03-25 19:21:26 +01001007 };
Tiger Huang332793b2019-10-29 23:21:27 +08001008 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider);
1009 mDisplayContent.setInsetProvider(ITYPE_TOP_GESTURES, win, frameProvider);
1010 mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001011 break;
1012 case TYPE_NAVIGATION_BAR:
Tiger Huang7c610aa2018-10-27 00:01:01 +08001013 mNavigationBar = win;
1014 mNavigationBarController.setWindow(win);
1015 mNavigationBarController.setOnBarVisibilityChangedListener(
1016 mNavBarVisibilityListener, true);
Jorim Jaggidd3d5102020-01-28 12:09:03 +01001017 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
1018 (displayFrames, windowState, inOutFrame) -> {
1019
1020 // In Gesture Nav, navigation bar frame is larger than frame to
1021 // calculate inset.
1022 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1023 sTmpRect.set(displayFrames.mUnrestricted);
1024 sTmpRect.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1025 inOutFrame.top = sTmpRect.bottom
1026 - getNavigationBarHeight(displayFrames.mRotation,
1027 mDisplayContent.getConfiguration().uiMode);
1028 }
Jorim Jaggi9b4f4202020-01-28 17:05:06 +01001029 },
1030
1031 // For IME we use regular frame.
1032 (displayFrames, windowState, inOutFrame) ->
1033 inOutFrame.set(windowState.getFrameLw()));
1034
Tiger Huang332793b2019-10-29 23:21:27 +08001035 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001036 (displayFrames, windowState, inOutFrame) -> {
1037 inOutFrame.top -= mBottomGestureAdditionalInset;
1038 });
Tiger Huang332793b2019-10-29 23:21:27 +08001039 mDisplayContent.setInsetProvider(ITYPE_LEFT_GESTURES, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001040 (displayFrames, windowState, inOutFrame) -> {
1041 inOutFrame.left = 0;
1042 inOutFrame.top = 0;
1043 inOutFrame.bottom = displayFrames.mDisplayHeight;
1044 inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
1045 });
Tiger Huang332793b2019-10-29 23:21:27 +08001046 mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001047 (displayFrames, windowState, inOutFrame) -> {
1048 inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
1049 inOutFrame.top = 0;
1050 inOutFrame.bottom = displayFrames.mDisplayHeight;
1051 inOutFrame.right = displayFrames.mDisplayWidth;
1052 });
Tiger Huang332793b2019-10-29 23:21:27 +08001053 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_TAPPABLE_ELEMENT, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001054 (displayFrames, windowState, inOutFrame) -> {
1055 if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
1056 || mNavigationBarLetsThroughTaps) {
1057 inOutFrame.setEmpty();
1058 }
1059 });
Tiger Huang7c610aa2018-10-27 00:01:01 +08001060 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
1061 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001062 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001063 }
1064
1065 /**
1066 * Called when a window is being removed from a window manager. Must not
1067 * throw an exception -- clean up as much as possible.
1068 *
1069 * @param win The window being removed.
1070 */
Tiger Huang5f6cbca2019-07-18 19:00:01 +08001071 void removeWindowLw(WindowState win) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001072 if (mStatusBar == win) {
1073 mStatusBar = null;
1074 mStatusBarController.setWindow(null);
Tiger Huang332793b2019-10-29 23:21:27 +08001075 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001076 } else if (mNavigationBar == win) {
1077 mNavigationBar = null;
1078 mNavigationBarController.setWindow(null);
Tiger Huang332793b2019-10-29 23:21:27 +08001079 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null);
wilsonshihe8321942019-10-18 18:39:46 +08001080 } else if (mNotificationShade == win) {
1081 mNotificationShade = null;
1082 if (mDisplayContent.isDefaultDisplay) {
1083 mService.mPolicy.setKeyguardCandidateLw(null);
1084 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001085 }
1086 if (mLastFocusedWindow == win) {
1087 mLastFocusedWindow = null;
1088 }
1089 mScreenDecorWindows.remove(win);
1090 }
1091
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001092 private int getStatusBarHeight(DisplayFrames displayFrames) {
1093 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1094 displayFrames.mDisplayCutoutSafe.top);
1095 }
1096
Jorim Jaggi28620472019-01-02 23:21:49 +01001097 WindowState getStatusBar() {
1098 return mStatusBar;
1099 }
1100
wilsonshihe8321942019-10-18 18:39:46 +08001101 WindowState getNotificationShade() {
1102 return mNotificationShade;
1103 }
1104
Jorim Jaggi28620472019-01-02 23:21:49 +01001105 WindowState getNavigationBar() {
1106 return mNavigationBar;
1107 }
1108
Tiger Huang7c610aa2018-10-27 00:01:01 +08001109 /**
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001110 * Control the animation to run when a window's state changes. Return a positive number to
1111 * force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the
1112 * style resource defining the animation, or {@link #ANIMATION_NONE} for no animation.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001113 *
1114 * @param win The window that is changing.
1115 * @param transit What is happening to the window:
1116 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1117 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1118 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1119 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1120 *
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001121 * @return Resource ID of the actual animation to use, or {@link #ANIMATION_NONE} for none.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001122 */
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001123 int selectAnimation(WindowState win, int transit) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001124 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1125 + ": transit=" + transit);
1126 if (win == mStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001127 if (transit == TRANSIT_EXIT
1128 || transit == TRANSIT_HIDE) {
1129 return R.anim.dock_top_exit;
1130 } else if (transit == TRANSIT_ENTER
1131 || transit == TRANSIT_SHOW) {
1132 return R.anim.dock_top_enter;
1133 }
1134 } else if (win == mNavigationBar) {
1135 if (win.getAttrs().windowAnimations != 0) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001136 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001137 }
1138 // This can be on either the bottom or the right or the left.
1139 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1140 if (transit == TRANSIT_EXIT
1141 || transit == TRANSIT_HIDE) {
1142 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1143 return R.anim.dock_bottom_exit_keyguard;
1144 } else {
1145 return R.anim.dock_bottom_exit;
1146 }
1147 } else if (transit == TRANSIT_ENTER
1148 || transit == TRANSIT_SHOW) {
1149 return R.anim.dock_bottom_enter;
1150 }
1151 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1152 if (transit == TRANSIT_EXIT
1153 || transit == TRANSIT_HIDE) {
1154 return R.anim.dock_right_exit;
1155 } else if (transit == TRANSIT_ENTER
1156 || transit == TRANSIT_SHOW) {
1157 return R.anim.dock_right_enter;
1158 }
1159 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1160 if (transit == TRANSIT_EXIT
1161 || transit == TRANSIT_HIDE) {
1162 return R.anim.dock_left_exit;
1163 } else if (transit == TRANSIT_ENTER
1164 || transit == TRANSIT_SHOW) {
1165 return R.anim.dock_left_enter;
1166 }
1167 }
1168 } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001169 return selectDockedDividerAnimation(win, transit);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001170 }
1171
1172 if (transit == TRANSIT_PREVIEW_DONE) {
1173 if (win.hasAppShownWindows()) {
1174 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1175 return R.anim.app_starting_exit;
1176 }
1177 } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
1178 && transit == TRANSIT_ENTER) {
1179 // Special case: we are animating in a dream, while the keyguard
1180 // is shown. We don't want an animation on the dream, because
1181 // we need it shown immediately with the keyguard animating away
1182 // to reveal it.
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001183 return ANIMATION_NONE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001184 }
1185
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001186 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001187 }
1188
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001189 private int selectDockedDividerAnimation(WindowState win, int transit) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001190 int insets = mDisplayContent.getDockedDividerController().getContentInsets();
1191
1192 // If the divider is behind the navigation bar, don't animate.
1193 final Rect frame = win.getFrameLw();
1194 final boolean behindNavBar = mNavigationBar != null
1195 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
1196 && frame.top + insets >= mNavigationBar.getFrameLw().top)
1197 || (mNavigationBarPosition == NAV_BAR_RIGHT
1198 && frame.left + insets >= mNavigationBar.getFrameLw().left)
1199 || (mNavigationBarPosition == NAV_BAR_LEFT
1200 && frame.right - insets <= mNavigationBar.getFrameLw().right));
1201 final boolean landscape = frame.height() > frame.width();
1202 final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
1203 || frame.left + insets >= win.getDisplayFrameLw().right);
1204 final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
1205 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1206 final boolean offscreen = offscreenLandscape || offscreenPortrait;
1207 if (behindNavBar || offscreen) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001208 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001209 }
1210 if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1211 return R.anim.fade_in;
1212 } else if (transit == TRANSIT_EXIT) {
1213 return R.anim.fade_out;
1214 } else {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001215 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001216 }
1217 }
1218
1219 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08001220 * Called when a new system UI visibility is being reported, allowing
1221 * the policy to adjust what is actually reported.
1222 * @param visibility The raw visibility reported by the status bar.
1223 * @return The new desired visibility.
1224 */
1225 public int adjustSystemUiVisibilityLw(int visibility) {
1226 mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1227 mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1228
1229 // Reset any bits in mForceClearingStatusBarVisibility that
1230 // are now clear.
1231 mResettingSystemUiFlags &= visibility;
1232 // Clear any bits in the new visibility that are currently being
1233 // force cleared, before reporting it.
1234 return visibility & ~mResettingSystemUiFlags
1235 & ~mForceClearedSystemUiFlags;
1236 }
1237
1238 /**
Brad Stenninge0573692019-03-11 13:52:46 -07001239 * @return true if the system bars are forced to stay visible
Tiger Huang7c610aa2018-10-27 00:01:01 +08001240 */
Brad Stenninge0573692019-03-11 13:52:46 -07001241 public boolean areSystemBarsForcedShownLw(WindowState windowState) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001242 return mForceShowSystemBars;
1243 }
1244
1245 // TODO: Should probably be moved into DisplayFrames.
1246 /**
1247 * Return the layout hints for a newly added window. These values are computed on the
1248 * most recent layout, so they are not guaranteed to be correct.
1249 *
1250 * @param attrs The LayoutParams of the window.
1251 * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1252 * associated with the window.
1253 * @param displayFrames display frames.
1254 * @param floatingStack Whether the window's stack is floating.
1255 * @param outFrame The frame of the window.
1256 * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1257 * @param outStableInsets The areas covered by stable system windows irrespective of their
1258 * current visibility. Expressed as positive insets.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001259 * @param outDisplayCutout The area that has been cut away from the display.
Brad Stenninge0573692019-03-11 13:52:46 -07001260 * @return Whether to always consume the system bars.
1261 * See {@link #areSystemBarsForcedShownLw(WindowState)}.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001262 */
1263 public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1264 DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1265 Rect outContentInsets, Rect outStableInsets,
Jorim Jaggif081f062019-10-24 16:24:54 +02001266 DisplayCutout.ParcelableWrapper outDisplayCutout) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001267 final int fl = PolicyControl.getWindowFlags(null, attrs);
1268 final int pfl = attrs.privateFlags;
1269 final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1270 final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001271
1272 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1273 final boolean layoutInScreenAndInsetDecor = layoutInScreen
1274 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1275 final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1276
1277 if (layoutInScreenAndInsetDecor && !screenDecor) {
Tiger Huang4a7835f2019-11-06 00:07:56 +08001278 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang52724442020-01-20 21:38:42 +08001279 || (attrs.getFitInsetsTypes() & Type.navigationBars()) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001280 outFrame.set(displayFrames.mUnrestricted);
1281 } else {
1282 outFrame.set(displayFrames.mRestricted);
1283 }
1284
1285 final Rect sf;
1286 if (floatingStack) {
1287 sf = null;
1288 } else {
1289 sf = displayFrames.mStable;
1290 }
1291
1292 final Rect cf;
1293 if (floatingStack) {
1294 cf = null;
1295 } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1296 if ((fl & FLAG_FULLSCREEN) != 0) {
1297 cf = displayFrames.mStableFullscreen;
1298 } else {
1299 cf = displayFrames.mStable;
1300 }
Jorim Jaggif081f062019-10-24 16:24:54 +02001301 } else if ((fl & FLAG_FULLSCREEN) != 0) {
1302 cf = displayFrames.mUnrestricted;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001303 } else {
1304 cf = displayFrames.mCurrent;
1305 }
1306
1307 if (taskBounds != null) {
1308 outFrame.intersect(taskBounds);
1309 }
1310 InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1311 InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1312 outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1313 .getDisplayCutout());
1314 return mForceShowSystemBars;
1315 } else {
1316 if (layoutInScreen) {
1317 outFrame.set(displayFrames.mUnrestricted);
1318 } else {
1319 outFrame.set(displayFrames.mStable);
1320 }
1321 if (taskBounds != null) {
1322 outFrame.intersect(taskBounds);
1323 }
1324
1325 outContentInsets.setEmpty();
1326 outStableInsets.setEmpty();
1327 outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1328 return mForceShowSystemBars;
1329 }
1330 }
1331
Tiger Huang4a7835f2019-11-06 00:07:56 +08001332 // TODO(b/118118435): remove after migration
Tiger Huang7c610aa2018-10-27 00:01:01 +08001333 private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1334 int impliedFlags = 0;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001335 final boolean forceWindowDrawsBarBackgrounds =
1336 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
Tiger Huang4a7835f2019-11-06 00:07:56 +08001337 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001338 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001339 || forceWindowDrawsBarBackgrounds) {
Jorim Jaggid6490572019-04-16 14:57:56 +02001340 impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001341 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1342 }
1343 return impliedFlags;
1344 }
1345
Tiger Huang7c610aa2018-10-27 00:01:01 +08001346 private final Runnable mClearHideNavigationFlag = new Runnable() {
1347 @Override
1348 public void run() {
1349 synchronized (mLock) {
1350 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1351 mDisplayContent.reevaluateStatusBarVisibility();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001352 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL && mNavigationBar != null) {
1353 final InsetsControlTarget target =
1354 mNavigationBar.getControllableInsetProvider().getControlTarget();
1355 if (target != null) {
1356 target.showInsets(Type.navigationBars(), false /* fromIme */);
1357 }
1358 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001359 }
1360 }
1361 };
1362
1363 /**
1364 * Input handler used while nav bar is hidden. Captures any touch on the screen,
1365 * to determine when the nav bar should be shown and prevent applications from
1366 * receiving those touches.
1367 */
1368 private final class HideNavInputEventReceiver extends InputEventReceiver {
1369 HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1370 super(inputChannel, looper);
1371 }
1372
1373 @Override
1374 public void onInputEvent(InputEvent event) {
1375 try {
1376 if (event instanceof MotionEvent
1377 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1378 final MotionEvent motionEvent = (MotionEvent) event;
1379 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1380 // When the user taps down, we re-show the nav bar.
1381 boolean changed = false;
1382 synchronized (mLock) {
1383 if (mInputConsumer == null) {
1384 return;
1385 }
1386 // Any user activity always causes us to show the
1387 // navigation controls, if they had been hidden.
1388 // We also clear the low profile and only content
1389 // flags so that tapping on the screen will atomically
1390 // restore all currently hidden screen decorations.
1391 int newVal = mResettingSystemUiFlags
1392 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1393 | View.SYSTEM_UI_FLAG_LOW_PROFILE
1394 | View.SYSTEM_UI_FLAG_FULLSCREEN;
1395 if (mResettingSystemUiFlags != newVal) {
1396 mResettingSystemUiFlags = newVal;
1397 changed = true;
1398 }
1399 // We don't allow the system's nav bar to be hidden
1400 // again for 1 second, to prevent applications from
1401 // spamming us and keeping it from being shown.
1402 newVal = mForceClearedSystemUiFlags
1403 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1404 if (mForceClearedSystemUiFlags != newVal) {
1405 mForceClearedSystemUiFlags = newVal;
1406 changed = true;
1407 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1408 }
1409 if (changed) {
1410 mDisplayContent.reevaluateStatusBarVisibility();
1411 }
1412 }
1413 }
1414 }
1415 } finally {
1416 finishInputEvent(event, false /* handled */);
1417 }
1418 }
1419 }
1420
1421 /**
1422 * Called when layout of the windows is about to start.
1423 *
1424 * @param displayFrames frames of the display we are doing layout on.
1425 * @param uiMode The current uiMode in configuration.
1426 */
1427 public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1428 displayFrames.onBeginLayout();
1429 mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1430 mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1431
1432 // For purposes of putting out fake window up to steal focus, we will
1433 // drive nav being hidden only by whether it is requested.
1434 final int sysui = mLastSystemUiFlags;
Tiger Huang4a7835f2019-11-06 00:07:56 +08001435 final int behavior = mLastBehavior;
1436 boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
1437 ? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
1438 : mNavigationBar != null && mNavigationBar.getControllableInsetProvider() != null
1439 && mNavigationBar.getControllableInsetProvider().isClientVisible()
1440 && !mDisplayContent.getInsetsPolicy().isTransient(ITYPE_NAVIGATION_BAR);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001441 boolean navTranslucent = (sysui
1442 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
Tiger Huang4a7835f2019-11-06 00:07:56 +08001443 boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
1444 || (behavior & BEHAVIOR_SHOW_BARS_BY_SWIPE) != 0;
1445 boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
1446 || (behavior & BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001447 boolean navAllowedHidden = immersive || immersiveSticky;
1448 navTranslucent &= !immersiveSticky; // transient trumps translucent
wilsonshihe8321942019-10-18 18:39:46 +08001449 boolean isKeyguardShowing = isKeyguardShowing() && !isKeyguardOccluded();
1450 boolean notificationShadeForcesShowingNavigation =
1451 !isKeyguardShowing && mNotificationShade != null
1452 && (mNotificationShade.getAttrs().privateFlags
Tiger Huang7c610aa2018-10-27 00:01:01 +08001453 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1454
1455 // When the navigation bar isn't visible, we put up a fake input window to catch all
1456 // touch events. This way we can detect when the user presses anywhere to bring back the
1457 // nav bar and ensure the application doesn't see the event.
1458 if (navVisible || navAllowedHidden) {
1459 if (mInputConsumer != null) {
1460 mHandler.sendMessage(
1461 mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1462 mInputConsumer = null;
1463 }
1464 } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1465 mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1466 INPUT_CONSUMER_NAVIGATION,
1467 HideNavInputEventReceiver::new,
1468 displayFrames.mDisplayId);
1469 // As long as mInputConsumer is active, hover events are not dispatched to the app
1470 // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1471 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1472 }
1473
1474 // For purposes of positioning and showing the nav bar, if we have decided that it can't
1475 // be hidden (because of the screen aspect ratio), then take that into account.
1476 navVisible |= !canHideNavigationBar();
1477
1478 boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
wilsonshihe8321942019-10-18 18:39:46 +08001479 navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001480 if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1481 updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1482 if (updateSysUiVisibility) {
1483 updateSystemUiVisibilityLw();
1484 }
1485 layoutScreenDecorWindows(displayFrames);
1486
1487 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1488 // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1489 // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1490 // bar.
1491 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1492 displayFrames.mStable.top);
1493 }
Issei Suzukia5dbf522019-02-01 17:58:15 +01001494
1495 // In case this is a virtual display, and the host display has insets that overlap this
1496 // virtual display, apply the insets of the overlapped area onto the current and content
1497 // frame of this virtual display. This let us layout windows in the virtual display as
1498 // expected when the window needs to avoid overlap with the system windows.
1499 // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1500 // IME.
1501 displayFrames.mCurrent.inset(mForwardedInsets);
1502 displayFrames.mContent.inset(mForwardedInsets);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001503 }
1504
1505 private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1506 if (mScreenDecorWindows.isEmpty()) {
1507 return;
1508 }
1509
1510 sTmpRect.setEmpty();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001511 final int displayId = displayFrames.mDisplayId;
1512 final Rect dockFrame = displayFrames.mDock;
1513 final int displayHeight = displayFrames.mDisplayHeight;
1514 final int displayWidth = displayFrames.mDisplayWidth;
1515
1516 for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1517 final WindowState w = mScreenDecorWindows.valueAt(i);
1518 if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1519 // Skip if not on the same display or not visible.
1520 continue;
1521 }
1522
chaviw0d833762019-06-20 17:09:53 -07001523 w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1524 displayFrames.mUnrestricted /* displayFrame */,
chaviw0d833762019-06-20 17:09:53 -07001525 displayFrames.mUnrestricted /* contentFrame */,
1526 displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001527 displayFrames.mUnrestricted /* stableFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001528 w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1529 w.computeFrameLw();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001530 if (w.getControllableInsetProvider() != null) {
1531 w.getControllableInsetProvider().updateSourceFrame();
1532 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001533 final Rect frame = w.getFrameLw();
1534
1535 if (frame.left <= 0 && frame.top <= 0) {
1536 // Docked at left or top.
1537 if (frame.bottom >= displayHeight) {
1538 // Docked left.
1539 dockFrame.left = Math.max(frame.right, dockFrame.left);
1540 } else if (frame.right >= displayWidth) {
1541 // Docked top.
1542 dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1543 } else {
1544 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1545 + " not docked on left or top of display. frame=" + frame
1546 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1547 }
1548 } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1549 // Docked at right or bottom.
1550 if (frame.top <= 0) {
1551 // Docked right.
1552 dockFrame.right = Math.min(frame.left, dockFrame.right);
1553 } else if (frame.left <= 0) {
1554 // Docked bottom.
1555 dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1556 } else {
1557 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1558 + " not docked on right or bottom" + " of display. frame=" + frame
1559 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1560 }
1561 } else {
1562 // Screen decor windows are required to be docked on one of the sides of the screen.
1563 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1564 + " not docked on one of the sides of the display. frame=" + frame
1565 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1566 }
1567 }
1568
1569 displayFrames.mRestricted.set(dockFrame);
1570 displayFrames.mCurrent.set(dockFrame);
1571 displayFrames.mVoiceContent.set(dockFrame);
1572 displayFrames.mSystem.set(dockFrame);
1573 displayFrames.mContent.set(dockFrame);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001574 }
1575
1576 private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1577 boolean isKeyguardShowing) {
1578 // decide where the status bar goes ahead of time
1579 if (mStatusBar == null) {
1580 return false;
1581 }
1582 // apply any navigation bar insets
1583 sTmpRect.setEmpty();
Jorim Jaggi4981f152019-03-26 18:58:45 +01001584 final WindowFrames windowFrames = mStatusBar.getWindowFrames();
1585 windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001586 displayFrames.mUnrestricted /* displayFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001587 displayFrames.mStable /* contentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001588 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001589 displayFrames.mStable /* stableFrame */);
Jorim Jaggi4981f152019-03-26 18:58:45 +01001590 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001591
1592 // Let the status bar determine its size.
1593 mStatusBar.computeFrameLw();
1594
Tiger Huang4a7835f2019-11-06 00:07:56 +08001595 // Update the source frame to provide insets to other windows during layout.
1596 if (mStatusBar.getControllableInsetProvider() != null) {
1597 mStatusBar.getControllableInsetProvider().updateSourceFrame();
1598 }
1599
Tiger Huang7c610aa2018-10-27 00:01:01 +08001600 // For layout, the status bar is always at the top with our fixed height.
1601 displayFrames.mStable.top = displayFrames.mUnrestricted.top
1602 + mStatusBarHeightForRotation[displayFrames.mRotation];
1603 // Make sure the status bar covers the entire cutout height
1604 displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1605 displayFrames.mDisplayCutoutSafe.top);
1606
1607 // Tell the bar controller where the collapsed status bar content is
1608 sTmpRect.set(mStatusBar.getContentFrameLw());
1609 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1610 sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
1611 sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
1612 mStatusBarController.setContentFrame(sTmpRect);
1613
Tiger Huang4a7835f2019-11-06 00:07:56 +08001614 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0
1615 || mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001616 boolean statusBarTranslucent = (sysui
1617 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001618
1619 // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1620 if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1621 // Status bar may go away, so the screen area it occupies is available to apps but just
1622 // covering them when the status bar is visible.
1623 final Rect dockFrame = displayFrames.mDock;
1624 dockFrame.top = displayFrames.mStable.top;
1625 displayFrames.mContent.set(dockFrame);
1626 displayFrames.mVoiceContent.set(dockFrame);
1627 displayFrames.mCurrent.set(dockFrame);
1628
1629 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1630 "dock=%s content=%s cur=%s", dockFrame.toString(),
1631 displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1632
Jorim Jaggi4981f152019-03-26 18:58:45 +01001633 if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
1634 && !mStatusBar.isAnimatingLw()) {
1635
Tiger Huang7c610aa2018-10-27 00:01:01 +08001636 // If the opaque status bar is currently requested to be visible, and not in the
1637 // process of animating on or off, then we can tell the app that it is covered by
1638 // it.
1639 displayFrames.mSystem.top = displayFrames.mStable.top;
1640 }
1641 }
1642 return mStatusBarController.checkHiddenLw();
1643 }
1644
1645 private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1646 boolean navTranslucent, boolean navAllowedHidden,
1647 boolean statusBarForcesShowingNavigation) {
1648 if (mNavigationBar == null) {
1649 return false;
1650 }
1651
1652 final Rect navigationFrame = sTmpNavFrame;
1653 boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1654 // Force the navigation bar to its appropriate place and size. We need to do this directly,
1655 // instead of relying on it to bubble up from the nav bar, because this needs to change
1656 // atomically with screen rotations.
1657 final int rotation = displayFrames.mRotation;
1658 final int displayHeight = displayFrames.mDisplayHeight;
1659 final int displayWidth = displayFrames.mDisplayWidth;
1660 final Rect dockFrame = displayFrames.mDock;
1661 mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1662
1663 final Rect cutoutSafeUnrestricted = sTmpRect;
1664 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1665 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1666
1667 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1668 // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1669 final int top = cutoutSafeUnrestricted.bottom
1670 - getNavigationBarHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001671 final int topNavBar = cutoutSafeUnrestricted.bottom
Matthew Nga7f24bc2019-04-09 17:06:41 -07001672 - getNavigationBarFrameHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001673 navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001674 displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1675 if (transientNavBarShowing) {
1676 mNavigationBarController.setBarShowingLw(true);
1677 } else if (navVisible) {
1678 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001679 dockFrame.bottom = displayFrames.mRestricted.bottom = top;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001680 } else {
1681 // We currently want to hide the navigation UI - unless we expanded the status bar.
1682 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1683 }
1684 if (navVisible && !navTranslucent && !navAllowedHidden
1685 && !mNavigationBar.isAnimatingLw()
1686 && !mNavigationBarController.wasRecentlyTranslucent()) {
1687 // If the opaque nav bar is currently requested to be visible and not in the process
1688 // of animating on or off, then we can tell the app that it is covered by it.
1689 displayFrames.mSystem.bottom = top;
1690 }
1691 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1692 // Landscape screen; nav bar goes to the right.
1693 final int left = cutoutSafeUnrestricted.right
1694 - getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001695 navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001696 displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1697 if (transientNavBarShowing) {
1698 mNavigationBarController.setBarShowingLw(true);
1699 } else if (navVisible) {
1700 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001701 dockFrame.right = displayFrames.mRestricted.right = left;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001702 } else {
1703 // We currently want to hide the navigation UI - unless we expanded the status bar.
1704 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1705 }
1706 if (navVisible && !navTranslucent && !navAllowedHidden
1707 && !mNavigationBar.isAnimatingLw()
1708 && !mNavigationBarController.wasRecentlyTranslucent()) {
1709 // If the nav bar is currently requested to be visible, and not in the process of
1710 // animating on or off, then we can tell the app that it is covered by it.
1711 displayFrames.mSystem.right = left;
1712 }
1713 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1714 // Seascape screen; nav bar goes to the left.
1715 final int right = cutoutSafeUnrestricted.left
1716 + getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001717 navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001718 displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1719 if (transientNavBarShowing) {
1720 mNavigationBarController.setBarShowingLw(true);
1721 } else if (navVisible) {
1722 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001723 dockFrame.left = displayFrames.mRestricted.left = right;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001724 } else {
1725 // We currently want to hide the navigation UI - unless we expanded the status bar.
1726 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1727 }
1728 if (navVisible && !navTranslucent && !navAllowedHidden
1729 && !mNavigationBar.isAnimatingLw()
1730 && !mNavigationBarController.wasRecentlyTranslucent()) {
1731 // If the nav bar is currently requested to be visible, and not in the process of
1732 // animating on or off, then we can tell the app that it is covered by it.
1733 displayFrames.mSystem.left = right;
1734 }
1735 }
1736
1737 // Make sure the content and current rectangles are updated to account for the restrictions
1738 // from the navigation bar.
1739 displayFrames.mCurrent.set(dockFrame);
1740 displayFrames.mVoiceContent.set(dockFrame);
1741 displayFrames.mContent.set(dockFrame);
1742 // And compute the final frame.
1743 sTmpRect.setEmpty();
1744 mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001745 navigationFrame /* displayFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001746 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1747 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001748 navigationFrame /* stableFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001749 mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1750 mNavigationBar.computeFrameLw();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001751 if (mNavigationBar.getControllableInsetProvider() != null) {
1752 mNavigationBar.getControllableInsetProvider().updateSourceFrame();
1753 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001754 mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1755
1756 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1757 return mNavigationBarController.checkHiddenLw();
1758 }
1759
1760 private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
Jorim Jaggif081f062019-10-24 16:24:54 +02001761 boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001762 DisplayFrames displayFrames) {
1763 if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1764 // Here's a special case: if the child window is not the 'dock window'
1765 // or input method target, and the window it is attached to is below
1766 // the dock window, then the frames we computed for the window it is
1767 // attached to can not be used because the dock is effectively part
1768 // of the underlying window and the attached window is floating on top
1769 // of the whole thing. So, we ignore the attached window and explicitly
1770 // compute the frames that would be appropriate without the dock.
1771 vf.set(displayFrames.mDock);
1772 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001773 df.set(displayFrames.mDock);
1774 } else {
Jorim Jaggid6490572019-04-16 14:57:56 +02001775
Jorim Jaggif081f062019-10-24 16:24:54 +02001776 // In case we forced the window to draw behind the navigation bar, restrict df to
1777 // DF.Restricted to simulate old compat behavior.
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001778 Rect parentDisplayFrame = attached.getDisplayFrameLw();
Jorim Jaggid6490572019-04-16 14:57:56 +02001779 final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
1780 if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1781 && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1782 && (attachedAttrs.systemUiVisibility
1783 & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001784 parentDisplayFrame = new Rect(parentDisplayFrame);
Jorim Jaggif081f062019-10-24 16:24:54 +02001785 parentDisplayFrame.intersect(displayFrames.mRestricted);
Jorim Jaggid6490572019-04-16 14:57:56 +02001786 }
1787
Tiger Huang7c610aa2018-10-27 00:01:01 +08001788 // The effective display frame of the attached window depends on whether it is taking
1789 // care of insetting its content. If not, we need to use the parent's content frame so
1790 // that the entire window is positioned within that content. Otherwise we can use the
Jorim Jaggif081f062019-10-24 16:24:54 +02001791 // parent display frame and let the attached window take care of positioning its content
Tiger Huang7c610aa2018-10-27 00:01:01 +08001792 // appropriately.
1793 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1794 // Set the content frame of the attached window to the parent's decor frame
1795 // (same as content frame when IME isn't present) if specifically requested by
1796 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1797 // Otherwise, use the overscan frame.
1798 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
Jorim Jaggif081f062019-10-24 16:24:54 +02001799 ? attached.getContentFrameLw() : parentDisplayFrame);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001800 } else {
1801 // If the window is resizing, then we want to base the content frame on our attached
1802 // content frame to resize...however, things can be tricky if the attached window is
1803 // NOT in resize mode, in which case its content frame will be larger.
1804 // Ungh. So to deal with that, make sure the content frame we end up using is not
1805 // covering the IM dock.
1806 cf.set(attached.getContentFrameLw());
1807 if (attached.isVoiceInteraction()) {
1808 cf.intersectUnchecked(displayFrames.mVoiceContent);
1809 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1810 cf.intersectUnchecked(displayFrames.mContent);
1811 }
1812 }
Jorim Jaggid6490572019-04-16 14:57:56 +02001813 df.set(insetDecors ? parentDisplayFrame : cf);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001814 vf.set(attached.getVisibleFrameLw());
1815 }
1816 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1817 // positioned relative to its parent or the entire screen.
1818 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1819 }
1820
1821 private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1822 if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1823 return;
1824 }
1825 // If app is requesting a stable layout, don't let the content insets go below the stable
1826 // values.
1827 if ((fl & FLAG_FULLSCREEN) != 0) {
1828 r.intersectUnchecked(displayFrames.mStableFullscreen);
1829 } else {
1830 r.intersectUnchecked(displayFrames.mStable);
1831 }
1832 }
1833
1834 private boolean canReceiveInput(WindowState win) {
1835 boolean notFocusable =
1836 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1837 boolean altFocusableIm =
1838 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1839 boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1840 return !notFocusableForIm;
1841 }
1842
1843 /**
1844 * Called for each window attached to the window manager as layout is proceeding. The
1845 * implementation of this function must take care of setting the window's frame, either here or
1846 * in finishLayout().
1847 *
1848 * @param win The window being positioned.
1849 * @param attached For sub-windows, the window it is attached to; this
1850 * window will already have had layoutWindow() called on it
1851 * so you can use its Rect. Otherwise null.
1852 * @param displayFrames The display frames.
1853 */
1854 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1855 // We've already done the navigation bar, status bar, and all screen decor windows. If the
1856 // status bar can receive input, we need to layout it again to accommodate for the IME
1857 // window.
1858 if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1859 || mScreenDecorWindows.contains(win)) {
1860 return;
1861 }
1862 final WindowManager.LayoutParams attrs = win.getAttrs();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001863
1864 final int type = attrs.type;
1865 final int fl = PolicyControl.getWindowFlags(win, attrs);
1866 final int pfl = attrs.privateFlags;
1867 final int sim = attrs.softInputMode;
1868 final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1869 final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1870
1871 final WindowFrames windowFrames = win.getWindowFrames();
1872
Tiger Huang7c610aa2018-10-27 00:01:01 +08001873 sTmpLastParentFrame.set(windowFrames.mParentFrame);
1874 final Rect pf = windowFrames.mParentFrame;
1875 final Rect df = windowFrames.mDisplayFrame;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001876 final Rect cf = windowFrames.mContentFrame;
1877 final Rect vf = windowFrames.mVisibleFrame;
1878 final Rect dcf = windowFrames.mDecorFrame;
1879 final Rect sf = windowFrames.mStableFrame;
1880 dcf.setEmpty();
1881 windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1882 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1883
1884 final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1885 && mNavigationBar.isVisibleLw();
1886
1887 final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1888
Tiger Huang7c610aa2018-10-27 00:01:01 +08001889 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1890 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1891
1892 sf.set(displayFrames.mStable);
1893
Tiger Huang4a7835f2019-11-06 00:07:56 +08001894 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
Tiger Huang52724442020-01-20 21:38:42 +08001895 final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
1896 final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001897 final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
1898 final Rect dfu = displayFrames.mUnrestricted;
1899 Insets insets = Insets.of(0, 0, 0, 0);
1900 for (int i = types.size() - 1; i >= 0; i--) {
Tiger Huang82520fc2019-12-19 22:29:20 +08001901 insets = Insets.max(insets, mDisplayContent.getInsetsPolicy()
Tiger Huang4a7835f2019-11-06 00:07:56 +08001902 .getInsetsForDispatch(win).getSource(types.valueAt(i))
Tiger Huang52724442020-01-20 21:38:42 +08001903 .calculateInsets(dfu, attrs.isFitInsetsIgnoringVisibility()));
Tiger Huang4a7835f2019-11-06 00:07:56 +08001904 }
1905 final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
1906 final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
1907 final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
1908 final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
1909 df.set(left, top, dfu.right - right, dfu.bottom - bottom);
1910 if (attached == null) {
1911 pf.set(df);
1912 vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
1913 ? displayFrames.mCurrent : displayFrames.mDock);
1914 } else {
1915 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1916 vf.set(attached.getVisibleFrameLw());
1917 }
1918 cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
1919 ? displayFrames.mDock : displayFrames.mContent);
1920 dcf.set(displayFrames.mSystem);
1921 } else if (type == TYPE_INPUT_METHOD) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001922 vf.set(displayFrames.mDock);
1923 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001924 df.set(displayFrames.mDock);
Tiger Huang4a7835f2019-11-06 00:07:56 +08001925 pf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001926 // IM dock windows layout below the nav bar...
Jorim Jaggif081f062019-10-24 16:24:54 +02001927 pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001928 // ...with content insets above the nav bar
1929 cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1930 if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1931 // The status bar forces the navigation bar while it's visible. Make sure the IME
1932 // avoids the navigation bar in that case.
1933 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001934 pf.right = df.right = cf.right = vf.right =
Tiger Huang7c610aa2018-10-27 00:01:01 +08001935 displayFrames.mStable.right;
1936 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001937 pf.left = df.left = cf.left = vf.left = displayFrames.mStable.left;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001938 }
1939 }
1940
Matthew Nga7f24bc2019-04-09 17:06:41 -07001941 // In case the navigation bar is on the bottom, we use the frame height instead of the
1942 // regular height for the insets we send to the IME as we need some space to show
1943 // additional buttons in SystemUI when the IME is up.
1944 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1945 final int rotation = displayFrames.mRotation;
1946 final int uimode = mService.mPolicy.getUiMode();
1947 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
1948 - getNavigationBarHeight(rotation, uimode);
1949 if (navHeightOffset > 0) {
1950 cf.bottom -= navHeightOffset;
1951 sf.bottom -= navHeightOffset;
1952 vf.bottom -= navHeightOffset;
1953 dcf.bottom -= navHeightOffset;
1954 }
1955 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001956
1957 // IM dock windows always go to the bottom of the screen.
1958 attrs.gravity = Gravity.BOTTOM;
1959 } else if (type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001960 df.set(displayFrames.mUnrestricted);
1961 pf.set(displayFrames.mUnrestricted);
1962 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1963 cf.set(displayFrames.mDock);
1964 } else {
1965 cf.set(displayFrames.mContent);
1966 }
1967 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1968 vf.set(displayFrames.mCurrent);
1969 } else {
1970 vf.set(cf);
1971 }
1972 } else if (type == TYPE_WALLPAPER) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001973 layoutWallpaper(displayFrames, pf, df, cf);
Jorim Jaggif2ce4fa2020-01-21 22:32:37 +01001974 } else if (win == mStatusBar || type == TYPE_NOTIFICATION_SHADE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001975 df.set(displayFrames.mUnrestricted);
1976 pf.set(displayFrames.mUnrestricted);
1977 cf.set(displayFrames.mStable);
1978 vf.set(displayFrames.mStable);
1979
1980 if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7fe7f682019-10-26 01:11:23 +08001981 // cf.bottom should not be below the stable bottom, or the content might be obscured
1982 // by the navigation bar.
1983 if (cf.bottom > displayFrames.mContent.bottom) {
1984 cf.bottom = displayFrames.mContent.bottom;
1985 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001986 } else {
Tiger Huang7fe7f682019-10-26 01:11:23 +08001987 if (cf.bottom > displayFrames.mDock.bottom) {
1988 cf.bottom = displayFrames.mDock.bottom;
1989 }
1990 if (vf.bottom > displayFrames.mContent.bottom) {
1991 vf.bottom = displayFrames.mContent.bottom;
1992 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001993 }
1994 } else {
1995 dcf.set(displayFrames.mSystem);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001996 final boolean isAppWindow =
1997 type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1998 final boolean topAtRest =
1999 win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
Jorim Jaggia2e648e2019-10-25 15:06:53 +02002000 if (isAppWindow && !topAtRest) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002001 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
2002 && (fl & FLAG_FULLSCREEN) == 0
2003 && (fl & FLAG_TRANSLUCENT_STATUS) == 0
2004 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07002005 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002006 // Ensure policy decor includes status bar
2007 dcf.top = displayFrames.mStable.top;
2008 }
2009 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
2010 && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07002011 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
2012 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002013 // Ensure policy decor includes navigation bar
2014 dcf.bottom = displayFrames.mStable.bottom;
2015 dcf.right = displayFrames.mStable.right;
2016 }
2017 }
2018
2019 if (layoutInScreen && layoutInsetDecor) {
2020 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2021 + "): IN_SCREEN, INSET_DECOR");
2022 // This is the case for a normal activity window: we want it to cover all of the
2023 // screen space, and it can take care of moving its contents to account for screen
2024 // decorations that intrude into that space.
2025 if (attached != null) {
2026 // If this window is attached to another, our display
2027 // frame is the same as the one we are attached to.
Jorim Jaggif081f062019-10-24 16:24:54 +02002028 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08002029 displayFrames);
2030 } else {
2031 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2032 // Status bar panels are the only windows who can go on top of the status
2033 // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
2034 // have the same privileges as the status bar itself.
2035 //
2036 // However, they should still dodge the navigation bar if it exists.
2037
Jorim Jaggif081f062019-10-24 16:24:54 +02002038 pf.left = df.left = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002039 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
Jorim Jaggif081f062019-10-24 16:24:54 +02002040 pf.top = df.top = displayFrames.mUnrestricted.top;
2041 pf.right = df.right = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002042 ? displayFrames.mRestricted.right
2043 : displayFrames.mUnrestricted.right;
Jorim Jaggif081f062019-10-24 16:24:54 +02002044 pf.bottom = df.bottom = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002045 ? displayFrames.mRestricted.bottom
2046 : displayFrames.mUnrestricted.bottom;
2047
2048 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
Jorim Jaggid6490572019-04-16 14:57:56 +02002049 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08002050 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
Charles Chen64172bb2019-04-22 17:30:29 +08002051 || type == TYPE_VOLUME_OVERLAY
2052 || type == TYPE_KEYGUARD_DIALOG)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002053 // Asking for layout as if the nav bar is hidden, lets the application
2054 // extend into the unrestricted overscan screen area. We only do this for
2055 // application windows and certain system windows to ensure no window that
2056 // can be above the nav bar can do this.
Jorim Jaggif081f062019-10-24 16:24:54 +02002057 df.set(displayFrames.mUnrestricted);
2058 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002059 } else {
Jorim Jaggif081f062019-10-24 16:24:54 +02002060 df.set(displayFrames.mRestricted);
2061 pf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002062 }
2063
2064 if ((fl & FLAG_FULLSCREEN) == 0) {
2065 if (win.isVoiceInteraction()) {
2066 cf.set(displayFrames.mVoiceContent);
2067 } else {
Jorim Jaggi648e5882019-01-24 13:24:02 +01002068 // IME Insets are handled on the client for ADJUST_RESIZE in the new
2069 // insets world
2070 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2071 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002072 cf.set(displayFrames.mDock);
2073 } else {
2074 cf.set(displayFrames.mContent);
2075 }
2076 }
2077 } else {
2078 // Full screen windows are always given a layout that is as if the status
2079 // bar and other transient decors are gone. This is to avoid bad states when
2080 // moving from a window that is not hiding the status bar to one that is.
2081 cf.set(displayFrames.mRestricted);
2082 }
2083 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
Jorim Jaggi4e04eb22020-01-09 16:42:14 +01002084 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
2085 && adjust != SOFT_INPUT_ADJUST_NOTHING) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002086 vf.set(displayFrames.mCurrent);
2087 } else {
2088 vf.set(cf);
2089 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002090 }
2091 } else if (layoutInScreen || (sysUiFl
Tiger Huang4a7835f2019-11-06 00:07:56 +08002092 & (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Jorim Jaggid6490572019-04-16 14:57:56 +02002093 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002094 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2095 + "): IN_SCREEN");
2096 // A window that has requested to fill the entire screen just
2097 // gets everything, period.
2098 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2099 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002100 df.set(displayFrames.mUnrestricted);
2101 pf.set(displayFrames.mUnrestricted);
2102 if (hasNavBar) {
Jorim Jaggif081f062019-10-24 16:24:54 +02002103 pf.left = df.left = cf.left = displayFrames.mDock.left;
2104 pf.right = df.right = cf.right = displayFrames.mRestricted.right;
2105 pf.bottom = df.bottom = cf.bottom =
Tiger Huang7c610aa2018-10-27 00:01:01 +08002106 displayFrames.mRestricted.bottom;
2107 }
2108 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
2109 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
2110 // The navigation bar has Real Ultimate Power.
Tiger Huang7c610aa2018-10-27 00:01:01 +08002111 df.set(displayFrames.mUnrestricted);
2112 pf.set(displayFrames.mUnrestricted);
2113 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
2114 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
2115 && ((fl & FLAG_FULLSCREEN) != 0)) {
2116 // Fullscreen secure system overlays get what they ask for. Screenshot region
2117 // selection overlay should also expand to full screen.
Jorim Jaggif081f062019-10-24 16:24:54 +02002118 cf.set(displayFrames.mUnrestricted);
2119 df.set(displayFrames.mUnrestricted);
2120 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002121 } else if (type == TYPE_BOOT_PROGRESS) {
2122 // Boot progress screen always covers entire display.
Jorim Jaggif081f062019-10-24 16:24:54 +02002123 cf.set(displayFrames.mUnrestricted);
2124 df.set(displayFrames.mUnrestricted);
2125 pf.set(displayFrames.mUnrestricted);
Jorim Jaggid6490572019-04-16 14:57:56 +02002126 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
wilsonshihe8321942019-10-18 18:39:46 +08002127 && (type == TYPE_NOTIFICATION_SHADE
Tiger Huang7c610aa2018-10-27 00:01:01 +08002128 || type == TYPE_TOAST
2129 || type == TYPE_DOCK_DIVIDER
2130 || type == TYPE_VOICE_INTERACTION_STARTING
2131 || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
2132 // Asking for layout as if the nav bar is hidden, lets the
2133 // application extend into the unrestricted screen area. We
2134 // only do this for application windows (or toasts) to ensure no window that
2135 // can be above the nav bar can do this.
2136 // XXX This assumes that an app asking for this will also
2137 // ask for layout in only content. We can't currently figure out
2138 // what the screen would be if only laying out to hide the nav bar.
2139 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002140 df.set(displayFrames.mUnrestricted);
2141 pf.set(displayFrames.mUnrestricted);
Tiger Huang4a7835f2019-11-06 00:07:56 +08002142 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002143 df.set(displayFrames.mRestricted);
2144 pf.set(displayFrames.mRestricted);
Jorim Jaggi648e5882019-01-24 13:24:02 +01002145
2146 // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2147 // world
2148 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2149 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002150 cf.set(displayFrames.mDock);
2151 } else {
2152 cf.set(displayFrames.mContent);
2153 }
2154 } else {
2155 cf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002156 df.set(displayFrames.mRestricted);
2157 pf.set(displayFrames.mRestricted);
2158 }
2159
2160 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2161
Jorim Jaggi4e04eb22020-01-09 16:42:14 +01002162 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
2163 && adjust != SOFT_INPUT_ADJUST_NOTHING) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002164 vf.set(displayFrames.mCurrent);
2165 } else {
2166 vf.set(cf);
2167 }
2168 } else if (attached != null) {
2169 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2170 + "): attached to " + attached);
2171 // A child window should be placed inside of the same visible
2172 // frame that its parent had.
Jorim Jaggif081f062019-10-24 16:24:54 +02002173 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08002174 displayFrames);
2175 } else {
2176 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2177 + "): normal window");
2178 // Otherwise, a normal window must be placed inside the content
2179 // of all screen decorations.
2180 if (type == TYPE_STATUS_BAR_PANEL) {
2181 // Status bar panels can go on
2182 // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2183 // permission, so they have the same privileges as the status bar itself.
2184 cf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002185 df.set(displayFrames.mRestricted);
2186 pf.set(displayFrames.mRestricted);
Vishnu Nair9ccb1d22019-03-20 16:32:44 +00002187 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002188 // These dialogs are stable to interim decor changes.
2189 cf.set(displayFrames.mStable);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002190 df.set(displayFrames.mStable);
2191 pf.set(displayFrames.mStable);
2192 } else {
2193 pf.set(displayFrames.mContent);
2194 if (win.isVoiceInteraction()) {
2195 cf.set(displayFrames.mVoiceContent);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002196 df.set(displayFrames.mVoiceContent);
2197 } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2198 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002199 df.set(displayFrames.mDock);
2200 } else {
2201 cf.set(displayFrames.mContent);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002202 df.set(displayFrames.mContent);
2203 }
Jorim Jaggi4e04eb22020-01-09 16:42:14 +01002204 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
2205 && adjust != SOFT_INPUT_ADJUST_NOTHING) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002206 vf.set(displayFrames.mCurrent);
2207 } else {
2208 vf.set(cf);
2209 }
2210 }
2211 }
2212 }
2213
2214 final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2215 final boolean attachedInParent = attached != null && !layoutInScreen;
Tiger Huang4a7835f2019-11-06 00:07:56 +08002216 final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
2217 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
Jorim Jaggi0dd0cf92019-12-27 15:17:44 +01002218 || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
2219 && !win.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002220 final boolean requestedHideNavigation =
Tiger Huang4a7835f2019-11-06 00:07:56 +08002221 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
Jorim Jaggi0dd0cf92019-12-27 15:17:44 +01002222 || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
2223 && !win.getRequestedInsetsState().getSource(ITYPE_NAVIGATION_BAR)
2224 .isVisible());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002225
2226 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2227 // cropped / shifted to the displayFrame in WindowState.
2228 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2229 && type != TYPE_BASE_APPLICATION;
2230
2231 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2232 // the cutout safe zone.
shawnlind0e23be2019-12-29 18:56:15 +08002233 if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
2234 || cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002235 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2236 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2237 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2238 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2239 // At the top we have the status bar, so apps that are
2240 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2241 // already expect that there's an inset there and we don't need to exclude
2242 // the window from that area.
2243 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2244 }
2245 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2246 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2247 // Same for the navigation bar.
2248 switch (mNavigationBarPosition) {
2249 case NAV_BAR_BOTTOM:
2250 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2251 break;
2252 case NAV_BAR_RIGHT:
2253 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2254 break;
2255 case NAV_BAR_LEFT:
2256 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2257 break;
2258 }
2259 }
2260 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2261 // The IME can always extend under the bottom cutout if the navbar is there.
2262 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2263 }
2264 // Windows that are attached to a parent and laid out in said parent already avoid
2265 // the cutout according to that parent and don't need to be further constrained.
2266 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2267 // They will later be cropped or shifted using the displayFrame in WindowState,
2268 // which prevents overlap with the DisplayCutout.
2269 if (!attachedInParent && !floatingInScreenWindow) {
2270 sTmpRect.set(pf);
2271 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2272 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2273 }
2274 // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2275 // cutout.
2276 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2277 }
2278
2279 // Content should never appear in the cutout.
2280 cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2281
2282 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2283 // Also, we don't allow windows in multi-window mode to extend out of the screen.
2284 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
Evan Rosky4fb1e912019-03-06 13:54:43 -08002285 && !win.inMultiWindowMode()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002286 df.left = df.top = -10000;
2287 df.right = df.bottom = 10000;
2288 if (type != TYPE_WALLPAPER) {
Jorim Jaggif081f062019-10-24 16:24:54 +02002289 cf.left = cf.top = vf.left = vf.top = -10000;
2290 cf.right = cf.bottom = vf.right = vf.bottom = 10000;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002291 }
2292 }
2293
2294 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2295 + ": sim=#" + Integer.toHexString(sim)
2296 + " attach=" + attached + " type=" + type
2297 + String.format(" flags=0x%08x", fl)
2298 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
Tiger Huang7c610aa2018-10-27 00:01:01 +08002299 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2300 + " dcf=" + dcf.toShortString()
Jorim Jaggif081f062019-10-24 16:24:54 +02002301 + " sf=" + sf.toShortString());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002302
2303 if (!sTmpLastParentFrame.equals(pf)) {
2304 windowFrames.setContentChanged(true);
2305 }
2306
2307 win.computeFrameLw();
Tiger Huang4a7835f2019-11-06 00:07:56 +08002308 if (win.getControllableInsetProvider() != null) {
2309 win.getControllableInsetProvider().updateSourceFrame();
2310 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002311 // Dock windows carve out the bottom of the screen, so normal windows
2312 // can't appear underneath them.
2313 if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2314 && !win.getGivenInsetsPendingLw()) {
2315 offsetInputMethodWindowLw(win, displayFrames);
2316 }
2317 if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2318 && !win.getGivenInsetsPendingLw()) {
2319 offsetVoiceInputWindowLw(win, displayFrames);
2320 }
2321 }
2322
Jorim Jaggif081f062019-10-24 16:24:54 +02002323 private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect cf) {
2324 // The wallpaper has Real Ultimate Power
2325 df.set(displayFrames.mUnrestricted);
2326 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002327 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002328 }
2329
2330 private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
Winson Chung913690d2019-11-14 16:06:01 -08002331 final int rotation = displayFrames.mRotation;
2332 final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
2333 displayFrames.mDisplayHeight, rotation);
2334
Tiger Huang7c610aa2018-10-27 00:01:01 +08002335 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2336 top += win.getGivenContentInsetsLw().top;
2337 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
Winson Chung913690d2019-11-14 16:06:01 -08002338 if (navBarPosition == NAV_BAR_BOTTOM) {
2339 // Always account for the nav bar frame height on the bottom since in all navigation
2340 // modes we make room to show the dismiss-ime button, even if the IME does not report
2341 // insets (ie. when floating)
2342 final int uimode = mService.mPolicy.getUiMode();
2343 final int navFrameHeight = getNavigationBarFrameHeight(rotation, uimode);
2344 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom,
2345 displayFrames.mUnrestricted.bottom - navFrameHeight);
2346 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002347 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2348 top = win.getVisibleFrameLw().top;
2349 top += win.getGivenVisibleInsetsLw().top;
2350 displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2351 if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2352 + displayFrames.mDock.bottom + " mContentBottom="
2353 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2354 }
2355
2356 private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2357 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2358 top += win.getGivenContentInsetsLw().top;
2359 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2360 }
2361
Riddle Hsuccf09402019-08-13 00:33:06 +08002362 WindowState getTopFullscreenOpaqueWindow() {
2363 return mTopFullscreenOpaqueWindowState;
2364 }
2365
2366 boolean isTopLayoutFullscreen() {
2367 return mTopIsFullscreen;
2368 }
2369
Tiger Huang7c610aa2018-10-27 00:01:01 +08002370 /**
2371 * Called following layout of all windows before each window has policy applied.
2372 */
2373 public void beginPostLayoutPolicyLw() {
2374 mTopFullscreenOpaqueWindowState = null;
2375 mTopFullscreenOpaqueOrDimmingWindowState = null;
2376 mTopDockedOpaqueWindowState = null;
2377 mTopDockedOpaqueOrDimmingWindowState = null;
2378 mForceStatusBar = false;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002379 mForcingShowNavBar = false;
2380 mForcingShowNavBarLayer = -1;
2381
2382 mAllowLockscreenWhenOn = false;
2383 mShowingDream = false;
2384 mWindowSleepTokenNeeded = false;
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002385 mIsFreeformWindowOverlappingWithNavBar = false;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002386 }
2387
2388 /**
2389 * Called following layout of all window to apply policy to each window.
2390 *
2391 * @param win The window being positioned.
2392 * @param attrs The LayoutParams of the window.
2393 * @param attached For sub-windows, the window it is attached to. Otherwise null.
2394 */
2395 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2396 WindowState attached, WindowState imeTarget) {
2397 final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2398 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2399 mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2400 final int fl = PolicyControl.getWindowFlags(win, attrs);
2401 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2402 && attrs.type == TYPE_INPUT_METHOD) {
2403 mForcingShowNavBar = true;
2404 mForcingShowNavBarLayer = win.getSurfaceLayer();
2405 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002406
2407 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2408 && attrs.type < FIRST_SYSTEM_WINDOW;
2409 final int windowingMode = win.getWindowingMode();
2410 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2411 windowingMode == WINDOWING_MODE_FULLSCREEN
2412 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2413 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2414 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2415 mForceStatusBar = true;
2416 }
2417 if (attrs.type == TYPE_DREAM) {
2418 // If the lockscreen was showing when the dream started then wait
2419 // for the dream to draw before hiding the lockscreen.
2420 if (!mDreamingLockscreen
2421 || (win.isVisibleLw() && win.hasDrawnLw())) {
2422 mShowingDream = true;
2423 appWindow = true;
2424 }
2425 }
2426
2427 // For app windows that are not attached, we decide if all windows in the app they
2428 // represent should be hidden or if we should hide the lockscreen. For attached app
2429 // windows we defer the decision to the window it is attached to.
2430 if (appWindow && attached == null) {
2431 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2432 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2433 mTopFullscreenOpaqueWindowState = win;
2434 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2435 mTopFullscreenOpaqueOrDimmingWindowState = win;
2436 }
2437 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2438 mAllowLockscreenWhenOn = true;
2439 }
2440 }
2441 }
2442 }
2443
2444 // Voice interaction overrides both top fullscreen and top docked.
Jorim Jaggi50150152019-03-27 23:08:58 +01002445 if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002446 if (mTopFullscreenOpaqueWindowState == null) {
2447 mTopFullscreenOpaqueWindowState = win;
2448 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2449 mTopFullscreenOpaqueOrDimmingWindowState = win;
2450 }
2451 }
2452 if (mTopDockedOpaqueWindowState == null) {
2453 mTopDockedOpaqueWindowState = win;
2454 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2455 mTopDockedOpaqueOrDimmingWindowState = win;
2456 }
2457 }
2458 }
2459
2460 // Keep track of the window if it's dimming but not necessarily fullscreen.
2461 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2462 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2463 mTopFullscreenOpaqueOrDimmingWindowState = win;
2464 }
2465
2466 // We need to keep track of the top "fullscreen" opaque window for the docked stack
2467 // separately, because both the "real fullscreen" opaque window and the one for the docked
2468 // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2469 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2470 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2471 mTopDockedOpaqueWindowState = win;
2472 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2473 mTopDockedOpaqueOrDimmingWindowState = win;
2474 }
2475 }
2476
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002477 // Check if the freeform window overlaps with the navigation bar area.
2478 final WindowState navBarWin = hasNavigationBar() ? mNavigationBar : null;
2479 if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode()
2480 && isOverlappingWithNavBar(win, navBarWin)) {
2481 mIsFreeformWindowOverlappingWithNavBar = true;
2482 }
2483
Tiger Huang7c610aa2018-10-27 00:01:01 +08002484 // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2485 // docked stack.
2486 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2487 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2488 mTopDockedOpaqueOrDimmingWindowState = win;
2489 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002490 }
2491
2492 /**
2493 * Called following layout of all windows and after policy has been applied
2494 * to each window. If in this function you do
2495 * something that may have modified the animation state of another window,
2496 * be sure to return non-zero in order to perform another pass through layout.
2497 *
2498 * @return Return any bit set of
2499 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2500 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2501 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2502 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2503 */
2504 public int finishPostLayoutPolicyLw() {
2505 int changes = 0;
2506 boolean topIsFullscreen = false;
2507
2508 // If we are not currently showing a dream then remember the current
2509 // lockscreen state. We will use this to determine whether the dream
2510 // started while the lockscreen was showing and remember this state
2511 // while the dream is showing.
2512 if (!mShowingDream) {
2513 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2514 if (mDreamingSleepTokenNeeded) {
2515 mDreamingSleepTokenNeeded = false;
2516 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2517 }
2518 } else {
2519 if (!mDreamingSleepTokenNeeded) {
2520 mDreamingSleepTokenNeeded = true;
2521 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2522 }
2523 }
2524
2525 if (mStatusBar != null) {
2526 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002527 + " top=" + mTopFullscreenOpaqueWindowState);
wilsonshihe8321942019-10-18 18:39:46 +08002528 final boolean forceShowStatusBar = (mStatusBar.getAttrs().privateFlags
2529 & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
2530 final boolean notificationShadeForcesShowingNavigation =
2531 mNotificationShade != null
2532 && (mNotificationShade.getAttrs().privateFlags
Tiger Huang7c610aa2018-10-27 00:01:01 +08002533 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
wilsonshihe8321942019-10-18 18:39:46 +08002534
Tiger Huang7c610aa2018-10-27 00:01:01 +08002535 boolean topAppHidesStatusBar = topAppHidesStatusBar();
wilsonshihe8321942019-10-18 18:39:46 +08002536 if (mForceStatusBar || forceShowStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002537 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2538 if (mStatusBarController.setBarShowingLw(true)) {
2539 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2540 }
2541 // Maintain fullscreen layout until incoming animation is complete.
2542 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
wilsonshihe8321942019-10-18 18:39:46 +08002543 // Transient status bar is not allowed if notification shade is expecting the
2544 // navigation keys from the user.
2545 if (notificationShadeForcesShowingNavigation
Tiger Huang7c610aa2018-10-27 00:01:01 +08002546 && mStatusBarController.isTransientShowing()) {
2547 mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2548 mLastSystemUiFlags, mLastSystemUiFlags);
2549 }
2550 } else if (mTopFullscreenOpaqueWindowState != null) {
2551 topIsFullscreen = topAppHidesStatusBar;
2552 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2553 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2554 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
2555 // case though.
2556 if (mStatusBarController.isTransientShowing()) {
2557 if (mStatusBarController.setBarShowingLw(true)) {
2558 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2559 }
2560 } else if (topIsFullscreen
Tiger Huang7c610aa2018-10-27 00:01:01 +08002561 && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2562 if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2563 if (mStatusBarController.setBarShowingLw(false)) {
2564 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2565 } else {
2566 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2567 }
2568 } else {
2569 if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2570 if (mStatusBarController.setBarShowingLw(true)) {
2571 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2572 }
2573 topAppHidesStatusBar = false;
2574 }
2575 }
2576 mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2577 }
2578
2579 if (mTopIsFullscreen != topIsFullscreen) {
2580 if (!topIsFullscreen) {
2581 // Force another layout when status bar becomes fully shown.
2582 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2583 }
2584 mTopIsFullscreen = topIsFullscreen;
2585 }
2586
2587 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2588 // If the navigation bar has been hidden or shown, we need to do another
2589 // layout pass to update that window.
2590 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2591 }
2592
2593 if (mShowingDream != mLastShowingDream) {
2594 mLastShowingDream = mShowingDream;
2595 mService.notifyShowingDreamChanged();
2596 }
2597
2598 updateWindowSleepToken();
2599
2600 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2601 return changes;
2602 }
2603
2604 private void updateWindowSleepToken() {
2605 if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2606 mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2607 mHandler.post(mAcquireSleepTokenRunnable);
2608 } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2609 mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2610 mHandler.post(mReleaseSleepTokenRunnable);
2611 }
2612 mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2613 }
2614
2615 /**
2616 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2617 * window.
2618 */
2619 private boolean topAppHidesStatusBar() {
hyok.kim332ccfc2019-07-02 15:39:43 +09002620 if (mTopFullscreenOpaqueWindowState == null || mForceShowSystemBars) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002621 return false;
2622 }
2623 final int fl = PolicyControl.getWindowFlags(null,
2624 mTopFullscreenOpaqueWindowState.getAttrs());
Adam Pardyl8c2d19c2019-09-16 17:15:38 +02002625 if (WindowManagerDebugConfig.DEBUG) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002626 Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2627 Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2628 + " lp.flags=0x" + Integer.toHexString(fl));
2629 }
2630 return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2631 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2632 }
2633
2634 /**
Winson Chungda20fec2019-04-10 12:19:59 -07002635 * Called when the user is switched.
2636 */
2637 public void switchUser() {
2638 updateCurrentUserResources();
2639 }
2640
2641 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002642 * Called when the resource overlays change.
2643 */
2644 public void onOverlayChangedLw() {
Winson Chungda20fec2019-04-10 12:19:59 -07002645 updateCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002646 onConfigurationChanged();
Jeff Changb0a061e2019-03-11 11:39:54 +08002647 mSystemGestures.onConfigurationChanged();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002648 }
2649
2650 /**
2651 * Called when the configuration has changed, and it's safe to load new values from resources.
2652 */
2653 public void onConfigurationChanged() {
2654 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2655
Winson Chungda20fec2019-04-10 12:19:59 -07002656 final Resources res = getCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002657 final int portraitRotation = displayRotation.getPortraitRotation();
2658 final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2659 final int landscapeRotation = displayRotation.getLandscapeRotation();
2660 final int seascapeRotation = displayRotation.getSeascapeRotation();
Matthew Nga7f24bc2019-04-09 17:06:41 -07002661 final int uiMode = mService.mPolicy.getUiMode();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002662
Louis Changfc64c832018-12-04 11:38:26 +08002663 if (hasStatusBar()) {
2664 mStatusBarHeightForRotation[portraitRotation] =
2665 mStatusBarHeightForRotation[upsideDownRotation] =
2666 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2667 mStatusBarHeightForRotation[landscapeRotation] =
2668 mStatusBarHeightForRotation[seascapeRotation] =
2669 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2670 } else {
2671 mStatusBarHeightForRotation[portraitRotation] =
2672 mStatusBarHeightForRotation[upsideDownRotation] =
2673 mStatusBarHeightForRotation[landscapeRotation] =
2674 mStatusBarHeightForRotation[seascapeRotation] = 0;
2675 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002676
2677 // Height of the navigation bar when presented horizontally at bottom
2678 mNavigationBarHeightForRotationDefault[portraitRotation] =
2679 mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2680 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2681 mNavigationBarHeightForRotationDefault[landscapeRotation] =
2682 mNavigationBarHeightForRotationDefault[seascapeRotation] =
2683 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2684
Matthew Nga7f24bc2019-04-09 17:06:41 -07002685 // Height of the navigation bar frame when presented horizontally at bottom
2686 mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2687 mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2688 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2689 mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2690 mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2691 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2692
Tiger Huang7c610aa2018-10-27 00:01:01 +08002693 // Width of the navigation bar when presented vertically along one side
2694 mNavigationBarWidthForRotationDefault[portraitRotation] =
2695 mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2696 mNavigationBarWidthForRotationDefault[landscapeRotation] =
2697 mNavigationBarWidthForRotationDefault[seascapeRotation] =
2698 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2699
2700 if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2701 // Height of the navigation bar when presented horizontally at bottom
2702 mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2703 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2704 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2705 mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2706 mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2707 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2708
2709 // Width of the navigation bar when presented vertically along one side
2710 mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2711 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2712 mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2713 mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2714 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2715 }
2716
Winson Chung4723b4e2019-03-25 16:49:36 -07002717 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002718 mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
2719 mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
Winson Chung36941632019-04-19 15:21:38 -07002720 mNavigationBarAlwaysShowOnSideGesture =
2721 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
Winson Chung4723b4e2019-03-25 16:49:36 -07002722
Matthew Nga7f24bc2019-04-09 17:06:41 -07002723 // This should calculate how much above the frame we accept gestures.
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002724 mBottomGestureAdditionalInset =
Matthew Nga7f24bc2019-04-09 17:06:41 -07002725 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002726 - getNavigationBarFrameHeight(portraitRotation, uiMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002727
Winson Chung4723b4e2019-03-25 16:49:36 -07002728 updateConfigurationAndScreenSizeDependentBehaviors();
2729 }
2730
2731 void updateConfigurationAndScreenSizeDependentBehaviors() {
Winson Chungda20fec2019-04-10 12:19:59 -07002732 final Resources res = getCurrentUserResources();
Winson Chung4723b4e2019-03-25 16:49:36 -07002733 mNavigationBarCanMove =
2734 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2735 && res.getBoolean(R.bool.config_navBarCanMove);
Riddle Hsuccf09402019-08-13 00:33:06 +08002736 mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002737 }
2738
Winson Chungda20fec2019-04-10 12:19:59 -07002739 /**
2740 * Updates the current user's resources to pick up any changes for the current user (including
2741 * overlay paths)
2742 */
2743 private void updateCurrentUserResources() {
2744 final int userId = mService.mAmInternal.getCurrentUserId();
2745 final Context uiContext = getSystemUiContext();
Winson Chung203e1522019-05-02 15:42:22 -07002746
2747 if (userId == UserHandle.USER_SYSTEM) {
2748 // Skip the (expensive) recreation of resources for the system user below and just
2749 // use the resources from the system ui context
2750 mCurrentUserResources = uiContext.getResources();
2751 return;
2752 }
2753
2754 // For non-system users, ensure that the resources are loaded from the current
2755 // user's package info (see ContextImpl.createDisplayContext)
Winson Chungda20fec2019-04-10 12:19:59 -07002756 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2757 uiContext.getPackageName(), null, 0, userId);
Winson Chungda20fec2019-04-10 12:19:59 -07002758 mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2759 pi.getResDir(),
2760 null /* splitResDirs */,
2761 pi.getOverlayDirs(),
2762 pi.getApplicationInfo().sharedLibraryFiles,
2763 mDisplayContent.getDisplayId(),
2764 null /* overrideConfig */,
2765 uiContext.getResources().getCompatibilityInfo(),
Ryan Mitchell4579c0a2020-01-08 16:29:11 -08002766 null /* classLoader */,
2767 null /* loaders */);
Winson Chungda20fec2019-04-10 12:19:59 -07002768 }
2769
Tiger Huang7c610aa2018-10-27 00:01:01 +08002770 @VisibleForTesting
Winson Chungda20fec2019-04-10 12:19:59 -07002771 Resources getCurrentUserResources() {
2772 if (mCurrentUserResources == null) {
2773 updateCurrentUserResources();
2774 }
2775 return mCurrentUserResources;
2776 }
2777
2778 @VisibleForTesting
2779 Context getContext() {
2780 return mContext;
2781 }
2782
Charles Chen173ae782019-11-11 20:39:02 +08002783 Context getSystemUiContext() {
2784 return mUiContext;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002785 }
2786
2787 private int getNavigationBarWidth(int rotation, int uiMode) {
2788 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2789 return mNavigationBarWidthForRotationInCarMode[rotation];
2790 } else {
2791 return mNavigationBarWidthForRotationDefault[rotation];
2792 }
2793 }
2794
Charles Chen3dedec32019-01-24 22:19:37 +08002795 void notifyDisplayReady() {
wilsonshih643bf132019-02-27 12:49:19 +08002796 mHandler.post(() -> {
2797 final int displayId = getDisplayId();
2798 getStatusBarManagerInternal().onDisplayReady(displayId);
Felipe Leme34a861a2019-08-05 16:00:12 -07002799 final WallpaperManagerInternal wpMgr = LocalServices
2800 .getService(WallpaperManagerInternal.class);
2801 if (wpMgr != null) {
2802 wpMgr.onDisplayReady(displayId);
2803 }
wilsonshih643bf132019-02-27 12:49:19 +08002804 });
Charles Chen3dedec32019-01-24 22:19:37 +08002805 }
2806
Tiger Huang7c610aa2018-10-27 00:01:01 +08002807 /**
2808 * Return the display width available after excluding any screen
2809 * decorations that could never be removed in Honeycomb. That is, system bar or
2810 * button bar.
2811 */
2812 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2813 DisplayCutout displayCutout) {
2814 int width = fullWidth;
2815 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002816 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2817 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002818 width -= getNavigationBarWidth(rotation, uiMode);
2819 }
2820 }
2821 if (displayCutout != null) {
2822 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2823 }
2824 return width;
2825 }
2826
2827 private int getNavigationBarHeight(int rotation, int uiMode) {
2828 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2829 return mNavigationBarHeightForRotationInCarMode[rotation];
2830 } else {
2831 return mNavigationBarHeightForRotationDefault[rotation];
2832 }
2833 }
2834
2835 /**
Matthew Nga7f24bc2019-04-09 17:06:41 -07002836 * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2837 * is used for spacing to show additional buttons on the navigation bar (such as the ime
2838 * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2839 * height that we send to the app as content insets that can be smaller.
2840 * <p>
2841 * In car mode it will return the same height as {@link #getNavigationBarHeight}
2842 *
2843 * @param rotation specifies rotation to return dimension from
2844 * @param uiMode to determine if in car mode
2845 * @return navigation bar frame height
2846 */
2847 private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2848 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2849 return mNavigationBarHeightForRotationInCarMode[rotation];
2850 } else {
2851 return mNavigationBarFrameHeightForRotationDefault[rotation];
2852 }
2853 }
2854
2855 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002856 * Return the display height available after excluding any screen
2857 * decorations that could never be removed in Honeycomb. That is, system bar or
2858 * button bar.
2859 */
2860 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2861 DisplayCutout displayCutout) {
2862 int height = fullHeight;
2863 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002864 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2865 if (navBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002866 height -= getNavigationBarHeight(rotation, uiMode);
2867 }
2868 }
2869 if (displayCutout != null) {
2870 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2871 }
2872 return height;
2873 }
2874
2875 /**
2876 * Return the available screen width that we should report for the
2877 * configuration. This must be no larger than
2878 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2879 * than that to account for more transient decoration like a status bar.
2880 */
2881 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2882 DisplayCutout displayCutout) {
2883 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2884 }
2885
2886 /**
2887 * Return the available screen height that we should report for the
2888 * configuration. This must be no larger than
2889 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2890 * than that to account for more transient decoration like a status bar.
2891 */
2892 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2893 DisplayCutout displayCutout) {
2894 // There is a separate status bar at the top of the display. We don't count that as part
2895 // of the fixed decor, since it can hide; however, for purposes of configurations,
2896 // we do want to exclude it since applications can't generally use that part
2897 // of the screen.
2898 int statusBarHeight = mStatusBarHeightForRotation[rotation];
2899 if (displayCutout != null) {
2900 // If there is a cutout, it may already have accounted for some part of the status
2901 // bar height.
2902 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2903 }
2904 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2905 - statusBarHeight;
2906 }
2907
Tiger Huang43b8fc22019-04-26 11:49:29 +08002908 /**
2909 * Return corner radius in pixels that should be used on windows in order to cover the display.
2910 * The radius is only valid for built-in displays since the one who configures window corner
2911 * radius cannot know the corner radius of non-built-in display.
2912 */
2913 float getWindowCornerRadius() {
2914 return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN
2915 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2916 }
2917
Tiger Huang7c610aa2018-10-27 00:01:01 +08002918 boolean isShowingDreamLw() {
2919 return mShowingDream;
2920 }
2921
2922 /**
Riddle Hsu61987bc2019-04-03 13:08:47 +08002923 * Calculates the stable insets if we already have the non-decor insets.
2924 *
2925 * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2926 * @param rotation The current display rotation.
2927 */
2928 void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2929 inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2930 }
2931
2932 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002933 * Calculates the stable insets without running a layout.
2934 *
2935 * @param displayRotation the current display rotation
2936 * @param displayWidth the current display width
2937 * @param displayHeight the current display height
2938 * @param displayCutout the current display cutout
2939 * @param outInsets the insets to return
2940 */
2941 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2942 DisplayCutout displayCutout, Rect outInsets) {
2943 outInsets.setEmpty();
2944
2945 // Navigation bar and status bar.
2946 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
Riddle Hsu61987bc2019-04-03 13:08:47 +08002947 convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002948 }
2949
2950 /**
2951 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2952 * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2953 *
2954 * @param displayRotation the current display rotation
2955 * @param displayWidth the current display width
2956 * @param displayHeight the current display height
2957 * @param displayCutout the current display cutout
2958 * @param outInsets the insets to return
2959 */
2960 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2961 DisplayCutout displayCutout, Rect outInsets) {
2962 outInsets.setEmpty();
2963
2964 // Only navigation bar
2965 if (hasNavigationBar()) {
2966 final int uiMode = mService.mPolicy.getUiMode();
2967 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2968 if (position == NAV_BAR_BOTTOM) {
2969 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2970 } else if (position == NAV_BAR_RIGHT) {
2971 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2972 } else if (position == NAV_BAR_LEFT) {
2973 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2974 }
2975 }
2976
2977 if (displayCutout != null) {
2978 outInsets.left += displayCutout.getSafeInsetLeft();
2979 outInsets.top += displayCutout.getSafeInsetTop();
2980 outInsets.right += displayCutout.getSafeInsetRight();
2981 outInsets.bottom += displayCutout.getSafeInsetBottom();
2982 }
2983 }
2984
Issei Suzukia5dbf522019-02-01 17:58:15 +01002985 /**
2986 * @see IWindowManager#setForwardedInsets
2987 */
2988 public void setForwardedInsets(@NonNull Insets forwardedInsets) {
2989 mForwardedInsets = forwardedInsets;
2990 }
2991
2992 @NonNull
2993 public Insets getForwardedInsets() {
2994 return mForwardedInsets;
2995 }
2996
Tiger Huang7c610aa2018-10-27 00:01:01 +08002997 @NavigationBarPosition
2998 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
2999 if (navigationBarCanMove() && displayWidth > displayHeight) {
3000 if (displayRotation == Surface.ROTATION_270) {
3001 return NAV_BAR_LEFT;
3002 } else if (displayRotation == Surface.ROTATION_90) {
3003 return NAV_BAR_RIGHT;
3004 }
3005 }
3006 return NAV_BAR_BOTTOM;
3007 }
3008
3009 /**
3010 * @return The side of the screen where navigation bar is positioned.
3011 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
3012 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
3013 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
3014 */
3015 @NavigationBarPosition
3016 public int getNavBarPosition() {
3017 return mNavigationBarPosition;
3018 }
3019
3020 /**
3021 * A new window has been focused.
3022 */
3023 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
3024 mFocusedWindow = newFocus;
3025 mLastFocusedWindow = lastFocus;
Issei Suzuki9f840c72018-12-07 15:09:30 -08003026 if (mDisplayContent.isDefaultDisplay) {
3027 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
3028 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003029 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
3030 // If the navigation bar has been hidden or shown, we need to do another
3031 // layout pass to update that window.
3032 return FINISH_LAYOUT_REDO_LAYOUT;
3033 }
3034 return 0;
3035 }
3036
3037 /**
3038 * Return true if it is okay to perform animations for an app transition
3039 * that is about to occur. You may return false for this if, for example,
3040 * the dream window is currently displayed so the switch should happen
3041 * immediately.
3042 */
3043 public boolean allowAppAnimationsLw() {
3044 return !mShowingDream;
3045 }
3046
3047 private void updateDreamingSleepToken(boolean acquire) {
3048 if (acquire) {
3049 final int displayId = getDisplayId();
3050 if (mDreamingSleepToken == null) {
3051 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
3052 "DreamOnDisplay" + displayId, displayId);
3053 }
3054 } else {
3055 if (mDreamingSleepToken != null) {
3056 mDreamingSleepToken.release();
3057 mDreamingSleepToken = null;
3058 }
3059 }
3060 }
3061
3062 private void requestTransientBars(WindowState swipeTarget) {
3063 synchronized (mLock) {
3064 if (!mService.mPolicy.isUserSetupComplete()) {
3065 // Swipe-up for navigation bar is disabled during setup
3066 return;
3067 }
Jorim Jaggi956ca412019-01-07 14:49:14 +01003068 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
3069 if (swipeTarget == mNavigationBar
Tiger Huang332793b2019-10-29 23:21:27 +08003070 && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
Jorim Jaggi956ca412019-01-07 14:49:14 +01003071 // Don't show status bar when swiping on already visible navigation bar
Tiger Huang7c610aa2018-10-27 00:01:01 +08003072 return;
3073 }
Jorim Jaggi956ca412019-01-07 14:49:14 +01003074 final InsetsControlTarget controlTarget =
3075 swipeTarget.getControllableInsetProvider().getControlTarget();
3076 if (controlTarget == null) {
3077 return;
3078 }
3079 if (controlTarget.canShowTransient()) {
3080 mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
Tiger Huang332793b2019-10-29 23:21:27 +08003081 new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
Jorim Jaggi956ca412019-01-07 14:49:14 +01003082 } else {
Tiger Huang4a7835f2019-11-06 00:07:56 +08003083 controlTarget.showInsets(Type.systemBars(), false);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003084 }
3085 } else {
3086 boolean sb = mStatusBarController.checkShowTransientBarLw();
3087 boolean nb = mNavigationBarController.checkShowTransientBarLw()
3088 && !isNavBarEmpty(mLastSystemUiFlags);
3089 if (sb || nb) {
3090 // Don't show status bar when swiping on already visible navigation bar
3091 if (!nb && swipeTarget == mNavigationBar) {
3092 if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
3093 return;
3094 }
3095 if (sb) mStatusBarController.showTransient();
3096 if (nb) mNavigationBarController.showTransient();
3097 updateSystemUiVisibilityLw();
3098 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003099 mImmersiveModeConfirmation.confirmCurrentPrompt();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003100 }
3101 }
3102 }
3103
3104 private void disposeInputConsumer(InputConsumer inputConsumer) {
3105 if (inputConsumer != null) {
3106 inputConsumer.dismiss();
3107 }
3108 }
3109
wilsonshihe8321942019-10-18 18:39:46 +08003110 boolean isKeyguardShowing() {
3111 return mService.mPolicy.isKeyguardShowing();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003112 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003113 private boolean isKeyguardOccluded() {
3114 // TODO (b/113840485): Handle per display keyguard.
3115 return mService.mPolicy.isKeyguardOccluded();
3116 }
3117
Jorim Jaggi956ca412019-01-07 14:49:14 +01003118 InsetsPolicy getInsetsPolicy() {
3119 return mDisplayContent.getInsetsPolicy();
3120 }
3121
Tiger Huang7c610aa2018-10-27 00:01:01 +08003122 void resetSystemUiVisibilityLw() {
3123 mLastSystemUiFlags = 0;
3124 updateSystemUiVisibilityLw();
3125 }
3126
3127 private int updateSystemUiVisibilityLw() {
3128 // If there is no window focused, there will be nobody to handle the events
3129 // anyway, so just hang on in whatever state we're in until things settle down.
3130 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
3131 : mTopFullscreenOpaqueWindowState;
3132 if (winCandidate == null) {
3133 return 0;
3134 }
3135
3136 // The immersive mode confirmation should never affect the system bar visibility, otherwise
3137 // it will unhide the navigation bar and hide itself.
3138 if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
3139
3140 // The immersive mode confirmation took the focus from mLastFocusedWindow which was
3141 // controlling the system ui visibility. So if mLastFocusedWindow can still receive
3142 // keys, we let it keep controlling the visibility.
3143 final boolean lastFocusCanReceiveKeys =
3144 (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
wilsonshihe8321942019-10-18 18:39:46 +08003145 winCandidate = isKeyguardShowing() ? mNotificationShade
Tiger Huang7c610aa2018-10-27 00:01:01 +08003146 : lastFocusCanReceiveKeys ? mLastFocusedWindow
3147 : mTopFullscreenOpaqueWindowState;
3148 if (winCandidate == null) {
3149 return 0;
3150 }
3151 }
3152 final WindowState win = winCandidate;
wilsonshihe8321942019-10-18 18:39:46 +08003153 if (win.getAttrs().type == TYPE_NOTIFICATION_SHADE && isKeyguardShowing()
3154 && isKeyguardOccluded()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003155 // We are updating at a point where the keyguard has gotten
3156 // focus, but we were last in a state where the top window is
3157 // hiding it. This is probably because the keyguard as been
3158 // shown while the top window was displayed, so we want to ignore
3159 // it here because this is just a very transient change and it
3160 // will quickly lose focus once it correctly gets hidden.
3161 return 0;
3162 }
3163
Jorim Jaggi28620472019-01-02 23:21:49 +01003164 mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
Jorim Jaggib6030952018-10-23 18:31:52 +02003165
Tiger Huang7c610aa2018-10-27 00:01:01 +08003166 int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
3167 & ~mResettingSystemUiFlags
3168 & ~mForceClearedSystemUiFlags;
3169 if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
3170 tmpVisibility
3171 &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
3172 }
3173
Jorim Jaggi956ca412019-01-07 14:49:14 +01003174 final int fullscreenAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
3175 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
3176 final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
3177 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003178 mService.getStackBounds(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003179 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003180 final boolean inSplitScreen = !mDockedStackBounds.isEmpty();
3181 mService.getStackBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
3182 : WINDOWING_MODE_FULLSCREEN,
Tiger Huangd5f0b9a2019-10-10 10:34:57 +02003183 ACTIVITY_TYPE_UNDEFINED, mNonDockedStackBounds);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003184 final Pair<Integer, Boolean> result =
3185 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
3186 final int visibility = result.first;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003187 final int appearance = win.mAttrs.insetsFlags.appearance
3188 | InsetsFlags.getAppearance(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003189 final int diff = visibility ^ mLastSystemUiFlags;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003190 final InsetsPolicy insetsPolicy = getInsetsPolicy();
3191 final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
3192 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) != 0
3193 || (PolicyControl.getWindowFlags(win, win.mAttrs) & FLAG_FULLSCREEN) != 0
Tiger Huang332793b2019-10-29 23:21:27 +08003194 || (mStatusBar != null && insetsPolicy.isHidden(ITYPE_STATUS_BAR))
Jorim Jaggi956ca412019-01-07 14:49:14 +01003195 || (mNavigationBar != null && insetsPolicy.isHidden(
Tiger Huang332793b2019-10-29 23:21:27 +08003196 ITYPE_NAVIGATION_BAR));
Jorim Jaggi956ca412019-01-07 14:49:14 +01003197 final int behavior = win.mAttrs.insetsFlags.behavior;
3198 final boolean isImmersive = (visibility & (View.SYSTEM_UI_FLAG_IMMERSIVE
3199 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)) != 0
3200 || behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
3201 || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003202 if (diff == 0
Jorim Jaggi956ca412019-01-07 14:49:14 +01003203 && mLastAppearance == appearance
3204 && mLastFullscreenAppearance == fullscreenAppearance
3205 && mLastDockedAppearance == dockedAppearance
Tiger Huang4a7835f2019-11-06 00:07:56 +08003206 && mLastBehavior == behavior
Jorim Jaggi956ca412019-01-07 14:49:14 +01003207 && mLastFocusIsFullscreen == isFullscreen
3208 && mLastFocusIsImmersive == isImmersive
Tiger Huang7c610aa2018-10-27 00:01:01 +08003209 && mFocusedApp == win.getAppToken()
3210 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
3211 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
3212 return 0;
3213 }
Tiger Huang0dbd5372019-10-26 00:24:22 +08003214
3215 // Obtains which types should show transient and which types should abort transient.
3216 // If there is no transient state change, this pair will contain two empty arrays.
3217 final Pair<int[], int[]> transientState = getTransientState(visibility, mLastSystemUiFlags);
3218
Tiger Huang7c610aa2018-10-27 00:01:01 +08003219 mLastSystemUiFlags = visibility;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003220 mLastAppearance = appearance;
3221 mLastFullscreenAppearance = fullscreenAppearance;
3222 mLastDockedAppearance = dockedAppearance;
Tiger Huang4a7835f2019-11-06 00:07:56 +08003223 mLastBehavior = behavior;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003224 mLastFocusIsFullscreen = isFullscreen;
3225 mLastFocusIsImmersive = isImmersive;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003226 mFocusedApp = win.getAppToken();
Riddle Hsu4d6a63f2019-03-29 19:14:43 +08003227 mLastNonDockedStackBounds.set(mNonDockedStackBounds);
3228 mLastDockedStackBounds.set(mDockedStackBounds);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003229 final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
3230 final Rect dockedStackBounds = new Rect(mDockedStackBounds);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003231 final AppearanceRegion[] appearanceRegions = inSplitScreen
3232 ? new AppearanceRegion[]{
3233 new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds),
3234 new AppearanceRegion(dockedAppearance, dockedStackBounds)}
3235 : new AppearanceRegion[]{
3236 new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds)};
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003237 final boolean isNavbarColorManagedByIme = result.second;
Vishnu Nair015d8cd2019-11-18 15:56:30 -08003238 String cause = win.toString();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003239 mHandler.post(() -> {
3240 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
3241 if (statusBar != null) {
3242 final int displayId = getDisplayId();
Tiger Huang0dbd5372019-10-26 00:24:22 +08003243 statusBar.setDisableFlags(displayId, visibility & StatusBarManager.DISABLE_MASK,
Vishnu Nair015d8cd2019-11-18 15:56:30 -08003244 cause);
Tiger Huang0dbd5372019-10-26 00:24:22 +08003245 if (transientState.first.length > 0) {
3246 statusBar.showTransient(displayId, transientState.first);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003247 }
Tiger Huang0dbd5372019-10-26 00:24:22 +08003248 if (transientState.second.length > 0) {
3249 statusBar.abortTransient(displayId, transientState.second);
3250 }
3251 statusBar.onSystemBarAppearanceChanged(displayId, appearance,
3252 appearanceRegions, isNavbarColorManagedByIme);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003253 statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive);
3254
3255 // TODO(b/118118435): Remove this after removing system UI visibilities.
Vishnu Nair015d8cd2019-11-18 15:56:30 -08003256 synchronized (mLock) {
3257 mDisplayContent.statusBarVisibilityChanged(
3258 visibility & ~(View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE));
3259 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003260 }
3261 });
3262 return diff;
3263 }
3264
Tiger Huang0dbd5372019-10-26 00:24:22 +08003265 private static Pair<int[], int[]> getTransientState(int vis, int oldVis) {
3266 final IntArray typesToShow = new IntArray(0);
3267 final IntArray typesToAbort = new IntArray(0);
Tiger Huang332793b2019-10-29 23:21:27 +08003268 updateTransientState(vis, oldVis, View.STATUS_BAR_TRANSIENT, ITYPE_STATUS_BAR, typesToShow,
Tiger Huang0dbd5372019-10-26 00:24:22 +08003269 typesToAbort);
3270 updateTransientState(vis, oldVis, View.NAVIGATION_BAR_TRANSIENT,
Tiger Huang332793b2019-10-29 23:21:27 +08003271 ITYPE_NAVIGATION_BAR, typesToShow, typesToAbort);
Tiger Huang0dbd5372019-10-26 00:24:22 +08003272 return Pair.create(typesToShow.toArray(), typesToAbort.toArray());
Tiger Huang7c610aa2018-10-27 00:01:01 +08003273 }
3274
Tiger Huang0dbd5372019-10-26 00:24:22 +08003275 private static void updateTransientState(int vis, int oldVis, int transientFlag,
Tiger Huang332793b2019-10-29 23:21:27 +08003276 @InternalInsetsType int type, IntArray typesToShow, IntArray typesToAbort) {
Tiger Huang0dbd5372019-10-26 00:24:22 +08003277 final boolean wasTransient = (oldVis & transientFlag) != 0;
3278 final boolean isTransient = (vis & transientFlag) != 0;
3279 if (!wasTransient && isTransient) {
3280 typesToShow.add(type);
3281 } else if (wasTransient && !isTransient) {
3282 typesToAbort.add(type);
3283 }
3284 }
3285
3286 private int updateLightStatusBarAppearanceLw(@Appearance int appearance, WindowState opaque,
Jorim Jaggi956ca412019-01-07 14:49:14 +01003287 WindowState opaqueOrDimming) {
wilsonshihe8321942019-10-18 18:39:46 +08003288 final boolean onKeyguard = isKeyguardShowing() && !isKeyguardOccluded();
3289 final WindowState statusColorWin = onKeyguard ? mNotificationShade : opaqueOrDimming;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003290 if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
3291 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
3292 // its light flag.
Tiger Huang332793b2019-10-29 23:21:27 +08003293 appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003294 final int legacyAppearance = InsetsFlags.getAppearance(
3295 PolicyControl.getSystemUiVisibility(statusColorWin, null));
3296 appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance)
Tiger Huang332793b2019-10-29 23:21:27 +08003297 & APPEARANCE_LIGHT_STATUS_BARS;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003298 } else if (statusColorWin != null && statusColorWin.isDimming()) {
3299 // Otherwise if it's dimming, clear the light flag.
Tiger Huang332793b2019-10-29 23:21:27 +08003300 appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003301 }
3302 return appearance;
3303 }
3304
Tiger Huang7c610aa2018-10-27 00:01:01 +08003305 @VisibleForTesting
3306 @Nullable
3307 static WindowState chooseNavigationColorWindowLw(WindowState opaque,
3308 WindowState opaqueOrDimming, WindowState imeWindow,
3309 @NavigationBarPosition int navBarPosition) {
3310 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
3311 // window can be navigation color window.
3312 final boolean imeWindowCanNavColorWindow = imeWindow != null
3313 && imeWindow.isVisibleLw()
3314 && navBarPosition == NAV_BAR_BOTTOM
3315 && (PolicyControl.getWindowFlags(imeWindow, null)
3316 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3317
3318 if (opaque != null && opaqueOrDimming == opaque) {
3319 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
3320 // unless IME window is also eligible, since currently the IME window is always show
3321 // above the opaque fullscreen app window, regardless of the IME target window.
3322 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
3323 return imeWindowCanNavColorWindow ? imeWindow : opaque;
3324 }
3325
3326 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
3327 // No dimming window is involved. Determine the result only with the IME window.
3328 return imeWindowCanNavColorWindow ? imeWindow : null;
3329 }
3330
3331 if (!imeWindowCanNavColorWindow) {
3332 // No IME window is involved. Determine the result only with opaqueOrDimming.
3333 return opaqueOrDimming;
3334 }
3335
3336 // The IME window and the dimming window are competing. Check if the dimming window can be
3337 // IME target or not.
3338 if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3339 // The IME window is above the dimming window.
3340 return imeWindow;
3341 } else {
3342 // The dimming window is above the IME window.
3343 return opaqueOrDimming;
3344 }
3345 }
3346
3347 @VisibleForTesting
3348 static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3349 WindowState imeWindow, WindowState navColorWin) {
3350
3351 if (navColorWin != null) {
3352 if (navColorWin == imeWindow || navColorWin == opaque) {
3353 // Respect the light flag.
3354 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3355 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3356 & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3357 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3358 // Clear the light flag for dimming window.
3359 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3360 }
3361 }
3362 return vis;
3363 }
3364
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003365 private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003366 final boolean dockedStackVisible =
3367 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3368 final boolean freeformStackVisible =
3369 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3370 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3371
3372 // We need to force system bars when the docked stack is visible, when the freeform stack
hyok.kim332ccfc2019-07-02 15:39:43 +09003373 // is focused but also when we are resizing for the transitions when docked stack
Tiger Huang7c610aa2018-10-27 00:01:01 +08003374 // visibility changes.
hyok.kim332ccfc2019-07-02 15:39:43 +09003375 mForceShowSystemBars = dockedStackVisible || win.inFreeformWindowingMode() || resizing
Brad Stenninge0573692019-03-11 13:52:46 -07003376 || mForceShowSystemBarsFromExternal;
wilsonshihe8321942019-10-18 18:39:46 +08003377 final boolean forceOpaqueStatusBar = mForceShowSystemBars && !isKeyguardShowing();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003378
3379 // apply translucent bar vis flags
wilsonshihe8321942019-10-18 18:39:46 +08003380 WindowState fullscreenTransWin = isKeyguardShowing() && !isKeyguardOccluded()
3381 ? mNotificationShade
Tiger Huang7c610aa2018-10-27 00:01:01 +08003382 : mTopFullscreenOpaqueWindowState;
3383 vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3384 vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
Adrian Roosfaba4062019-05-14 15:27:17 +02003385 int dockedVis = mStatusBarController.applyTranslucentFlagLw(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003386 mTopDockedOpaqueWindowState, 0, 0);
Adrian Roosfaba4062019-05-14 15:27:17 +02003387 dockedVis = mNavigationBarController.applyTranslucentFlagLw(
3388 mTopDockedOpaqueWindowState, dockedVis, 0);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003389
3390 final boolean fullscreenDrawsStatusBarBackground =
3391 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3392 final boolean dockedDrawsStatusBarBackground =
3393 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003394 final boolean fullscreenDrawsNavBarBackground =
3395 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
Adrian Roosfaba4062019-05-14 15:27:17 +02003396 final boolean dockedDrawsNavigationBarBackground =
3397 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003398
3399 // prevent status bar interaction from clearing certain flags
3400 int type = win.getAttrs().type;
wilsonshihe8321942019-10-18 18:39:46 +08003401 boolean notificationShadeHasFocus = type == TYPE_NOTIFICATION_SHADE;
3402 if (notificationShadeHasFocus && !isKeyguardShowing()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003403 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3404 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3405 | View.SYSTEM_UI_FLAG_IMMERSIVE
3406 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3407 | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3408 if (isKeyguardOccluded()) {
3409 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3410 }
3411 vis = (vis & ~flags) | (oldVis & flags);
3412 }
3413
3414 if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3415 vis |= View.STATUS_BAR_TRANSPARENT;
3416 vis &= ~View.STATUS_BAR_TRANSLUCENT;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003417 } else if (forceOpaqueStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003418 vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3419 }
3420
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003421 vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003422 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003423
3424 // update status bar
3425 boolean immersiveSticky =
3426 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3427 final boolean hideStatusBarWM =
3428 mTopFullscreenOpaqueWindowState != null
3429 && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3430 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3431 final boolean hideStatusBarSysui =
3432 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3433 final boolean hideNavBarSysui =
3434 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3435
3436 final boolean transientStatusBarAllowed = mStatusBar != null
wilsonshihe8321942019-10-18 18:39:46 +08003437 && (notificationShadeHasFocus || (!mForceShowSystemBars
Tiger Huang7c610aa2018-10-27 00:01:01 +08003438 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3439
3440 final boolean transientNavBarAllowed = mNavigationBar != null
3441 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3442
3443 final long now = SystemClock.uptimeMillis();
3444 final boolean pendingPanic = mPendingPanicGestureUptime != 0
3445 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3446 final DisplayPolicy defaultDisplayPolicy =
3447 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
wilsonshihe8321942019-10-18 18:39:46 +08003448 if (pendingPanic && hideNavBarSysui && !isKeyguardShowing()
Tiger Huang7c610aa2018-10-27 00:01:01 +08003449 // TODO (b/111955725): Show keyguard presentation on all external displays
3450 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3451 // The user performed the panic gesture recently, we're about to hide the bars,
3452 // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3453 mPendingPanicGestureUptime = 0;
3454 mStatusBarController.showTransient();
3455 if (!isNavBarEmpty(vis)) {
3456 mNavigationBarController.showTransient();
3457 }
3458 }
3459
3460 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3461 && !transientStatusBarAllowed && hideStatusBarSysui;
3462 final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3463 && !transientNavBarAllowed;
3464 if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3465 // clear the clearable flags instead
3466 clearClearableFlagsLw();
3467 vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3468 }
3469
3470 final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3471 immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3472 final boolean navAllowedHidden = immersive || immersiveSticky;
3473
3474 if (hideNavBarSysui && !navAllowedHidden
3475 && mService.mPolicy.getWindowLayerLw(win)
3476 > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3477 // We can't hide the navbar from this window otherwise the input consumer would not get
3478 // the input events.
3479 vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3480 }
3481
3482 vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3483
3484 // update navigation bar
3485 boolean oldImmersiveMode = isImmersiveMode(oldVis);
3486 boolean newImmersiveMode = isImmersiveMode(vis);
3487 if (oldImmersiveMode != newImmersiveMode) {
3488 final String pkg = win.getOwningPackage();
3489 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3490 mService.mPolicy.isUserSetupComplete(),
3491 isNavBarEmpty(win.getSystemUiVisibility()));
3492 }
3493
3494 vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3495
3496 final WindowState navColorWin = chooseNavigationColorWindowLw(
3497 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3498 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3499 vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3500 mTopFullscreenOpaqueOrDimmingWindowState,
3501 mDisplayContent.mInputMethodWindow, navColorWin);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003502 // Navbar color is controlled by the IME.
3503 final boolean isManagedByIme =
3504 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003505
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003506 return Pair.create(vis, isManagedByIme);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003507 }
3508
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003509 private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
3510 int translucentFlag) {
3511 if (!controller.isTransparentAllowed(win)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003512 return false;
3513 }
3514 if (win == null) {
3515 return true;
3516 }
3517
3518 final boolean drawsSystemBars =
3519 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3520 final boolean forceDrawsSystemBars =
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003521 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003522
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003523 return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
3524 }
3525
3526 private boolean drawsStatusBarBackground(int vis, WindowState win) {
3527 return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
3528 }
3529
3530 private boolean drawsNavigationBarBackground(int vis, WindowState win) {
3531 return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003532 }
3533
3534 /**
3535 * @return the current visibility flags with the nav-bar opacity related flags toggled based
3536 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3537 */
3538 private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003539 boolean freeformStackVisible, boolean isDockedDividerResizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003540 boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
3541 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
3542 if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
3543 visibility = setNavBarTransparentFlag(visibility);
3544 } else if (dockedStackVisible) {
3545 visibility = setNavBarOpaqueFlag(visibility);
3546 }
3547 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003548 if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003549 if (mIsFreeformWindowOverlappingWithNavBar) {
3550 visibility = setNavBarTranslucentFlag(visibility);
3551 } else {
3552 visibility = setNavBarOpaqueFlag(visibility);
3553 }
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003554 } else if (fullscreenDrawsBackground) {
3555 visibility = setNavBarTransparentFlag(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003556 }
3557 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3558 if (isDockedDividerResizing) {
3559 visibility = setNavBarOpaqueFlag(visibility);
3560 } else if (freeformStackVisible) {
3561 visibility = setNavBarTranslucentFlag(visibility);
3562 } else {
3563 visibility = setNavBarOpaqueFlag(visibility);
3564 }
3565 }
3566
Tiger Huang7c610aa2018-10-27 00:01:01 +08003567 return visibility;
3568 }
3569
3570 private int setNavBarOpaqueFlag(int visibility) {
3571 return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3572 }
3573
3574 private int setNavBarTranslucentFlag(int visibility) {
3575 visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3576 return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3577 }
3578
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003579 private int setNavBarTransparentFlag(int visibility) {
3580 visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3581 return visibility | View.NAVIGATION_BAR_TRANSPARENT;
3582 }
3583
Tiger Huang7c610aa2018-10-27 00:01:01 +08003584 private void clearClearableFlagsLw() {
3585 int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3586 if (newVal != mResettingSystemUiFlags) {
3587 mResettingSystemUiFlags = newVal;
3588 mDisplayContent.reevaluateStatusBarVisibility();
3589 }
3590 }
3591
3592 private boolean isImmersiveMode(int vis) {
3593 final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3594 return mNavigationBar != null
3595 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3596 && (vis & flags) != 0
3597 && canHideNavigationBar();
3598 }
3599
3600 /**
3601 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3602 */
3603 private boolean canHideNavigationBar() {
3604 return hasNavigationBar();
3605 }
3606
3607 private static boolean isNavBarEmpty(int systemUiFlags) {
3608 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3609 | View.STATUS_BAR_DISABLE_BACK
3610 | View.STATUS_BAR_DISABLE_RECENT);
3611
3612 return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3613 }
3614
Tiger Huang7c610aa2018-10-27 00:01:01 +08003615 private final Runnable mHiddenNavPanic = new Runnable() {
3616 @Override
3617 public void run() {
3618 synchronized (mLock) {
3619 if (!mService.mPolicy.isUserSetupComplete()) {
3620 // Swipe-up for navigation bar is disabled during setup
3621 return;
3622 }
3623 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3624 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3625 mNavigationBarController.showTransient();
Jorim Jaggi956ca412019-01-07 14:49:14 +01003626 mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
Tiger Huang332793b2019-10-29 23:21:27 +08003627 new int[] {ITYPE_NAVIGATION_BAR}));
Tiger Huang7c610aa2018-10-27 00:01:01 +08003628 }
3629 }
3630 }
3631 };
3632
3633 void onPowerKeyDown(boolean isScreenOn) {
3634 // Detect user pressing the power button in panic when an application has
3635 // taken over the whole screen.
3636 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3637 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3638 isNavBarEmpty(mLastSystemUiFlags));
3639 if (panic) {
3640 mHandler.post(mHiddenNavPanic);
3641 }
3642 }
3643
3644 void onVrStateChangedLw(boolean enabled) {
3645 mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3646 }
3647
3648 /**
3649 * Called when the state of lock task mode changes. This should be used to disable immersive
3650 * mode confirmation.
3651 *
3652 * @param lockTaskState the new lock task mode state. One of
3653 * {@link ActivityManager#LOCK_TASK_MODE_NONE},
3654 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3655 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3656 */
3657 public void onLockTaskStateChangedLw(int lockTaskState) {
3658 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3659 }
3660
3661 /**
3662 * Request a screenshot be taken.
3663 *
3664 * @param screenshotType The type of screenshot, for example either
3665 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3666 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3667 */
3668 public void takeScreenshot(int screenshotType) {
3669 if (mScreenshotHelper != null) {
3670 mScreenshotHelper.takeScreenshot(screenshotType,
3671 mStatusBar != null && mStatusBar.isVisibleLw(),
James O'Learyfa5bb7a2019-09-05 13:43:29 -04003672 mNavigationBar != null && mNavigationBar.isVisibleLw(),
3673 mHandler, null /* completionConsumer */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003674 }
3675 }
3676
Ady Abrahamf3e05312019-05-13 18:04:59 -07003677 RefreshRatePolicy getRefreshRatePolicy() {
3678 return mRefreshRatePolicy;
3679 }
3680
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003681 void dump(String prefix, PrintWriter pw) {
Riddle Hsuccf09402019-08-13 00:33:06 +08003682 pw.print(prefix); pw.println("DisplayPolicy");
Tiger Huang7c610aa2018-10-27 00:01:01 +08003683 prefix += " ";
3684 pw.print(prefix);
3685 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3686 pw.print(" mDeskDockEnablesAccelerometer=");
3687 pw.println(mDeskDockEnablesAccelerometer);
3688 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3689 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3690 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3691 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3692 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3693 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3694 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3695 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3696 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3697 || mForceClearedSystemUiFlags != 0) {
3698 pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3699 pw.print(Integer.toHexString(mLastSystemUiFlags));
3700 pw.print(" mResettingSystemUiFlags=0x");
3701 pw.print(Integer.toHexString(mResettingSystemUiFlags));
3702 pw.print(" mForceClearedSystemUiFlags=0x");
3703 pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3704 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003705 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3706 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3707 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3708 if (mStatusBar != null) {
3709 pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003710 }
wilsonshihe8321942019-10-18 18:39:46 +08003711 if (mNotificationShade != null) {
3712 pw.print(prefix); pw.print("mExpandedPanel="); pw.print(mNotificationShade);
3713 }
3714 pw.print(" isKeyguardShowing="); pw.println(isKeyguardShowing());
Tiger Huang7c610aa2018-10-27 00:01:01 +08003715 if (mNavigationBar != null) {
3716 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
Winson Chung4723b4e2019-03-25 16:49:36 -07003717 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
3718 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
3719 pw.print(prefix); pw.print("mNavigationBarPosition=");
3720 pw.println(mNavigationBarPosition);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003721 }
3722 if (mFocusedWindow != null) {
3723 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3724 }
3725 if (mFocusedApp != null) {
3726 pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3727 }
3728 if (mTopFullscreenOpaqueWindowState != null) {
3729 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3730 pw.println(mTopFullscreenOpaqueWindowState);
3731 }
3732 if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3733 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3734 pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3735 }
3736 if (mForcingShowNavBar) {
3737 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3738 pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3739 pw.println(mForcingShowNavBarLayer);
3740 }
Riddle Hsuccf09402019-08-13 00:33:06 +08003741 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003742 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
Riddle Hsuccf09402019-08-13 00:33:06 +08003743 pw.print(prefix); pw.print("mForceShowSystemBarsFromExternal=");
3744 pw.print(mForceShowSystemBarsFromExternal);
3745 pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003746 mStatusBarController.dump(pw, prefix);
3747 mNavigationBarController.dump(pw, prefix);
3748
3749 pw.print(prefix); pw.println("Looper state:");
3750 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003751 }
Arthur Hung20479922019-02-27 17:13:22 +08003752
3753 private boolean supportsPointerLocation() {
3754 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
3755 }
3756
3757 void setPointerLocationEnabled(boolean pointerLocationEnabled) {
3758 if (!supportsPointerLocation()) {
3759 return;
3760 }
3761
3762 mHandler.sendEmptyMessage(pointerLocationEnabled
3763 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
3764 }
3765
3766 private void enablePointerLocation() {
3767 if (mPointerLocationView != null) {
3768 return;
3769 }
3770
3771 mPointerLocationView = new PointerLocationView(mContext);
3772 mPointerLocationView.setPrintCoords(false);
3773 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
3774 WindowManager.LayoutParams.MATCH_PARENT,
3775 WindowManager.LayoutParams.MATCH_PARENT);
3776 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3777 lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
3778 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3779 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3780 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3781 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3782 if (ActivityManager.isHighEndGfx()) {
3783 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3784 lp.privateFlags |=
3785 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3786 }
3787 lp.format = PixelFormat.TRANSLUCENT;
3788 lp.setTitle("PointerLocation - display " + getDisplayId());
3789 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3790 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3791 wm.addView(mPointerLocationView, lp);
3792 mDisplayContent.registerPointerEventListener(mPointerLocationView);
3793 }
3794
3795 private void disablePointerLocation() {
3796 if (mPointerLocationView == null) {
3797 return;
3798 }
3799
3800 mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3801 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3802 wm.removeView(mPointerLocationView);
3803 mPointerLocationView = null;
3804 }
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003805
Arthur Hungfbc8f412019-08-01 19:57:54 +08003806 /**
3807 * Check if the window could be excluded from checking if the display has content.
3808 *
3809 * @param w WindowState to check if should be excluded.
3810 * @return True if the window type is PointerLocation which is excluded.
3811 */
3812 boolean isWindowExcludedFromContent(WindowState w) {
3813 if (w != null && mPointerLocationView != null) {
3814 return w.mClient == mPointerLocationView.getWindowToken();
3815 }
3816
3817 return false;
3818 }
3819
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003820 @VisibleForTesting
3821 static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
3822 if (navBarWindow == null || !navBarWindow.isVisibleLw()
Garfield Tane8d84ab2019-10-11 09:49:40 -07003823 || targetWindow.mActivityRecord == null || !targetWindow.isVisibleLw()) {
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003824 return false;
3825 }
3826
3827 return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw());
3828 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003829}