blob: d211cfd835490e41d8150de14a84e0e5dd9229b4 [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 }
1029 });
Tiger Huang332793b2019-10-29 23:21:27 +08001030 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001031 (displayFrames, windowState, inOutFrame) -> {
1032 inOutFrame.top -= mBottomGestureAdditionalInset;
1033 });
Tiger Huang332793b2019-10-29 23:21:27 +08001034 mDisplayContent.setInsetProvider(ITYPE_LEFT_GESTURES, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001035 (displayFrames, windowState, inOutFrame) -> {
1036 inOutFrame.left = 0;
1037 inOutFrame.top = 0;
1038 inOutFrame.bottom = displayFrames.mDisplayHeight;
1039 inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
1040 });
Tiger Huang332793b2019-10-29 23:21:27 +08001041 mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001042 (displayFrames, windowState, inOutFrame) -> {
1043 inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
1044 inOutFrame.top = 0;
1045 inOutFrame.bottom = displayFrames.mDisplayHeight;
1046 inOutFrame.right = displayFrames.mDisplayWidth;
1047 });
Tiger Huang332793b2019-10-29 23:21:27 +08001048 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_TAPPABLE_ELEMENT, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001049 (displayFrames, windowState, inOutFrame) -> {
1050 if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
1051 || mNavigationBarLetsThroughTaps) {
1052 inOutFrame.setEmpty();
1053 }
1054 });
Tiger Huang7c610aa2018-10-27 00:01:01 +08001055 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
1056 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001057 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001058 }
1059
1060 /**
1061 * Called when a window is being removed from a window manager. Must not
1062 * throw an exception -- clean up as much as possible.
1063 *
1064 * @param win The window being removed.
1065 */
Tiger Huang5f6cbca2019-07-18 19:00:01 +08001066 void removeWindowLw(WindowState win) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001067 if (mStatusBar == win) {
1068 mStatusBar = null;
1069 mStatusBarController.setWindow(null);
Tiger Huang332793b2019-10-29 23:21:27 +08001070 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001071 } else if (mNavigationBar == win) {
1072 mNavigationBar = null;
1073 mNavigationBarController.setWindow(null);
Tiger Huang332793b2019-10-29 23:21:27 +08001074 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null);
wilsonshihe8321942019-10-18 18:39:46 +08001075 } else if (mNotificationShade == win) {
1076 mNotificationShade = null;
1077 if (mDisplayContent.isDefaultDisplay) {
1078 mService.mPolicy.setKeyguardCandidateLw(null);
1079 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001080 }
1081 if (mLastFocusedWindow == win) {
1082 mLastFocusedWindow = null;
1083 }
1084 mScreenDecorWindows.remove(win);
1085 }
1086
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001087 private int getStatusBarHeight(DisplayFrames displayFrames) {
1088 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1089 displayFrames.mDisplayCutoutSafe.top);
1090 }
1091
Jorim Jaggi28620472019-01-02 23:21:49 +01001092 WindowState getStatusBar() {
1093 return mStatusBar;
1094 }
1095
wilsonshihe8321942019-10-18 18:39:46 +08001096 WindowState getNotificationShade() {
1097 return mNotificationShade;
1098 }
1099
Jorim Jaggi28620472019-01-02 23:21:49 +01001100 WindowState getNavigationBar() {
1101 return mNavigationBar;
1102 }
1103
Tiger Huang7c610aa2018-10-27 00:01:01 +08001104 /**
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001105 * Control the animation to run when a window's state changes. Return a positive number to
1106 * force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the
1107 * style resource defining the animation, or {@link #ANIMATION_NONE} for no animation.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001108 *
1109 * @param win The window that is changing.
1110 * @param transit What is happening to the window:
1111 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1112 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1113 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1114 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1115 *
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001116 * @return Resource ID of the actual animation to use, or {@link #ANIMATION_NONE} for none.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001117 */
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001118 int selectAnimation(WindowState win, int transit) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001119 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1120 + ": transit=" + transit);
1121 if (win == mStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001122 if (transit == TRANSIT_EXIT
1123 || transit == TRANSIT_HIDE) {
1124 return R.anim.dock_top_exit;
1125 } else if (transit == TRANSIT_ENTER
1126 || transit == TRANSIT_SHOW) {
1127 return R.anim.dock_top_enter;
1128 }
1129 } else if (win == mNavigationBar) {
1130 if (win.getAttrs().windowAnimations != 0) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001131 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001132 }
1133 // This can be on either the bottom or the right or the left.
1134 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1135 if (transit == TRANSIT_EXIT
1136 || transit == TRANSIT_HIDE) {
1137 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1138 return R.anim.dock_bottom_exit_keyguard;
1139 } else {
1140 return R.anim.dock_bottom_exit;
1141 }
1142 } else if (transit == TRANSIT_ENTER
1143 || transit == TRANSIT_SHOW) {
1144 return R.anim.dock_bottom_enter;
1145 }
1146 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1147 if (transit == TRANSIT_EXIT
1148 || transit == TRANSIT_HIDE) {
1149 return R.anim.dock_right_exit;
1150 } else if (transit == TRANSIT_ENTER
1151 || transit == TRANSIT_SHOW) {
1152 return R.anim.dock_right_enter;
1153 }
1154 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1155 if (transit == TRANSIT_EXIT
1156 || transit == TRANSIT_HIDE) {
1157 return R.anim.dock_left_exit;
1158 } else if (transit == TRANSIT_ENTER
1159 || transit == TRANSIT_SHOW) {
1160 return R.anim.dock_left_enter;
1161 }
1162 }
1163 } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001164 return selectDockedDividerAnimation(win, transit);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001165 }
1166
1167 if (transit == TRANSIT_PREVIEW_DONE) {
1168 if (win.hasAppShownWindows()) {
1169 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1170 return R.anim.app_starting_exit;
1171 }
1172 } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
1173 && transit == TRANSIT_ENTER) {
1174 // Special case: we are animating in a dream, while the keyguard
1175 // is shown. We don't want an animation on the dream, because
1176 // we need it shown immediately with the keyguard animating away
1177 // to reveal it.
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001178 return ANIMATION_NONE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001179 }
1180
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001181 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001182 }
1183
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001184 private int selectDockedDividerAnimation(WindowState win, int transit) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001185 int insets = mDisplayContent.getDockedDividerController().getContentInsets();
1186
1187 // If the divider is behind the navigation bar, don't animate.
1188 final Rect frame = win.getFrameLw();
1189 final boolean behindNavBar = mNavigationBar != null
1190 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
1191 && frame.top + insets >= mNavigationBar.getFrameLw().top)
1192 || (mNavigationBarPosition == NAV_BAR_RIGHT
1193 && frame.left + insets >= mNavigationBar.getFrameLw().left)
1194 || (mNavigationBarPosition == NAV_BAR_LEFT
1195 && frame.right - insets <= mNavigationBar.getFrameLw().right));
1196 final boolean landscape = frame.height() > frame.width();
1197 final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
1198 || frame.left + insets >= win.getDisplayFrameLw().right);
1199 final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
1200 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1201 final boolean offscreen = offscreenLandscape || offscreenPortrait;
1202 if (behindNavBar || offscreen) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001203 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001204 }
1205 if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1206 return R.anim.fade_in;
1207 } else if (transit == TRANSIT_EXIT) {
1208 return R.anim.fade_out;
1209 } else {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001210 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001211 }
1212 }
1213
1214 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08001215 * Called when a new system UI visibility is being reported, allowing
1216 * the policy to adjust what is actually reported.
1217 * @param visibility The raw visibility reported by the status bar.
1218 * @return The new desired visibility.
1219 */
1220 public int adjustSystemUiVisibilityLw(int visibility) {
1221 mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1222 mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1223
1224 // Reset any bits in mForceClearingStatusBarVisibility that
1225 // are now clear.
1226 mResettingSystemUiFlags &= visibility;
1227 // Clear any bits in the new visibility that are currently being
1228 // force cleared, before reporting it.
1229 return visibility & ~mResettingSystemUiFlags
1230 & ~mForceClearedSystemUiFlags;
1231 }
1232
1233 /**
Brad Stenninge0573692019-03-11 13:52:46 -07001234 * @return true if the system bars are forced to stay visible
Tiger Huang7c610aa2018-10-27 00:01:01 +08001235 */
Brad Stenninge0573692019-03-11 13:52:46 -07001236 public boolean areSystemBarsForcedShownLw(WindowState windowState) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001237 return mForceShowSystemBars;
1238 }
1239
1240 // TODO: Should probably be moved into DisplayFrames.
1241 /**
1242 * Return the layout hints for a newly added window. These values are computed on the
1243 * most recent layout, so they are not guaranteed to be correct.
1244 *
1245 * @param attrs The LayoutParams of the window.
1246 * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1247 * associated with the window.
1248 * @param displayFrames display frames.
1249 * @param floatingStack Whether the window's stack is floating.
1250 * @param outFrame The frame of the window.
1251 * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1252 * @param outStableInsets The areas covered by stable system windows irrespective of their
1253 * current visibility. Expressed as positive insets.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001254 * @param outDisplayCutout The area that has been cut away from the display.
Brad Stenninge0573692019-03-11 13:52:46 -07001255 * @return Whether to always consume the system bars.
1256 * See {@link #areSystemBarsForcedShownLw(WindowState)}.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001257 */
1258 public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1259 DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1260 Rect outContentInsets, Rect outStableInsets,
Jorim Jaggif081f062019-10-24 16:24:54 +02001261 DisplayCutout.ParcelableWrapper outDisplayCutout) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001262 final int fl = PolicyControl.getWindowFlags(null, attrs);
1263 final int pfl = attrs.privateFlags;
1264 final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1265 final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001266
1267 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1268 final boolean layoutInScreenAndInsetDecor = layoutInScreen
1269 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1270 final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1271
1272 if (layoutInScreenAndInsetDecor && !screenDecor) {
Tiger Huang4a7835f2019-11-06 00:07:56 +08001273 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang52724442020-01-20 21:38:42 +08001274 || (attrs.getFitInsetsTypes() & Type.navigationBars()) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001275 outFrame.set(displayFrames.mUnrestricted);
1276 } else {
1277 outFrame.set(displayFrames.mRestricted);
1278 }
1279
1280 final Rect sf;
1281 if (floatingStack) {
1282 sf = null;
1283 } else {
1284 sf = displayFrames.mStable;
1285 }
1286
1287 final Rect cf;
1288 if (floatingStack) {
1289 cf = null;
1290 } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1291 if ((fl & FLAG_FULLSCREEN) != 0) {
1292 cf = displayFrames.mStableFullscreen;
1293 } else {
1294 cf = displayFrames.mStable;
1295 }
Jorim Jaggif081f062019-10-24 16:24:54 +02001296 } else if ((fl & FLAG_FULLSCREEN) != 0) {
1297 cf = displayFrames.mUnrestricted;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001298 } else {
1299 cf = displayFrames.mCurrent;
1300 }
1301
1302 if (taskBounds != null) {
1303 outFrame.intersect(taskBounds);
1304 }
1305 InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1306 InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1307 outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1308 .getDisplayCutout());
1309 return mForceShowSystemBars;
1310 } else {
1311 if (layoutInScreen) {
1312 outFrame.set(displayFrames.mUnrestricted);
1313 } else {
1314 outFrame.set(displayFrames.mStable);
1315 }
1316 if (taskBounds != null) {
1317 outFrame.intersect(taskBounds);
1318 }
1319
1320 outContentInsets.setEmpty();
1321 outStableInsets.setEmpty();
1322 outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1323 return mForceShowSystemBars;
1324 }
1325 }
1326
Tiger Huang4a7835f2019-11-06 00:07:56 +08001327 // TODO(b/118118435): remove after migration
Tiger Huang7c610aa2018-10-27 00:01:01 +08001328 private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1329 int impliedFlags = 0;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001330 final boolean forceWindowDrawsBarBackgrounds =
1331 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
Tiger Huang4a7835f2019-11-06 00:07:56 +08001332 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001333 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001334 || forceWindowDrawsBarBackgrounds) {
Jorim Jaggid6490572019-04-16 14:57:56 +02001335 impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001336 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1337 }
1338 return impliedFlags;
1339 }
1340
Tiger Huang7c610aa2018-10-27 00:01:01 +08001341 private final Runnable mClearHideNavigationFlag = new Runnable() {
1342 @Override
1343 public void run() {
1344 synchronized (mLock) {
1345 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1346 mDisplayContent.reevaluateStatusBarVisibility();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001347 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL && mNavigationBar != null) {
1348 final InsetsControlTarget target =
1349 mNavigationBar.getControllableInsetProvider().getControlTarget();
1350 if (target != null) {
1351 target.showInsets(Type.navigationBars(), false /* fromIme */);
1352 }
1353 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001354 }
1355 }
1356 };
1357
1358 /**
1359 * Input handler used while nav bar is hidden. Captures any touch on the screen,
1360 * to determine when the nav bar should be shown and prevent applications from
1361 * receiving those touches.
1362 */
1363 private final class HideNavInputEventReceiver extends InputEventReceiver {
1364 HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1365 super(inputChannel, looper);
1366 }
1367
1368 @Override
1369 public void onInputEvent(InputEvent event) {
1370 try {
1371 if (event instanceof MotionEvent
1372 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1373 final MotionEvent motionEvent = (MotionEvent) event;
1374 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1375 // When the user taps down, we re-show the nav bar.
1376 boolean changed = false;
1377 synchronized (mLock) {
1378 if (mInputConsumer == null) {
1379 return;
1380 }
1381 // Any user activity always causes us to show the
1382 // navigation controls, if they had been hidden.
1383 // We also clear the low profile and only content
1384 // flags so that tapping on the screen will atomically
1385 // restore all currently hidden screen decorations.
1386 int newVal = mResettingSystemUiFlags
1387 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1388 | View.SYSTEM_UI_FLAG_LOW_PROFILE
1389 | View.SYSTEM_UI_FLAG_FULLSCREEN;
1390 if (mResettingSystemUiFlags != newVal) {
1391 mResettingSystemUiFlags = newVal;
1392 changed = true;
1393 }
1394 // We don't allow the system's nav bar to be hidden
1395 // again for 1 second, to prevent applications from
1396 // spamming us and keeping it from being shown.
1397 newVal = mForceClearedSystemUiFlags
1398 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1399 if (mForceClearedSystemUiFlags != newVal) {
1400 mForceClearedSystemUiFlags = newVal;
1401 changed = true;
1402 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1403 }
1404 if (changed) {
1405 mDisplayContent.reevaluateStatusBarVisibility();
1406 }
1407 }
1408 }
1409 }
1410 } finally {
1411 finishInputEvent(event, false /* handled */);
1412 }
1413 }
1414 }
1415
1416 /**
1417 * Called when layout of the windows is about to start.
1418 *
1419 * @param displayFrames frames of the display we are doing layout on.
1420 * @param uiMode The current uiMode in configuration.
1421 */
1422 public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1423 displayFrames.onBeginLayout();
1424 mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1425 mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1426
1427 // For purposes of putting out fake window up to steal focus, we will
1428 // drive nav being hidden only by whether it is requested.
1429 final int sysui = mLastSystemUiFlags;
Tiger Huang4a7835f2019-11-06 00:07:56 +08001430 final int behavior = mLastBehavior;
1431 boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
1432 ? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
1433 : mNavigationBar != null && mNavigationBar.getControllableInsetProvider() != null
1434 && mNavigationBar.getControllableInsetProvider().isClientVisible()
1435 && !mDisplayContent.getInsetsPolicy().isTransient(ITYPE_NAVIGATION_BAR);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001436 boolean navTranslucent = (sysui
1437 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
Tiger Huang4a7835f2019-11-06 00:07:56 +08001438 boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
1439 || (behavior & BEHAVIOR_SHOW_BARS_BY_SWIPE) != 0;
1440 boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
1441 || (behavior & BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001442 boolean navAllowedHidden = immersive || immersiveSticky;
1443 navTranslucent &= !immersiveSticky; // transient trumps translucent
wilsonshihe8321942019-10-18 18:39:46 +08001444 boolean isKeyguardShowing = isKeyguardShowing() && !isKeyguardOccluded();
1445 boolean notificationShadeForcesShowingNavigation =
1446 !isKeyguardShowing && mNotificationShade != null
1447 && (mNotificationShade.getAttrs().privateFlags
Tiger Huang7c610aa2018-10-27 00:01:01 +08001448 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1449
1450 // When the navigation bar isn't visible, we put up a fake input window to catch all
1451 // touch events. This way we can detect when the user presses anywhere to bring back the
1452 // nav bar and ensure the application doesn't see the event.
1453 if (navVisible || navAllowedHidden) {
1454 if (mInputConsumer != null) {
1455 mHandler.sendMessage(
1456 mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1457 mInputConsumer = null;
1458 }
1459 } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1460 mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1461 INPUT_CONSUMER_NAVIGATION,
1462 HideNavInputEventReceiver::new,
1463 displayFrames.mDisplayId);
1464 // As long as mInputConsumer is active, hover events are not dispatched to the app
1465 // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1466 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1467 }
1468
1469 // For purposes of positioning and showing the nav bar, if we have decided that it can't
1470 // be hidden (because of the screen aspect ratio), then take that into account.
1471 navVisible |= !canHideNavigationBar();
1472
1473 boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
wilsonshihe8321942019-10-18 18:39:46 +08001474 navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001475 if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1476 updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1477 if (updateSysUiVisibility) {
1478 updateSystemUiVisibilityLw();
1479 }
1480 layoutScreenDecorWindows(displayFrames);
1481
1482 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1483 // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1484 // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1485 // bar.
1486 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1487 displayFrames.mStable.top);
1488 }
Issei Suzukia5dbf522019-02-01 17:58:15 +01001489
1490 // In case this is a virtual display, and the host display has insets that overlap this
1491 // virtual display, apply the insets of the overlapped area onto the current and content
1492 // frame of this virtual display. This let us layout windows in the virtual display as
1493 // expected when the window needs to avoid overlap with the system windows.
1494 // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1495 // IME.
1496 displayFrames.mCurrent.inset(mForwardedInsets);
1497 displayFrames.mContent.inset(mForwardedInsets);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001498 }
1499
1500 private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1501 if (mScreenDecorWindows.isEmpty()) {
1502 return;
1503 }
1504
1505 sTmpRect.setEmpty();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001506 final int displayId = displayFrames.mDisplayId;
1507 final Rect dockFrame = displayFrames.mDock;
1508 final int displayHeight = displayFrames.mDisplayHeight;
1509 final int displayWidth = displayFrames.mDisplayWidth;
1510
1511 for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1512 final WindowState w = mScreenDecorWindows.valueAt(i);
1513 if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1514 // Skip if not on the same display or not visible.
1515 continue;
1516 }
1517
chaviw0d833762019-06-20 17:09:53 -07001518 w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1519 displayFrames.mUnrestricted /* displayFrame */,
chaviw0d833762019-06-20 17:09:53 -07001520 displayFrames.mUnrestricted /* contentFrame */,
1521 displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001522 displayFrames.mUnrestricted /* stableFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001523 w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1524 w.computeFrameLw();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001525 if (w.getControllableInsetProvider() != null) {
1526 w.getControllableInsetProvider().updateSourceFrame();
1527 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001528 final Rect frame = w.getFrameLw();
1529
1530 if (frame.left <= 0 && frame.top <= 0) {
1531 // Docked at left or top.
1532 if (frame.bottom >= displayHeight) {
1533 // Docked left.
1534 dockFrame.left = Math.max(frame.right, dockFrame.left);
1535 } else if (frame.right >= displayWidth) {
1536 // Docked top.
1537 dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1538 } else {
1539 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1540 + " not docked on left or top of display. frame=" + frame
1541 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1542 }
1543 } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1544 // Docked at right or bottom.
1545 if (frame.top <= 0) {
1546 // Docked right.
1547 dockFrame.right = Math.min(frame.left, dockFrame.right);
1548 } else if (frame.left <= 0) {
1549 // Docked bottom.
1550 dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1551 } else {
1552 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1553 + " not docked on right or bottom" + " of display. frame=" + frame
1554 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1555 }
1556 } else {
1557 // Screen decor windows are required to be docked on one of the sides of the screen.
1558 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1559 + " not docked on one of the sides of the display. frame=" + frame
1560 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1561 }
1562 }
1563
1564 displayFrames.mRestricted.set(dockFrame);
1565 displayFrames.mCurrent.set(dockFrame);
1566 displayFrames.mVoiceContent.set(dockFrame);
1567 displayFrames.mSystem.set(dockFrame);
1568 displayFrames.mContent.set(dockFrame);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001569 }
1570
1571 private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1572 boolean isKeyguardShowing) {
1573 // decide where the status bar goes ahead of time
1574 if (mStatusBar == null) {
1575 return false;
1576 }
1577 // apply any navigation bar insets
1578 sTmpRect.setEmpty();
Jorim Jaggi4981f152019-03-26 18:58:45 +01001579 final WindowFrames windowFrames = mStatusBar.getWindowFrames();
1580 windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001581 displayFrames.mUnrestricted /* displayFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001582 displayFrames.mStable /* contentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001583 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001584 displayFrames.mStable /* stableFrame */);
Jorim Jaggi4981f152019-03-26 18:58:45 +01001585 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001586
1587 // Let the status bar determine its size.
1588 mStatusBar.computeFrameLw();
1589
Tiger Huang4a7835f2019-11-06 00:07:56 +08001590 // Update the source frame to provide insets to other windows during layout.
1591 if (mStatusBar.getControllableInsetProvider() != null) {
1592 mStatusBar.getControllableInsetProvider().updateSourceFrame();
1593 }
1594
Tiger Huang7c610aa2018-10-27 00:01:01 +08001595 // For layout, the status bar is always at the top with our fixed height.
1596 displayFrames.mStable.top = displayFrames.mUnrestricted.top
1597 + mStatusBarHeightForRotation[displayFrames.mRotation];
1598 // Make sure the status bar covers the entire cutout height
1599 displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1600 displayFrames.mDisplayCutoutSafe.top);
1601
1602 // Tell the bar controller where the collapsed status bar content is
1603 sTmpRect.set(mStatusBar.getContentFrameLw());
1604 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1605 sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
1606 sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
1607 mStatusBarController.setContentFrame(sTmpRect);
1608
Tiger Huang4a7835f2019-11-06 00:07:56 +08001609 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0
1610 || mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001611 boolean statusBarTranslucent = (sysui
1612 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001613
1614 // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1615 if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1616 // Status bar may go away, so the screen area it occupies is available to apps but just
1617 // covering them when the status bar is visible.
1618 final Rect dockFrame = displayFrames.mDock;
1619 dockFrame.top = displayFrames.mStable.top;
1620 displayFrames.mContent.set(dockFrame);
1621 displayFrames.mVoiceContent.set(dockFrame);
1622 displayFrames.mCurrent.set(dockFrame);
1623
1624 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1625 "dock=%s content=%s cur=%s", dockFrame.toString(),
1626 displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1627
Jorim Jaggi4981f152019-03-26 18:58:45 +01001628 if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
1629 && !mStatusBar.isAnimatingLw()) {
1630
Tiger Huang7c610aa2018-10-27 00:01:01 +08001631 // If the opaque status bar is currently requested to be visible, and not in the
1632 // process of animating on or off, then we can tell the app that it is covered by
1633 // it.
1634 displayFrames.mSystem.top = displayFrames.mStable.top;
1635 }
1636 }
1637 return mStatusBarController.checkHiddenLw();
1638 }
1639
1640 private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1641 boolean navTranslucent, boolean navAllowedHidden,
1642 boolean statusBarForcesShowingNavigation) {
1643 if (mNavigationBar == null) {
1644 return false;
1645 }
1646
1647 final Rect navigationFrame = sTmpNavFrame;
1648 boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1649 // Force the navigation bar to its appropriate place and size. We need to do this directly,
1650 // instead of relying on it to bubble up from the nav bar, because this needs to change
1651 // atomically with screen rotations.
1652 final int rotation = displayFrames.mRotation;
1653 final int displayHeight = displayFrames.mDisplayHeight;
1654 final int displayWidth = displayFrames.mDisplayWidth;
1655 final Rect dockFrame = displayFrames.mDock;
1656 mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1657
1658 final Rect cutoutSafeUnrestricted = sTmpRect;
1659 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1660 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1661
1662 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1663 // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1664 final int top = cutoutSafeUnrestricted.bottom
1665 - getNavigationBarHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001666 final int topNavBar = cutoutSafeUnrestricted.bottom
Matthew Nga7f24bc2019-04-09 17:06:41 -07001667 - getNavigationBarFrameHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001668 navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001669 displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1670 if (transientNavBarShowing) {
1671 mNavigationBarController.setBarShowingLw(true);
1672 } else if (navVisible) {
1673 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001674 dockFrame.bottom = displayFrames.mRestricted.bottom = top;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001675 } else {
1676 // We currently want to hide the navigation UI - unless we expanded the status bar.
1677 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1678 }
1679 if (navVisible && !navTranslucent && !navAllowedHidden
1680 && !mNavigationBar.isAnimatingLw()
1681 && !mNavigationBarController.wasRecentlyTranslucent()) {
1682 // If the opaque nav bar is currently requested to be visible and not in the process
1683 // of animating on or off, then we can tell the app that it is covered by it.
1684 displayFrames.mSystem.bottom = top;
1685 }
1686 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1687 // Landscape screen; nav bar goes to the right.
1688 final int left = cutoutSafeUnrestricted.right
1689 - getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001690 navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001691 displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1692 if (transientNavBarShowing) {
1693 mNavigationBarController.setBarShowingLw(true);
1694 } else if (navVisible) {
1695 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001696 dockFrame.right = displayFrames.mRestricted.right = left;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001697 } else {
1698 // We currently want to hide the navigation UI - unless we expanded the status bar.
1699 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1700 }
1701 if (navVisible && !navTranslucent && !navAllowedHidden
1702 && !mNavigationBar.isAnimatingLw()
1703 && !mNavigationBarController.wasRecentlyTranslucent()) {
1704 // If the nav bar is currently requested to be visible, and not in the process of
1705 // animating on or off, then we can tell the app that it is covered by it.
1706 displayFrames.mSystem.right = left;
1707 }
1708 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1709 // Seascape screen; nav bar goes to the left.
1710 final int right = cutoutSafeUnrestricted.left
1711 + getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001712 navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001713 displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1714 if (transientNavBarShowing) {
1715 mNavigationBarController.setBarShowingLw(true);
1716 } else if (navVisible) {
1717 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001718 dockFrame.left = displayFrames.mRestricted.left = right;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001719 } else {
1720 // We currently want to hide the navigation UI - unless we expanded the status bar.
1721 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1722 }
1723 if (navVisible && !navTranslucent && !navAllowedHidden
1724 && !mNavigationBar.isAnimatingLw()
1725 && !mNavigationBarController.wasRecentlyTranslucent()) {
1726 // If the nav bar is currently requested to be visible, and not in the process of
1727 // animating on or off, then we can tell the app that it is covered by it.
1728 displayFrames.mSystem.left = right;
1729 }
1730 }
1731
1732 // Make sure the content and current rectangles are updated to account for the restrictions
1733 // from the navigation bar.
1734 displayFrames.mCurrent.set(dockFrame);
1735 displayFrames.mVoiceContent.set(dockFrame);
1736 displayFrames.mContent.set(dockFrame);
1737 // And compute the final frame.
1738 sTmpRect.setEmpty();
1739 mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001740 navigationFrame /* displayFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001741 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1742 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001743 navigationFrame /* stableFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001744 mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1745 mNavigationBar.computeFrameLw();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001746 if (mNavigationBar.getControllableInsetProvider() != null) {
1747 mNavigationBar.getControllableInsetProvider().updateSourceFrame();
1748 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001749 mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1750
1751 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1752 return mNavigationBarController.checkHiddenLw();
1753 }
1754
1755 private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
Jorim Jaggif081f062019-10-24 16:24:54 +02001756 boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001757 DisplayFrames displayFrames) {
1758 if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1759 // Here's a special case: if the child window is not the 'dock window'
1760 // or input method target, and the window it is attached to is below
1761 // the dock window, then the frames we computed for the window it is
1762 // attached to can not be used because the dock is effectively part
1763 // of the underlying window and the attached window is floating on top
1764 // of the whole thing. So, we ignore the attached window and explicitly
1765 // compute the frames that would be appropriate without the dock.
1766 vf.set(displayFrames.mDock);
1767 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001768 df.set(displayFrames.mDock);
1769 } else {
Jorim Jaggid6490572019-04-16 14:57:56 +02001770
Jorim Jaggif081f062019-10-24 16:24:54 +02001771 // In case we forced the window to draw behind the navigation bar, restrict df to
1772 // DF.Restricted to simulate old compat behavior.
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001773 Rect parentDisplayFrame = attached.getDisplayFrameLw();
Jorim Jaggid6490572019-04-16 14:57:56 +02001774 final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
1775 if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1776 && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1777 && (attachedAttrs.systemUiVisibility
1778 & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001779 parentDisplayFrame = new Rect(parentDisplayFrame);
Jorim Jaggif081f062019-10-24 16:24:54 +02001780 parentDisplayFrame.intersect(displayFrames.mRestricted);
Jorim Jaggid6490572019-04-16 14:57:56 +02001781 }
1782
Tiger Huang7c610aa2018-10-27 00:01:01 +08001783 // The effective display frame of the attached window depends on whether it is taking
1784 // care of insetting its content. If not, we need to use the parent's content frame so
1785 // that the entire window is positioned within that content. Otherwise we can use the
Jorim Jaggif081f062019-10-24 16:24:54 +02001786 // parent display frame and let the attached window take care of positioning its content
Tiger Huang7c610aa2018-10-27 00:01:01 +08001787 // appropriately.
1788 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1789 // Set the content frame of the attached window to the parent's decor frame
1790 // (same as content frame when IME isn't present) if specifically requested by
1791 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1792 // Otherwise, use the overscan frame.
1793 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
Jorim Jaggif081f062019-10-24 16:24:54 +02001794 ? attached.getContentFrameLw() : parentDisplayFrame);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001795 } else {
1796 // If the window is resizing, then we want to base the content frame on our attached
1797 // content frame to resize...however, things can be tricky if the attached window is
1798 // NOT in resize mode, in which case its content frame will be larger.
1799 // Ungh. So to deal with that, make sure the content frame we end up using is not
1800 // covering the IM dock.
1801 cf.set(attached.getContentFrameLw());
1802 if (attached.isVoiceInteraction()) {
1803 cf.intersectUnchecked(displayFrames.mVoiceContent);
1804 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1805 cf.intersectUnchecked(displayFrames.mContent);
1806 }
1807 }
Jorim Jaggid6490572019-04-16 14:57:56 +02001808 df.set(insetDecors ? parentDisplayFrame : cf);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001809 vf.set(attached.getVisibleFrameLw());
1810 }
1811 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1812 // positioned relative to its parent or the entire screen.
1813 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1814 }
1815
1816 private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1817 if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1818 return;
1819 }
1820 // If app is requesting a stable layout, don't let the content insets go below the stable
1821 // values.
1822 if ((fl & FLAG_FULLSCREEN) != 0) {
1823 r.intersectUnchecked(displayFrames.mStableFullscreen);
1824 } else {
1825 r.intersectUnchecked(displayFrames.mStable);
1826 }
1827 }
1828
1829 private boolean canReceiveInput(WindowState win) {
1830 boolean notFocusable =
1831 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1832 boolean altFocusableIm =
1833 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1834 boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1835 return !notFocusableForIm;
1836 }
1837
1838 /**
1839 * Called for each window attached to the window manager as layout is proceeding. The
1840 * implementation of this function must take care of setting the window's frame, either here or
1841 * in finishLayout().
1842 *
1843 * @param win The window being positioned.
1844 * @param attached For sub-windows, the window it is attached to; this
1845 * window will already have had layoutWindow() called on it
1846 * so you can use its Rect. Otherwise null.
1847 * @param displayFrames The display frames.
1848 */
1849 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1850 // We've already done the navigation bar, status bar, and all screen decor windows. If the
1851 // status bar can receive input, we need to layout it again to accommodate for the IME
1852 // window.
1853 if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1854 || mScreenDecorWindows.contains(win)) {
1855 return;
1856 }
1857 final WindowManager.LayoutParams attrs = win.getAttrs();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001858
1859 final int type = attrs.type;
1860 final int fl = PolicyControl.getWindowFlags(win, attrs);
1861 final int pfl = attrs.privateFlags;
1862 final int sim = attrs.softInputMode;
1863 final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1864 final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1865
1866 final WindowFrames windowFrames = win.getWindowFrames();
1867
Tiger Huang7c610aa2018-10-27 00:01:01 +08001868 sTmpLastParentFrame.set(windowFrames.mParentFrame);
1869 final Rect pf = windowFrames.mParentFrame;
1870 final Rect df = windowFrames.mDisplayFrame;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001871 final Rect cf = windowFrames.mContentFrame;
1872 final Rect vf = windowFrames.mVisibleFrame;
1873 final Rect dcf = windowFrames.mDecorFrame;
1874 final Rect sf = windowFrames.mStableFrame;
1875 dcf.setEmpty();
1876 windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1877 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1878
1879 final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1880 && mNavigationBar.isVisibleLw();
1881
1882 final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1883
Tiger Huang7c610aa2018-10-27 00:01:01 +08001884 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1885 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1886
1887 sf.set(displayFrames.mStable);
1888
Tiger Huang4a7835f2019-11-06 00:07:56 +08001889 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
Tiger Huang52724442020-01-20 21:38:42 +08001890 final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
1891 final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001892 final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
1893 final Rect dfu = displayFrames.mUnrestricted;
1894 Insets insets = Insets.of(0, 0, 0, 0);
1895 for (int i = types.size() - 1; i >= 0; i--) {
Tiger Huang82520fc2019-12-19 22:29:20 +08001896 insets = Insets.max(insets, mDisplayContent.getInsetsPolicy()
Tiger Huang4a7835f2019-11-06 00:07:56 +08001897 .getInsetsForDispatch(win).getSource(types.valueAt(i))
Tiger Huang52724442020-01-20 21:38:42 +08001898 .calculateInsets(dfu, attrs.isFitInsetsIgnoringVisibility()));
Tiger Huang4a7835f2019-11-06 00:07:56 +08001899 }
1900 final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
1901 final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
1902 final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
1903 final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
1904 df.set(left, top, dfu.right - right, dfu.bottom - bottom);
1905 if (attached == null) {
1906 pf.set(df);
1907 vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
1908 ? displayFrames.mCurrent : displayFrames.mDock);
1909 } else {
1910 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1911 vf.set(attached.getVisibleFrameLw());
1912 }
1913 cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
1914 ? displayFrames.mDock : displayFrames.mContent);
1915 dcf.set(displayFrames.mSystem);
1916 } else if (type == TYPE_INPUT_METHOD) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001917 vf.set(displayFrames.mDock);
1918 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001919 df.set(displayFrames.mDock);
Tiger Huang4a7835f2019-11-06 00:07:56 +08001920 pf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001921 // IM dock windows layout below the nav bar...
Jorim Jaggif081f062019-10-24 16:24:54 +02001922 pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001923 // ...with content insets above the nav bar
1924 cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1925 if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1926 // The status bar forces the navigation bar while it's visible. Make sure the IME
1927 // avoids the navigation bar in that case.
1928 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001929 pf.right = df.right = cf.right = vf.right =
Tiger Huang7c610aa2018-10-27 00:01:01 +08001930 displayFrames.mStable.right;
1931 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001932 pf.left = df.left = cf.left = vf.left = displayFrames.mStable.left;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001933 }
1934 }
1935
Matthew Nga7f24bc2019-04-09 17:06:41 -07001936 // In case the navigation bar is on the bottom, we use the frame height instead of the
1937 // regular height for the insets we send to the IME as we need some space to show
1938 // additional buttons in SystemUI when the IME is up.
1939 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1940 final int rotation = displayFrames.mRotation;
1941 final int uimode = mService.mPolicy.getUiMode();
1942 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
1943 - getNavigationBarHeight(rotation, uimode);
1944 if (navHeightOffset > 0) {
1945 cf.bottom -= navHeightOffset;
1946 sf.bottom -= navHeightOffset;
1947 vf.bottom -= navHeightOffset;
1948 dcf.bottom -= navHeightOffset;
1949 }
1950 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001951
1952 // IM dock windows always go to the bottom of the screen.
1953 attrs.gravity = Gravity.BOTTOM;
1954 } else if (type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001955 df.set(displayFrames.mUnrestricted);
1956 pf.set(displayFrames.mUnrestricted);
1957 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1958 cf.set(displayFrames.mDock);
1959 } else {
1960 cf.set(displayFrames.mContent);
1961 }
1962 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1963 vf.set(displayFrames.mCurrent);
1964 } else {
1965 vf.set(cf);
1966 }
1967 } else if (type == TYPE_WALLPAPER) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001968 layoutWallpaper(displayFrames, pf, df, cf);
Jorim Jaggif2ce4fa2020-01-21 22:32:37 +01001969 } else if (win == mStatusBar || type == TYPE_NOTIFICATION_SHADE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001970 df.set(displayFrames.mUnrestricted);
1971 pf.set(displayFrames.mUnrestricted);
1972 cf.set(displayFrames.mStable);
1973 vf.set(displayFrames.mStable);
1974
1975 if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7fe7f682019-10-26 01:11:23 +08001976 // cf.bottom should not be below the stable bottom, or the content might be obscured
1977 // by the navigation bar.
1978 if (cf.bottom > displayFrames.mContent.bottom) {
1979 cf.bottom = displayFrames.mContent.bottom;
1980 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001981 } else {
Tiger Huang7fe7f682019-10-26 01:11:23 +08001982 if (cf.bottom > displayFrames.mDock.bottom) {
1983 cf.bottom = displayFrames.mDock.bottom;
1984 }
1985 if (vf.bottom > displayFrames.mContent.bottom) {
1986 vf.bottom = displayFrames.mContent.bottom;
1987 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001988 }
1989 } else {
1990 dcf.set(displayFrames.mSystem);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001991 final boolean isAppWindow =
1992 type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1993 final boolean topAtRest =
1994 win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
Jorim Jaggia2e648e2019-10-25 15:06:53 +02001995 if (isAppWindow && !topAtRest) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001996 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
1997 && (fl & FLAG_FULLSCREEN) == 0
1998 && (fl & FLAG_TRANSLUCENT_STATUS) == 0
1999 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07002000 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002001 // Ensure policy decor includes status bar
2002 dcf.top = displayFrames.mStable.top;
2003 }
2004 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
2005 && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07002006 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
2007 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002008 // Ensure policy decor includes navigation bar
2009 dcf.bottom = displayFrames.mStable.bottom;
2010 dcf.right = displayFrames.mStable.right;
2011 }
2012 }
2013
2014 if (layoutInScreen && layoutInsetDecor) {
2015 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2016 + "): IN_SCREEN, INSET_DECOR");
2017 // This is the case for a normal activity window: we want it to cover all of the
2018 // screen space, and it can take care of moving its contents to account for screen
2019 // decorations that intrude into that space.
2020 if (attached != null) {
2021 // If this window is attached to another, our display
2022 // frame is the same as the one we are attached to.
Jorim Jaggif081f062019-10-24 16:24:54 +02002023 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08002024 displayFrames);
2025 } else {
2026 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2027 // Status bar panels are the only windows who can go on top of the status
2028 // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
2029 // have the same privileges as the status bar itself.
2030 //
2031 // However, they should still dodge the navigation bar if it exists.
2032
Jorim Jaggif081f062019-10-24 16:24:54 +02002033 pf.left = df.left = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002034 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
Jorim Jaggif081f062019-10-24 16:24:54 +02002035 pf.top = df.top = displayFrames.mUnrestricted.top;
2036 pf.right = df.right = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002037 ? displayFrames.mRestricted.right
2038 : displayFrames.mUnrestricted.right;
Jorim Jaggif081f062019-10-24 16:24:54 +02002039 pf.bottom = df.bottom = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002040 ? displayFrames.mRestricted.bottom
2041 : displayFrames.mUnrestricted.bottom;
2042
2043 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
Jorim Jaggid6490572019-04-16 14:57:56 +02002044 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08002045 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
Charles Chen64172bb2019-04-22 17:30:29 +08002046 || type == TYPE_VOLUME_OVERLAY
2047 || type == TYPE_KEYGUARD_DIALOG)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002048 // Asking for layout as if the nav bar is hidden, lets the application
2049 // extend into the unrestricted overscan screen area. We only do this for
2050 // application windows and certain system windows to ensure no window that
2051 // can be above the nav bar can do this.
Jorim Jaggif081f062019-10-24 16:24:54 +02002052 df.set(displayFrames.mUnrestricted);
2053 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002054 } else {
Jorim Jaggif081f062019-10-24 16:24:54 +02002055 df.set(displayFrames.mRestricted);
2056 pf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002057 }
2058
2059 if ((fl & FLAG_FULLSCREEN) == 0) {
2060 if (win.isVoiceInteraction()) {
2061 cf.set(displayFrames.mVoiceContent);
2062 } else {
Jorim Jaggi648e5882019-01-24 13:24:02 +01002063 // IME Insets are handled on the client for ADJUST_RESIZE in the new
2064 // insets world
2065 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2066 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002067 cf.set(displayFrames.mDock);
2068 } else {
2069 cf.set(displayFrames.mContent);
2070 }
2071 }
2072 } else {
2073 // Full screen windows are always given a layout that is as if the status
2074 // bar and other transient decors are gone. This is to avoid bad states when
2075 // moving from a window that is not hiding the status bar to one that is.
2076 cf.set(displayFrames.mRestricted);
2077 }
2078 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
Jorim Jaggi4e04eb22020-01-09 16:42:14 +01002079 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
2080 && adjust != SOFT_INPUT_ADJUST_NOTHING) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002081 vf.set(displayFrames.mCurrent);
2082 } else {
2083 vf.set(cf);
2084 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002085 }
2086 } else if (layoutInScreen || (sysUiFl
Tiger Huang4a7835f2019-11-06 00:07:56 +08002087 & (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Jorim Jaggid6490572019-04-16 14:57:56 +02002088 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002089 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2090 + "): IN_SCREEN");
2091 // A window that has requested to fill the entire screen just
2092 // gets everything, period.
2093 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2094 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002095 df.set(displayFrames.mUnrestricted);
2096 pf.set(displayFrames.mUnrestricted);
2097 if (hasNavBar) {
Jorim Jaggif081f062019-10-24 16:24:54 +02002098 pf.left = df.left = cf.left = displayFrames.mDock.left;
2099 pf.right = df.right = cf.right = displayFrames.mRestricted.right;
2100 pf.bottom = df.bottom = cf.bottom =
Tiger Huang7c610aa2018-10-27 00:01:01 +08002101 displayFrames.mRestricted.bottom;
2102 }
2103 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
2104 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
2105 // The navigation bar has Real Ultimate Power.
Tiger Huang7c610aa2018-10-27 00:01:01 +08002106 df.set(displayFrames.mUnrestricted);
2107 pf.set(displayFrames.mUnrestricted);
2108 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
2109 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
2110 && ((fl & FLAG_FULLSCREEN) != 0)) {
2111 // Fullscreen secure system overlays get what they ask for. Screenshot region
2112 // selection overlay should also expand to full screen.
Jorim Jaggif081f062019-10-24 16:24:54 +02002113 cf.set(displayFrames.mUnrestricted);
2114 df.set(displayFrames.mUnrestricted);
2115 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002116 } else if (type == TYPE_BOOT_PROGRESS) {
2117 // Boot progress screen always covers entire display.
Jorim Jaggif081f062019-10-24 16:24:54 +02002118 cf.set(displayFrames.mUnrestricted);
2119 df.set(displayFrames.mUnrestricted);
2120 pf.set(displayFrames.mUnrestricted);
Jorim Jaggid6490572019-04-16 14:57:56 +02002121 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
wilsonshihe8321942019-10-18 18:39:46 +08002122 && (type == TYPE_NOTIFICATION_SHADE
Tiger Huang7c610aa2018-10-27 00:01:01 +08002123 || type == TYPE_TOAST
2124 || type == TYPE_DOCK_DIVIDER
2125 || type == TYPE_VOICE_INTERACTION_STARTING
2126 || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
2127 // Asking for layout as if the nav bar is hidden, lets the
2128 // application extend into the unrestricted screen area. We
2129 // only do this for application windows (or toasts) to ensure no window that
2130 // can be above the nav bar can do this.
2131 // XXX This assumes that an app asking for this will also
2132 // ask for layout in only content. We can't currently figure out
2133 // what the screen would be if only laying out to hide the nav bar.
2134 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002135 df.set(displayFrames.mUnrestricted);
2136 pf.set(displayFrames.mUnrestricted);
Tiger Huang4a7835f2019-11-06 00:07:56 +08002137 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002138 df.set(displayFrames.mRestricted);
2139 pf.set(displayFrames.mRestricted);
Jorim Jaggi648e5882019-01-24 13:24:02 +01002140
2141 // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2142 // world
2143 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2144 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002145 cf.set(displayFrames.mDock);
2146 } else {
2147 cf.set(displayFrames.mContent);
2148 }
2149 } else {
2150 cf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002151 df.set(displayFrames.mRestricted);
2152 pf.set(displayFrames.mRestricted);
2153 }
2154
2155 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2156
Jorim Jaggi4e04eb22020-01-09 16:42:14 +01002157 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
2158 && adjust != SOFT_INPUT_ADJUST_NOTHING) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002159 vf.set(displayFrames.mCurrent);
2160 } else {
2161 vf.set(cf);
2162 }
2163 } else if (attached != null) {
2164 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2165 + "): attached to " + attached);
2166 // A child window should be placed inside of the same visible
2167 // frame that its parent had.
Jorim Jaggif081f062019-10-24 16:24:54 +02002168 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08002169 displayFrames);
2170 } else {
2171 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2172 + "): normal window");
2173 // Otherwise, a normal window must be placed inside the content
2174 // of all screen decorations.
2175 if (type == TYPE_STATUS_BAR_PANEL) {
2176 // Status bar panels can go on
2177 // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2178 // permission, so they have the same privileges as the status bar itself.
2179 cf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002180 df.set(displayFrames.mRestricted);
2181 pf.set(displayFrames.mRestricted);
Vishnu Nair9ccb1d22019-03-20 16:32:44 +00002182 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002183 // These dialogs are stable to interim decor changes.
2184 cf.set(displayFrames.mStable);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002185 df.set(displayFrames.mStable);
2186 pf.set(displayFrames.mStable);
2187 } else {
2188 pf.set(displayFrames.mContent);
2189 if (win.isVoiceInteraction()) {
2190 cf.set(displayFrames.mVoiceContent);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002191 df.set(displayFrames.mVoiceContent);
2192 } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2193 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002194 df.set(displayFrames.mDock);
2195 } else {
2196 cf.set(displayFrames.mContent);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002197 df.set(displayFrames.mContent);
2198 }
Jorim Jaggi4e04eb22020-01-09 16:42:14 +01002199 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
2200 && adjust != SOFT_INPUT_ADJUST_NOTHING) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002201 vf.set(displayFrames.mCurrent);
2202 } else {
2203 vf.set(cf);
2204 }
2205 }
2206 }
2207 }
2208
2209 final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2210 final boolean attachedInParent = attached != null && !layoutInScreen;
Tiger Huang4a7835f2019-11-06 00:07:56 +08002211 final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
2212 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
Jorim Jaggi0dd0cf92019-12-27 15:17:44 +01002213 || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
2214 && !win.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002215 final boolean requestedHideNavigation =
Tiger Huang4a7835f2019-11-06 00:07:56 +08002216 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
Jorim Jaggi0dd0cf92019-12-27 15:17:44 +01002217 || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
2218 && !win.getRequestedInsetsState().getSource(ITYPE_NAVIGATION_BAR)
2219 .isVisible());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002220
2221 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2222 // cropped / shifted to the displayFrame in WindowState.
2223 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2224 && type != TYPE_BASE_APPLICATION;
2225
2226 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2227 // the cutout safe zone.
shawnlind0e23be2019-12-29 18:56:15 +08002228 if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
2229 || cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002230 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2231 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2232 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2233 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2234 // At the top we have the status bar, so apps that are
2235 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2236 // already expect that there's an inset there and we don't need to exclude
2237 // the window from that area.
2238 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2239 }
2240 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2241 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2242 // Same for the navigation bar.
2243 switch (mNavigationBarPosition) {
2244 case NAV_BAR_BOTTOM:
2245 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2246 break;
2247 case NAV_BAR_RIGHT:
2248 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2249 break;
2250 case NAV_BAR_LEFT:
2251 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2252 break;
2253 }
2254 }
2255 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2256 // The IME can always extend under the bottom cutout if the navbar is there.
2257 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2258 }
2259 // Windows that are attached to a parent and laid out in said parent already avoid
2260 // the cutout according to that parent and don't need to be further constrained.
2261 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2262 // They will later be cropped or shifted using the displayFrame in WindowState,
2263 // which prevents overlap with the DisplayCutout.
2264 if (!attachedInParent && !floatingInScreenWindow) {
2265 sTmpRect.set(pf);
2266 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2267 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2268 }
2269 // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2270 // cutout.
2271 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2272 }
2273
2274 // Content should never appear in the cutout.
2275 cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2276
2277 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2278 // Also, we don't allow windows in multi-window mode to extend out of the screen.
2279 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
Evan Rosky4fb1e912019-03-06 13:54:43 -08002280 && !win.inMultiWindowMode()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002281 df.left = df.top = -10000;
2282 df.right = df.bottom = 10000;
2283 if (type != TYPE_WALLPAPER) {
Jorim Jaggif081f062019-10-24 16:24:54 +02002284 cf.left = cf.top = vf.left = vf.top = -10000;
2285 cf.right = cf.bottom = vf.right = vf.bottom = 10000;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002286 }
2287 }
2288
2289 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2290 + ": sim=#" + Integer.toHexString(sim)
2291 + " attach=" + attached + " type=" + type
2292 + String.format(" flags=0x%08x", fl)
2293 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
Tiger Huang7c610aa2018-10-27 00:01:01 +08002294 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2295 + " dcf=" + dcf.toShortString()
Jorim Jaggif081f062019-10-24 16:24:54 +02002296 + " sf=" + sf.toShortString());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002297
2298 if (!sTmpLastParentFrame.equals(pf)) {
2299 windowFrames.setContentChanged(true);
2300 }
2301
2302 win.computeFrameLw();
Tiger Huang4a7835f2019-11-06 00:07:56 +08002303 if (win.getControllableInsetProvider() != null) {
2304 win.getControllableInsetProvider().updateSourceFrame();
2305 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002306 // Dock windows carve out the bottom of the screen, so normal windows
2307 // can't appear underneath them.
2308 if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2309 && !win.getGivenInsetsPendingLw()) {
2310 offsetInputMethodWindowLw(win, displayFrames);
2311 }
2312 if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2313 && !win.getGivenInsetsPendingLw()) {
2314 offsetVoiceInputWindowLw(win, displayFrames);
2315 }
2316 }
2317
Jorim Jaggif081f062019-10-24 16:24:54 +02002318 private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect cf) {
2319 // The wallpaper has Real Ultimate Power
2320 df.set(displayFrames.mUnrestricted);
2321 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002322 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002323 }
2324
2325 private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
Winson Chung913690d2019-11-14 16:06:01 -08002326 final int rotation = displayFrames.mRotation;
2327 final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
2328 displayFrames.mDisplayHeight, rotation);
2329
Tiger Huang7c610aa2018-10-27 00:01:01 +08002330 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2331 top += win.getGivenContentInsetsLw().top;
2332 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
Winson Chung913690d2019-11-14 16:06:01 -08002333 if (navBarPosition == NAV_BAR_BOTTOM) {
2334 // Always account for the nav bar frame height on the bottom since in all navigation
2335 // modes we make room to show the dismiss-ime button, even if the IME does not report
2336 // insets (ie. when floating)
2337 final int uimode = mService.mPolicy.getUiMode();
2338 final int navFrameHeight = getNavigationBarFrameHeight(rotation, uimode);
2339 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom,
2340 displayFrames.mUnrestricted.bottom - navFrameHeight);
2341 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002342 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2343 top = win.getVisibleFrameLw().top;
2344 top += win.getGivenVisibleInsetsLw().top;
2345 displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2346 if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2347 + displayFrames.mDock.bottom + " mContentBottom="
2348 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2349 }
2350
2351 private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2352 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2353 top += win.getGivenContentInsetsLw().top;
2354 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2355 }
2356
Riddle Hsuccf09402019-08-13 00:33:06 +08002357 WindowState getTopFullscreenOpaqueWindow() {
2358 return mTopFullscreenOpaqueWindowState;
2359 }
2360
2361 boolean isTopLayoutFullscreen() {
2362 return mTopIsFullscreen;
2363 }
2364
Tiger Huang7c610aa2018-10-27 00:01:01 +08002365 /**
2366 * Called following layout of all windows before each window has policy applied.
2367 */
2368 public void beginPostLayoutPolicyLw() {
2369 mTopFullscreenOpaqueWindowState = null;
2370 mTopFullscreenOpaqueOrDimmingWindowState = null;
2371 mTopDockedOpaqueWindowState = null;
2372 mTopDockedOpaqueOrDimmingWindowState = null;
2373 mForceStatusBar = false;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002374 mForcingShowNavBar = false;
2375 mForcingShowNavBarLayer = -1;
2376
2377 mAllowLockscreenWhenOn = false;
2378 mShowingDream = false;
2379 mWindowSleepTokenNeeded = false;
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002380 mIsFreeformWindowOverlappingWithNavBar = false;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002381 }
2382
2383 /**
2384 * Called following layout of all window to apply policy to each window.
2385 *
2386 * @param win The window being positioned.
2387 * @param attrs The LayoutParams of the window.
2388 * @param attached For sub-windows, the window it is attached to. Otherwise null.
2389 */
2390 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2391 WindowState attached, WindowState imeTarget) {
2392 final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2393 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2394 mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2395 final int fl = PolicyControl.getWindowFlags(win, attrs);
2396 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2397 && attrs.type == TYPE_INPUT_METHOD) {
2398 mForcingShowNavBar = true;
2399 mForcingShowNavBarLayer = win.getSurfaceLayer();
2400 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002401
2402 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2403 && attrs.type < FIRST_SYSTEM_WINDOW;
2404 final int windowingMode = win.getWindowingMode();
2405 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2406 windowingMode == WINDOWING_MODE_FULLSCREEN
2407 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2408 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2409 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2410 mForceStatusBar = true;
2411 }
2412 if (attrs.type == TYPE_DREAM) {
2413 // If the lockscreen was showing when the dream started then wait
2414 // for the dream to draw before hiding the lockscreen.
2415 if (!mDreamingLockscreen
2416 || (win.isVisibleLw() && win.hasDrawnLw())) {
2417 mShowingDream = true;
2418 appWindow = true;
2419 }
2420 }
2421
2422 // For app windows that are not attached, we decide if all windows in the app they
2423 // represent should be hidden or if we should hide the lockscreen. For attached app
2424 // windows we defer the decision to the window it is attached to.
2425 if (appWindow && attached == null) {
2426 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2427 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2428 mTopFullscreenOpaqueWindowState = win;
2429 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2430 mTopFullscreenOpaqueOrDimmingWindowState = win;
2431 }
2432 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2433 mAllowLockscreenWhenOn = true;
2434 }
2435 }
2436 }
2437 }
2438
2439 // Voice interaction overrides both top fullscreen and top docked.
Jorim Jaggi50150152019-03-27 23:08:58 +01002440 if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002441 if (mTopFullscreenOpaqueWindowState == null) {
2442 mTopFullscreenOpaqueWindowState = win;
2443 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2444 mTopFullscreenOpaqueOrDimmingWindowState = win;
2445 }
2446 }
2447 if (mTopDockedOpaqueWindowState == null) {
2448 mTopDockedOpaqueWindowState = win;
2449 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2450 mTopDockedOpaqueOrDimmingWindowState = win;
2451 }
2452 }
2453 }
2454
2455 // Keep track of the window if it's dimming but not necessarily fullscreen.
2456 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2457 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2458 mTopFullscreenOpaqueOrDimmingWindowState = win;
2459 }
2460
2461 // We need to keep track of the top "fullscreen" opaque window for the docked stack
2462 // separately, because both the "real fullscreen" opaque window and the one for the docked
2463 // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2464 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2465 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2466 mTopDockedOpaqueWindowState = win;
2467 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2468 mTopDockedOpaqueOrDimmingWindowState = win;
2469 }
2470 }
2471
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002472 // Check if the freeform window overlaps with the navigation bar area.
2473 final WindowState navBarWin = hasNavigationBar() ? mNavigationBar : null;
2474 if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode()
2475 && isOverlappingWithNavBar(win, navBarWin)) {
2476 mIsFreeformWindowOverlappingWithNavBar = true;
2477 }
2478
Tiger Huang7c610aa2018-10-27 00:01:01 +08002479 // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2480 // docked stack.
2481 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2482 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2483 mTopDockedOpaqueOrDimmingWindowState = win;
2484 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002485 }
2486
2487 /**
2488 * Called following layout of all windows and after policy has been applied
2489 * to each window. If in this function you do
2490 * something that may have modified the animation state of another window,
2491 * be sure to return non-zero in order to perform another pass through layout.
2492 *
2493 * @return Return any bit set of
2494 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2495 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2496 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2497 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2498 */
2499 public int finishPostLayoutPolicyLw() {
2500 int changes = 0;
2501 boolean topIsFullscreen = false;
2502
2503 // If we are not currently showing a dream then remember the current
2504 // lockscreen state. We will use this to determine whether the dream
2505 // started while the lockscreen was showing and remember this state
2506 // while the dream is showing.
2507 if (!mShowingDream) {
2508 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2509 if (mDreamingSleepTokenNeeded) {
2510 mDreamingSleepTokenNeeded = false;
2511 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2512 }
2513 } else {
2514 if (!mDreamingSleepTokenNeeded) {
2515 mDreamingSleepTokenNeeded = true;
2516 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2517 }
2518 }
2519
2520 if (mStatusBar != null) {
2521 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002522 + " top=" + mTopFullscreenOpaqueWindowState);
wilsonshihe8321942019-10-18 18:39:46 +08002523 final boolean forceShowStatusBar = (mStatusBar.getAttrs().privateFlags
2524 & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
2525 final boolean notificationShadeForcesShowingNavigation =
2526 mNotificationShade != null
2527 && (mNotificationShade.getAttrs().privateFlags
Tiger Huang7c610aa2018-10-27 00:01:01 +08002528 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
wilsonshihe8321942019-10-18 18:39:46 +08002529
Tiger Huang7c610aa2018-10-27 00:01:01 +08002530 boolean topAppHidesStatusBar = topAppHidesStatusBar();
wilsonshihe8321942019-10-18 18:39:46 +08002531 if (mForceStatusBar || forceShowStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002532 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2533 if (mStatusBarController.setBarShowingLw(true)) {
2534 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2535 }
2536 // Maintain fullscreen layout until incoming animation is complete.
2537 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
wilsonshihe8321942019-10-18 18:39:46 +08002538 // Transient status bar is not allowed if notification shade is expecting the
2539 // navigation keys from the user.
2540 if (notificationShadeForcesShowingNavigation
Tiger Huang7c610aa2018-10-27 00:01:01 +08002541 && mStatusBarController.isTransientShowing()) {
2542 mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2543 mLastSystemUiFlags, mLastSystemUiFlags);
2544 }
2545 } else if (mTopFullscreenOpaqueWindowState != null) {
2546 topIsFullscreen = topAppHidesStatusBar;
2547 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2548 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2549 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
2550 // case though.
2551 if (mStatusBarController.isTransientShowing()) {
2552 if (mStatusBarController.setBarShowingLw(true)) {
2553 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2554 }
2555 } else if (topIsFullscreen
Tiger Huang7c610aa2018-10-27 00:01:01 +08002556 && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2557 if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2558 if (mStatusBarController.setBarShowingLw(false)) {
2559 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2560 } else {
2561 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2562 }
2563 } else {
2564 if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2565 if (mStatusBarController.setBarShowingLw(true)) {
2566 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2567 }
2568 topAppHidesStatusBar = false;
2569 }
2570 }
2571 mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2572 }
2573
2574 if (mTopIsFullscreen != topIsFullscreen) {
2575 if (!topIsFullscreen) {
2576 // Force another layout when status bar becomes fully shown.
2577 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2578 }
2579 mTopIsFullscreen = topIsFullscreen;
2580 }
2581
2582 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2583 // If the navigation bar has been hidden or shown, we need to do another
2584 // layout pass to update that window.
2585 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2586 }
2587
2588 if (mShowingDream != mLastShowingDream) {
2589 mLastShowingDream = mShowingDream;
2590 mService.notifyShowingDreamChanged();
2591 }
2592
2593 updateWindowSleepToken();
2594
2595 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2596 return changes;
2597 }
2598
2599 private void updateWindowSleepToken() {
2600 if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2601 mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2602 mHandler.post(mAcquireSleepTokenRunnable);
2603 } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2604 mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2605 mHandler.post(mReleaseSleepTokenRunnable);
2606 }
2607 mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2608 }
2609
2610 /**
2611 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2612 * window.
2613 */
2614 private boolean topAppHidesStatusBar() {
hyok.kim332ccfc2019-07-02 15:39:43 +09002615 if (mTopFullscreenOpaqueWindowState == null || mForceShowSystemBars) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002616 return false;
2617 }
2618 final int fl = PolicyControl.getWindowFlags(null,
2619 mTopFullscreenOpaqueWindowState.getAttrs());
Adam Pardyl8c2d19c2019-09-16 17:15:38 +02002620 if (WindowManagerDebugConfig.DEBUG) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002621 Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2622 Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2623 + " lp.flags=0x" + Integer.toHexString(fl));
2624 }
2625 return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2626 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2627 }
2628
2629 /**
Winson Chungda20fec2019-04-10 12:19:59 -07002630 * Called when the user is switched.
2631 */
2632 public void switchUser() {
2633 updateCurrentUserResources();
2634 }
2635
2636 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002637 * Called when the resource overlays change.
2638 */
2639 public void onOverlayChangedLw() {
Winson Chungda20fec2019-04-10 12:19:59 -07002640 updateCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002641 onConfigurationChanged();
Jeff Changb0a061e2019-03-11 11:39:54 +08002642 mSystemGestures.onConfigurationChanged();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002643 }
2644
2645 /**
2646 * Called when the configuration has changed, and it's safe to load new values from resources.
2647 */
2648 public void onConfigurationChanged() {
2649 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2650
Winson Chungda20fec2019-04-10 12:19:59 -07002651 final Resources res = getCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002652 final int portraitRotation = displayRotation.getPortraitRotation();
2653 final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2654 final int landscapeRotation = displayRotation.getLandscapeRotation();
2655 final int seascapeRotation = displayRotation.getSeascapeRotation();
Matthew Nga7f24bc2019-04-09 17:06:41 -07002656 final int uiMode = mService.mPolicy.getUiMode();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002657
Louis Changfc64c832018-12-04 11:38:26 +08002658 if (hasStatusBar()) {
2659 mStatusBarHeightForRotation[portraitRotation] =
2660 mStatusBarHeightForRotation[upsideDownRotation] =
2661 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2662 mStatusBarHeightForRotation[landscapeRotation] =
2663 mStatusBarHeightForRotation[seascapeRotation] =
2664 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2665 } else {
2666 mStatusBarHeightForRotation[portraitRotation] =
2667 mStatusBarHeightForRotation[upsideDownRotation] =
2668 mStatusBarHeightForRotation[landscapeRotation] =
2669 mStatusBarHeightForRotation[seascapeRotation] = 0;
2670 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002671
2672 // Height of the navigation bar when presented horizontally at bottom
2673 mNavigationBarHeightForRotationDefault[portraitRotation] =
2674 mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2675 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2676 mNavigationBarHeightForRotationDefault[landscapeRotation] =
2677 mNavigationBarHeightForRotationDefault[seascapeRotation] =
2678 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2679
Matthew Nga7f24bc2019-04-09 17:06:41 -07002680 // Height of the navigation bar frame when presented horizontally at bottom
2681 mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2682 mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2683 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2684 mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2685 mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2686 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2687
Tiger Huang7c610aa2018-10-27 00:01:01 +08002688 // Width of the navigation bar when presented vertically along one side
2689 mNavigationBarWidthForRotationDefault[portraitRotation] =
2690 mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2691 mNavigationBarWidthForRotationDefault[landscapeRotation] =
2692 mNavigationBarWidthForRotationDefault[seascapeRotation] =
2693 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2694
2695 if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2696 // Height of the navigation bar when presented horizontally at bottom
2697 mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2698 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2699 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2700 mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2701 mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2702 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2703
2704 // Width of the navigation bar when presented vertically along one side
2705 mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2706 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2707 mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2708 mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2709 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2710 }
2711
Winson Chung4723b4e2019-03-25 16:49:36 -07002712 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002713 mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
2714 mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
Winson Chung36941632019-04-19 15:21:38 -07002715 mNavigationBarAlwaysShowOnSideGesture =
2716 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
Winson Chung4723b4e2019-03-25 16:49:36 -07002717
Matthew Nga7f24bc2019-04-09 17:06:41 -07002718 // This should calculate how much above the frame we accept gestures.
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002719 mBottomGestureAdditionalInset =
Matthew Nga7f24bc2019-04-09 17:06:41 -07002720 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002721 - getNavigationBarFrameHeight(portraitRotation, uiMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002722
Winson Chung4723b4e2019-03-25 16:49:36 -07002723 updateConfigurationAndScreenSizeDependentBehaviors();
2724 }
2725
2726 void updateConfigurationAndScreenSizeDependentBehaviors() {
Winson Chungda20fec2019-04-10 12:19:59 -07002727 final Resources res = getCurrentUserResources();
Winson Chung4723b4e2019-03-25 16:49:36 -07002728 mNavigationBarCanMove =
2729 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2730 && res.getBoolean(R.bool.config_navBarCanMove);
Riddle Hsuccf09402019-08-13 00:33:06 +08002731 mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002732 }
2733
Winson Chungda20fec2019-04-10 12:19:59 -07002734 /**
2735 * Updates the current user's resources to pick up any changes for the current user (including
2736 * overlay paths)
2737 */
2738 private void updateCurrentUserResources() {
2739 final int userId = mService.mAmInternal.getCurrentUserId();
2740 final Context uiContext = getSystemUiContext();
Winson Chung203e1522019-05-02 15:42:22 -07002741
2742 if (userId == UserHandle.USER_SYSTEM) {
2743 // Skip the (expensive) recreation of resources for the system user below and just
2744 // use the resources from the system ui context
2745 mCurrentUserResources = uiContext.getResources();
2746 return;
2747 }
2748
2749 // For non-system users, ensure that the resources are loaded from the current
2750 // user's package info (see ContextImpl.createDisplayContext)
Winson Chungda20fec2019-04-10 12:19:59 -07002751 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2752 uiContext.getPackageName(), null, 0, userId);
Winson Chungda20fec2019-04-10 12:19:59 -07002753 mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2754 pi.getResDir(),
2755 null /* splitResDirs */,
2756 pi.getOverlayDirs(),
2757 pi.getApplicationInfo().sharedLibraryFiles,
2758 mDisplayContent.getDisplayId(),
2759 null /* overrideConfig */,
2760 uiContext.getResources().getCompatibilityInfo(),
2761 null /* classLoader */);
2762 }
2763
Tiger Huang7c610aa2018-10-27 00:01:01 +08002764 @VisibleForTesting
Winson Chungda20fec2019-04-10 12:19:59 -07002765 Resources getCurrentUserResources() {
2766 if (mCurrentUserResources == null) {
2767 updateCurrentUserResources();
2768 }
2769 return mCurrentUserResources;
2770 }
2771
2772 @VisibleForTesting
2773 Context getContext() {
2774 return mContext;
2775 }
2776
Charles Chen173ae782019-11-11 20:39:02 +08002777 Context getSystemUiContext() {
2778 return mUiContext;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002779 }
2780
2781 private int getNavigationBarWidth(int rotation, int uiMode) {
2782 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2783 return mNavigationBarWidthForRotationInCarMode[rotation];
2784 } else {
2785 return mNavigationBarWidthForRotationDefault[rotation];
2786 }
2787 }
2788
Charles Chen3dedec32019-01-24 22:19:37 +08002789 void notifyDisplayReady() {
wilsonshih643bf132019-02-27 12:49:19 +08002790 mHandler.post(() -> {
2791 final int displayId = getDisplayId();
2792 getStatusBarManagerInternal().onDisplayReady(displayId);
Felipe Leme34a861a2019-08-05 16:00:12 -07002793 final WallpaperManagerInternal wpMgr = LocalServices
2794 .getService(WallpaperManagerInternal.class);
2795 if (wpMgr != null) {
2796 wpMgr.onDisplayReady(displayId);
2797 }
wilsonshih643bf132019-02-27 12:49:19 +08002798 });
Charles Chen3dedec32019-01-24 22:19:37 +08002799 }
2800
Tiger Huang7c610aa2018-10-27 00:01:01 +08002801 /**
2802 * Return the display width available after excluding any screen
2803 * decorations that could never be removed in Honeycomb. That is, system bar or
2804 * button bar.
2805 */
2806 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2807 DisplayCutout displayCutout) {
2808 int width = fullWidth;
2809 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002810 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2811 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002812 width -= getNavigationBarWidth(rotation, uiMode);
2813 }
2814 }
2815 if (displayCutout != null) {
2816 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2817 }
2818 return width;
2819 }
2820
2821 private int getNavigationBarHeight(int rotation, int uiMode) {
2822 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2823 return mNavigationBarHeightForRotationInCarMode[rotation];
2824 } else {
2825 return mNavigationBarHeightForRotationDefault[rotation];
2826 }
2827 }
2828
2829 /**
Matthew Nga7f24bc2019-04-09 17:06:41 -07002830 * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2831 * is used for spacing to show additional buttons on the navigation bar (such as the ime
2832 * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2833 * height that we send to the app as content insets that can be smaller.
2834 * <p>
2835 * In car mode it will return the same height as {@link #getNavigationBarHeight}
2836 *
2837 * @param rotation specifies rotation to return dimension from
2838 * @param uiMode to determine if in car mode
2839 * @return navigation bar frame height
2840 */
2841 private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2842 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2843 return mNavigationBarHeightForRotationInCarMode[rotation];
2844 } else {
2845 return mNavigationBarFrameHeightForRotationDefault[rotation];
2846 }
2847 }
2848
2849 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002850 * Return the display height available after excluding any screen
2851 * decorations that could never be removed in Honeycomb. That is, system bar or
2852 * button bar.
2853 */
2854 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2855 DisplayCutout displayCutout) {
2856 int height = fullHeight;
2857 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002858 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2859 if (navBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002860 height -= getNavigationBarHeight(rotation, uiMode);
2861 }
2862 }
2863 if (displayCutout != null) {
2864 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2865 }
2866 return height;
2867 }
2868
2869 /**
2870 * Return the available screen width that we should report for the
2871 * configuration. This must be no larger than
2872 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2873 * than that to account for more transient decoration like a status bar.
2874 */
2875 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2876 DisplayCutout displayCutout) {
2877 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2878 }
2879
2880 /**
2881 * Return the available screen height that we should report for the
2882 * configuration. This must be no larger than
2883 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2884 * than that to account for more transient decoration like a status bar.
2885 */
2886 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2887 DisplayCutout displayCutout) {
2888 // There is a separate status bar at the top of the display. We don't count that as part
2889 // of the fixed decor, since it can hide; however, for purposes of configurations,
2890 // we do want to exclude it since applications can't generally use that part
2891 // of the screen.
2892 int statusBarHeight = mStatusBarHeightForRotation[rotation];
2893 if (displayCutout != null) {
2894 // If there is a cutout, it may already have accounted for some part of the status
2895 // bar height.
2896 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2897 }
2898 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2899 - statusBarHeight;
2900 }
2901
Tiger Huang43b8fc22019-04-26 11:49:29 +08002902 /**
2903 * Return corner radius in pixels that should be used on windows in order to cover the display.
2904 * The radius is only valid for built-in displays since the one who configures window corner
2905 * radius cannot know the corner radius of non-built-in display.
2906 */
2907 float getWindowCornerRadius() {
2908 return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN
2909 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2910 }
2911
Tiger Huang7c610aa2018-10-27 00:01:01 +08002912 boolean isShowingDreamLw() {
2913 return mShowingDream;
2914 }
2915
2916 /**
Riddle Hsu61987bc2019-04-03 13:08:47 +08002917 * Calculates the stable insets if we already have the non-decor insets.
2918 *
2919 * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2920 * @param rotation The current display rotation.
2921 */
2922 void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2923 inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2924 }
2925
2926 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002927 * Calculates the stable insets without running a layout.
2928 *
2929 * @param displayRotation the current display rotation
2930 * @param displayWidth the current display width
2931 * @param displayHeight the current display height
2932 * @param displayCutout the current display cutout
2933 * @param outInsets the insets to return
2934 */
2935 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2936 DisplayCutout displayCutout, Rect outInsets) {
2937 outInsets.setEmpty();
2938
2939 // Navigation bar and status bar.
2940 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
Riddle Hsu61987bc2019-04-03 13:08:47 +08002941 convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002942 }
2943
2944 /**
2945 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2946 * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2947 *
2948 * @param displayRotation the current display rotation
2949 * @param displayWidth the current display width
2950 * @param displayHeight the current display height
2951 * @param displayCutout the current display cutout
2952 * @param outInsets the insets to return
2953 */
2954 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2955 DisplayCutout displayCutout, Rect outInsets) {
2956 outInsets.setEmpty();
2957
2958 // Only navigation bar
2959 if (hasNavigationBar()) {
2960 final int uiMode = mService.mPolicy.getUiMode();
2961 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2962 if (position == NAV_BAR_BOTTOM) {
2963 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2964 } else if (position == NAV_BAR_RIGHT) {
2965 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2966 } else if (position == NAV_BAR_LEFT) {
2967 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2968 }
2969 }
2970
2971 if (displayCutout != null) {
2972 outInsets.left += displayCutout.getSafeInsetLeft();
2973 outInsets.top += displayCutout.getSafeInsetTop();
2974 outInsets.right += displayCutout.getSafeInsetRight();
2975 outInsets.bottom += displayCutout.getSafeInsetBottom();
2976 }
2977 }
2978
Issei Suzukia5dbf522019-02-01 17:58:15 +01002979 /**
2980 * @see IWindowManager#setForwardedInsets
2981 */
2982 public void setForwardedInsets(@NonNull Insets forwardedInsets) {
2983 mForwardedInsets = forwardedInsets;
2984 }
2985
2986 @NonNull
2987 public Insets getForwardedInsets() {
2988 return mForwardedInsets;
2989 }
2990
Tiger Huang7c610aa2018-10-27 00:01:01 +08002991 @NavigationBarPosition
2992 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
2993 if (navigationBarCanMove() && displayWidth > displayHeight) {
2994 if (displayRotation == Surface.ROTATION_270) {
2995 return NAV_BAR_LEFT;
2996 } else if (displayRotation == Surface.ROTATION_90) {
2997 return NAV_BAR_RIGHT;
2998 }
2999 }
3000 return NAV_BAR_BOTTOM;
3001 }
3002
3003 /**
3004 * @return The side of the screen where navigation bar is positioned.
3005 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
3006 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
3007 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
3008 */
3009 @NavigationBarPosition
3010 public int getNavBarPosition() {
3011 return mNavigationBarPosition;
3012 }
3013
3014 /**
3015 * A new window has been focused.
3016 */
3017 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
3018 mFocusedWindow = newFocus;
3019 mLastFocusedWindow = lastFocus;
Issei Suzuki9f840c72018-12-07 15:09:30 -08003020 if (mDisplayContent.isDefaultDisplay) {
3021 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
3022 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003023 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
3024 // If the navigation bar has been hidden or shown, we need to do another
3025 // layout pass to update that window.
3026 return FINISH_LAYOUT_REDO_LAYOUT;
3027 }
3028 return 0;
3029 }
3030
3031 /**
3032 * Return true if it is okay to perform animations for an app transition
3033 * that is about to occur. You may return false for this if, for example,
3034 * the dream window is currently displayed so the switch should happen
3035 * immediately.
3036 */
3037 public boolean allowAppAnimationsLw() {
3038 return !mShowingDream;
3039 }
3040
3041 private void updateDreamingSleepToken(boolean acquire) {
3042 if (acquire) {
3043 final int displayId = getDisplayId();
3044 if (mDreamingSleepToken == null) {
3045 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
3046 "DreamOnDisplay" + displayId, displayId);
3047 }
3048 } else {
3049 if (mDreamingSleepToken != null) {
3050 mDreamingSleepToken.release();
3051 mDreamingSleepToken = null;
3052 }
3053 }
3054 }
3055
3056 private void requestTransientBars(WindowState swipeTarget) {
3057 synchronized (mLock) {
3058 if (!mService.mPolicy.isUserSetupComplete()) {
3059 // Swipe-up for navigation bar is disabled during setup
3060 return;
3061 }
Jorim Jaggi956ca412019-01-07 14:49:14 +01003062 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
3063 if (swipeTarget == mNavigationBar
Tiger Huang332793b2019-10-29 23:21:27 +08003064 && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
Jorim Jaggi956ca412019-01-07 14:49:14 +01003065 // Don't show status bar when swiping on already visible navigation bar
Tiger Huang7c610aa2018-10-27 00:01:01 +08003066 return;
3067 }
Jorim Jaggi956ca412019-01-07 14:49:14 +01003068 final InsetsControlTarget controlTarget =
3069 swipeTarget.getControllableInsetProvider().getControlTarget();
3070 if (controlTarget == null) {
3071 return;
3072 }
3073 if (controlTarget.canShowTransient()) {
3074 mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
Tiger Huang332793b2019-10-29 23:21:27 +08003075 new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
Jorim Jaggi956ca412019-01-07 14:49:14 +01003076 } else {
Tiger Huang4a7835f2019-11-06 00:07:56 +08003077 controlTarget.showInsets(Type.systemBars(), false);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003078 }
3079 } else {
3080 boolean sb = mStatusBarController.checkShowTransientBarLw();
3081 boolean nb = mNavigationBarController.checkShowTransientBarLw()
3082 && !isNavBarEmpty(mLastSystemUiFlags);
3083 if (sb || nb) {
3084 // Don't show status bar when swiping on already visible navigation bar
3085 if (!nb && swipeTarget == mNavigationBar) {
3086 if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
3087 return;
3088 }
3089 if (sb) mStatusBarController.showTransient();
3090 if (nb) mNavigationBarController.showTransient();
3091 updateSystemUiVisibilityLw();
3092 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003093 mImmersiveModeConfirmation.confirmCurrentPrompt();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003094 }
3095 }
3096 }
3097
3098 private void disposeInputConsumer(InputConsumer inputConsumer) {
3099 if (inputConsumer != null) {
3100 inputConsumer.dismiss();
3101 }
3102 }
3103
wilsonshihe8321942019-10-18 18:39:46 +08003104 boolean isKeyguardShowing() {
3105 return mService.mPolicy.isKeyguardShowing();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003106 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003107 private boolean isKeyguardOccluded() {
3108 // TODO (b/113840485): Handle per display keyguard.
3109 return mService.mPolicy.isKeyguardOccluded();
3110 }
3111
Jorim Jaggi956ca412019-01-07 14:49:14 +01003112 InsetsPolicy getInsetsPolicy() {
3113 return mDisplayContent.getInsetsPolicy();
3114 }
3115
Tiger Huang7c610aa2018-10-27 00:01:01 +08003116 void resetSystemUiVisibilityLw() {
3117 mLastSystemUiFlags = 0;
3118 updateSystemUiVisibilityLw();
3119 }
3120
3121 private int updateSystemUiVisibilityLw() {
3122 // If there is no window focused, there will be nobody to handle the events
3123 // anyway, so just hang on in whatever state we're in until things settle down.
3124 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
3125 : mTopFullscreenOpaqueWindowState;
3126 if (winCandidate == null) {
3127 return 0;
3128 }
3129
3130 // The immersive mode confirmation should never affect the system bar visibility, otherwise
3131 // it will unhide the navigation bar and hide itself.
3132 if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
3133
3134 // The immersive mode confirmation took the focus from mLastFocusedWindow which was
3135 // controlling the system ui visibility. So if mLastFocusedWindow can still receive
3136 // keys, we let it keep controlling the visibility.
3137 final boolean lastFocusCanReceiveKeys =
3138 (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
wilsonshihe8321942019-10-18 18:39:46 +08003139 winCandidate = isKeyguardShowing() ? mNotificationShade
Tiger Huang7c610aa2018-10-27 00:01:01 +08003140 : lastFocusCanReceiveKeys ? mLastFocusedWindow
3141 : mTopFullscreenOpaqueWindowState;
3142 if (winCandidate == null) {
3143 return 0;
3144 }
3145 }
3146 final WindowState win = winCandidate;
wilsonshihe8321942019-10-18 18:39:46 +08003147 if (win.getAttrs().type == TYPE_NOTIFICATION_SHADE && isKeyguardShowing()
3148 && isKeyguardOccluded()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003149 // We are updating at a point where the keyguard has gotten
3150 // focus, but we were last in a state where the top window is
3151 // hiding it. This is probably because the keyguard as been
3152 // shown while the top window was displayed, so we want to ignore
3153 // it here because this is just a very transient change and it
3154 // will quickly lose focus once it correctly gets hidden.
3155 return 0;
3156 }
3157
Jorim Jaggi28620472019-01-02 23:21:49 +01003158 mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
Jorim Jaggib6030952018-10-23 18:31:52 +02003159
Tiger Huang7c610aa2018-10-27 00:01:01 +08003160 int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
3161 & ~mResettingSystemUiFlags
3162 & ~mForceClearedSystemUiFlags;
3163 if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
3164 tmpVisibility
3165 &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
3166 }
3167
Jorim Jaggi956ca412019-01-07 14:49:14 +01003168 final int fullscreenAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
3169 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
3170 final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
3171 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003172 mService.getStackBounds(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003173 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003174 final boolean inSplitScreen = !mDockedStackBounds.isEmpty();
3175 mService.getStackBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
3176 : WINDOWING_MODE_FULLSCREEN,
Tiger Huangd5f0b9a2019-10-10 10:34:57 +02003177 ACTIVITY_TYPE_UNDEFINED, mNonDockedStackBounds);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003178 final Pair<Integer, Boolean> result =
3179 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
3180 final int visibility = result.first;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003181 final int appearance = win.mAttrs.insetsFlags.appearance
3182 | InsetsFlags.getAppearance(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003183 final int diff = visibility ^ mLastSystemUiFlags;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003184 final InsetsPolicy insetsPolicy = getInsetsPolicy();
3185 final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
3186 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) != 0
3187 || (PolicyControl.getWindowFlags(win, win.mAttrs) & FLAG_FULLSCREEN) != 0
Tiger Huang332793b2019-10-29 23:21:27 +08003188 || (mStatusBar != null && insetsPolicy.isHidden(ITYPE_STATUS_BAR))
Jorim Jaggi956ca412019-01-07 14:49:14 +01003189 || (mNavigationBar != null && insetsPolicy.isHidden(
Tiger Huang332793b2019-10-29 23:21:27 +08003190 ITYPE_NAVIGATION_BAR));
Jorim Jaggi956ca412019-01-07 14:49:14 +01003191 final int behavior = win.mAttrs.insetsFlags.behavior;
3192 final boolean isImmersive = (visibility & (View.SYSTEM_UI_FLAG_IMMERSIVE
3193 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)) != 0
3194 || behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
3195 || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003196 if (diff == 0
Jorim Jaggi956ca412019-01-07 14:49:14 +01003197 && mLastAppearance == appearance
3198 && mLastFullscreenAppearance == fullscreenAppearance
3199 && mLastDockedAppearance == dockedAppearance
Tiger Huang4a7835f2019-11-06 00:07:56 +08003200 && mLastBehavior == behavior
Jorim Jaggi956ca412019-01-07 14:49:14 +01003201 && mLastFocusIsFullscreen == isFullscreen
3202 && mLastFocusIsImmersive == isImmersive
Tiger Huang7c610aa2018-10-27 00:01:01 +08003203 && mFocusedApp == win.getAppToken()
3204 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
3205 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
3206 return 0;
3207 }
Tiger Huang0dbd5372019-10-26 00:24:22 +08003208
3209 // Obtains which types should show transient and which types should abort transient.
3210 // If there is no transient state change, this pair will contain two empty arrays.
3211 final Pair<int[], int[]> transientState = getTransientState(visibility, mLastSystemUiFlags);
3212
Tiger Huang7c610aa2018-10-27 00:01:01 +08003213 mLastSystemUiFlags = visibility;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003214 mLastAppearance = appearance;
3215 mLastFullscreenAppearance = fullscreenAppearance;
3216 mLastDockedAppearance = dockedAppearance;
Tiger Huang4a7835f2019-11-06 00:07:56 +08003217 mLastBehavior = behavior;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003218 mLastFocusIsFullscreen = isFullscreen;
3219 mLastFocusIsImmersive = isImmersive;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003220 mFocusedApp = win.getAppToken();
Riddle Hsu4d6a63f2019-03-29 19:14:43 +08003221 mLastNonDockedStackBounds.set(mNonDockedStackBounds);
3222 mLastDockedStackBounds.set(mDockedStackBounds);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003223 final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
3224 final Rect dockedStackBounds = new Rect(mDockedStackBounds);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003225 final AppearanceRegion[] appearanceRegions = inSplitScreen
3226 ? new AppearanceRegion[]{
3227 new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds),
3228 new AppearanceRegion(dockedAppearance, dockedStackBounds)}
3229 : new AppearanceRegion[]{
3230 new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds)};
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003231 final boolean isNavbarColorManagedByIme = result.second;
Vishnu Nair015d8cd2019-11-18 15:56:30 -08003232 String cause = win.toString();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003233 mHandler.post(() -> {
3234 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
3235 if (statusBar != null) {
3236 final int displayId = getDisplayId();
Tiger Huang0dbd5372019-10-26 00:24:22 +08003237 statusBar.setDisableFlags(displayId, visibility & StatusBarManager.DISABLE_MASK,
Vishnu Nair015d8cd2019-11-18 15:56:30 -08003238 cause);
Tiger Huang0dbd5372019-10-26 00:24:22 +08003239 if (transientState.first.length > 0) {
3240 statusBar.showTransient(displayId, transientState.first);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003241 }
Tiger Huang0dbd5372019-10-26 00:24:22 +08003242 if (transientState.second.length > 0) {
3243 statusBar.abortTransient(displayId, transientState.second);
3244 }
3245 statusBar.onSystemBarAppearanceChanged(displayId, appearance,
3246 appearanceRegions, isNavbarColorManagedByIme);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003247 statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive);
3248
3249 // TODO(b/118118435): Remove this after removing system UI visibilities.
Vishnu Nair015d8cd2019-11-18 15:56:30 -08003250 synchronized (mLock) {
3251 mDisplayContent.statusBarVisibilityChanged(
3252 visibility & ~(View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE));
3253 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003254 }
3255 });
3256 return diff;
3257 }
3258
Tiger Huang0dbd5372019-10-26 00:24:22 +08003259 private static Pair<int[], int[]> getTransientState(int vis, int oldVis) {
3260 final IntArray typesToShow = new IntArray(0);
3261 final IntArray typesToAbort = new IntArray(0);
Tiger Huang332793b2019-10-29 23:21:27 +08003262 updateTransientState(vis, oldVis, View.STATUS_BAR_TRANSIENT, ITYPE_STATUS_BAR, typesToShow,
Tiger Huang0dbd5372019-10-26 00:24:22 +08003263 typesToAbort);
3264 updateTransientState(vis, oldVis, View.NAVIGATION_BAR_TRANSIENT,
Tiger Huang332793b2019-10-29 23:21:27 +08003265 ITYPE_NAVIGATION_BAR, typesToShow, typesToAbort);
Tiger Huang0dbd5372019-10-26 00:24:22 +08003266 return Pair.create(typesToShow.toArray(), typesToAbort.toArray());
Tiger Huang7c610aa2018-10-27 00:01:01 +08003267 }
3268
Tiger Huang0dbd5372019-10-26 00:24:22 +08003269 private static void updateTransientState(int vis, int oldVis, int transientFlag,
Tiger Huang332793b2019-10-29 23:21:27 +08003270 @InternalInsetsType int type, IntArray typesToShow, IntArray typesToAbort) {
Tiger Huang0dbd5372019-10-26 00:24:22 +08003271 final boolean wasTransient = (oldVis & transientFlag) != 0;
3272 final boolean isTransient = (vis & transientFlag) != 0;
3273 if (!wasTransient && isTransient) {
3274 typesToShow.add(type);
3275 } else if (wasTransient && !isTransient) {
3276 typesToAbort.add(type);
3277 }
3278 }
3279
3280 private int updateLightStatusBarAppearanceLw(@Appearance int appearance, WindowState opaque,
Jorim Jaggi956ca412019-01-07 14:49:14 +01003281 WindowState opaqueOrDimming) {
wilsonshihe8321942019-10-18 18:39:46 +08003282 final boolean onKeyguard = isKeyguardShowing() && !isKeyguardOccluded();
3283 final WindowState statusColorWin = onKeyguard ? mNotificationShade : opaqueOrDimming;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003284 if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
3285 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
3286 // its light flag.
Tiger Huang332793b2019-10-29 23:21:27 +08003287 appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003288 final int legacyAppearance = InsetsFlags.getAppearance(
3289 PolicyControl.getSystemUiVisibility(statusColorWin, null));
3290 appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance)
Tiger Huang332793b2019-10-29 23:21:27 +08003291 & APPEARANCE_LIGHT_STATUS_BARS;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003292 } else if (statusColorWin != null && statusColorWin.isDimming()) {
3293 // Otherwise if it's dimming, clear the light flag.
Tiger Huang332793b2019-10-29 23:21:27 +08003294 appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003295 }
3296 return appearance;
3297 }
3298
Tiger Huang7c610aa2018-10-27 00:01:01 +08003299 @VisibleForTesting
3300 @Nullable
3301 static WindowState chooseNavigationColorWindowLw(WindowState opaque,
3302 WindowState opaqueOrDimming, WindowState imeWindow,
3303 @NavigationBarPosition int navBarPosition) {
3304 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
3305 // window can be navigation color window.
3306 final boolean imeWindowCanNavColorWindow = imeWindow != null
3307 && imeWindow.isVisibleLw()
3308 && navBarPosition == NAV_BAR_BOTTOM
3309 && (PolicyControl.getWindowFlags(imeWindow, null)
3310 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3311
3312 if (opaque != null && opaqueOrDimming == opaque) {
3313 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
3314 // unless IME window is also eligible, since currently the IME window is always show
3315 // above the opaque fullscreen app window, regardless of the IME target window.
3316 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
3317 return imeWindowCanNavColorWindow ? imeWindow : opaque;
3318 }
3319
3320 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
3321 // No dimming window is involved. Determine the result only with the IME window.
3322 return imeWindowCanNavColorWindow ? imeWindow : null;
3323 }
3324
3325 if (!imeWindowCanNavColorWindow) {
3326 // No IME window is involved. Determine the result only with opaqueOrDimming.
3327 return opaqueOrDimming;
3328 }
3329
3330 // The IME window and the dimming window are competing. Check if the dimming window can be
3331 // IME target or not.
3332 if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3333 // The IME window is above the dimming window.
3334 return imeWindow;
3335 } else {
3336 // The dimming window is above the IME window.
3337 return opaqueOrDimming;
3338 }
3339 }
3340
3341 @VisibleForTesting
3342 static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3343 WindowState imeWindow, WindowState navColorWin) {
3344
3345 if (navColorWin != null) {
3346 if (navColorWin == imeWindow || navColorWin == opaque) {
3347 // Respect the light flag.
3348 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3349 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3350 & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3351 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3352 // Clear the light flag for dimming window.
3353 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3354 }
3355 }
3356 return vis;
3357 }
3358
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003359 private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003360 final boolean dockedStackVisible =
3361 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3362 final boolean freeformStackVisible =
3363 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3364 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3365
3366 // We need to force system bars when the docked stack is visible, when the freeform stack
hyok.kim332ccfc2019-07-02 15:39:43 +09003367 // is focused but also when we are resizing for the transitions when docked stack
Tiger Huang7c610aa2018-10-27 00:01:01 +08003368 // visibility changes.
hyok.kim332ccfc2019-07-02 15:39:43 +09003369 mForceShowSystemBars = dockedStackVisible || win.inFreeformWindowingMode() || resizing
Brad Stenninge0573692019-03-11 13:52:46 -07003370 || mForceShowSystemBarsFromExternal;
wilsonshihe8321942019-10-18 18:39:46 +08003371 final boolean forceOpaqueStatusBar = mForceShowSystemBars && !isKeyguardShowing();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003372
3373 // apply translucent bar vis flags
wilsonshihe8321942019-10-18 18:39:46 +08003374 WindowState fullscreenTransWin = isKeyguardShowing() && !isKeyguardOccluded()
3375 ? mNotificationShade
Tiger Huang7c610aa2018-10-27 00:01:01 +08003376 : mTopFullscreenOpaqueWindowState;
3377 vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3378 vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
Adrian Roosfaba4062019-05-14 15:27:17 +02003379 int dockedVis = mStatusBarController.applyTranslucentFlagLw(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003380 mTopDockedOpaqueWindowState, 0, 0);
Adrian Roosfaba4062019-05-14 15:27:17 +02003381 dockedVis = mNavigationBarController.applyTranslucentFlagLw(
3382 mTopDockedOpaqueWindowState, dockedVis, 0);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003383
3384 final boolean fullscreenDrawsStatusBarBackground =
3385 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3386 final boolean dockedDrawsStatusBarBackground =
3387 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003388 final boolean fullscreenDrawsNavBarBackground =
3389 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
Adrian Roosfaba4062019-05-14 15:27:17 +02003390 final boolean dockedDrawsNavigationBarBackground =
3391 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003392
3393 // prevent status bar interaction from clearing certain flags
3394 int type = win.getAttrs().type;
wilsonshihe8321942019-10-18 18:39:46 +08003395 boolean notificationShadeHasFocus = type == TYPE_NOTIFICATION_SHADE;
3396 if (notificationShadeHasFocus && !isKeyguardShowing()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003397 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3398 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3399 | View.SYSTEM_UI_FLAG_IMMERSIVE
3400 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3401 | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3402 if (isKeyguardOccluded()) {
3403 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3404 }
3405 vis = (vis & ~flags) | (oldVis & flags);
3406 }
3407
3408 if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3409 vis |= View.STATUS_BAR_TRANSPARENT;
3410 vis &= ~View.STATUS_BAR_TRANSLUCENT;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003411 } else if (forceOpaqueStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003412 vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3413 }
3414
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003415 vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003416 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003417
3418 // update status bar
3419 boolean immersiveSticky =
3420 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3421 final boolean hideStatusBarWM =
3422 mTopFullscreenOpaqueWindowState != null
3423 && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3424 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3425 final boolean hideStatusBarSysui =
3426 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3427 final boolean hideNavBarSysui =
3428 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3429
3430 final boolean transientStatusBarAllowed = mStatusBar != null
wilsonshihe8321942019-10-18 18:39:46 +08003431 && (notificationShadeHasFocus || (!mForceShowSystemBars
Tiger Huang7c610aa2018-10-27 00:01:01 +08003432 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3433
3434 final boolean transientNavBarAllowed = mNavigationBar != null
3435 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3436
3437 final long now = SystemClock.uptimeMillis();
3438 final boolean pendingPanic = mPendingPanicGestureUptime != 0
3439 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3440 final DisplayPolicy defaultDisplayPolicy =
3441 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
wilsonshihe8321942019-10-18 18:39:46 +08003442 if (pendingPanic && hideNavBarSysui && !isKeyguardShowing()
Tiger Huang7c610aa2018-10-27 00:01:01 +08003443 // TODO (b/111955725): Show keyguard presentation on all external displays
3444 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3445 // The user performed the panic gesture recently, we're about to hide the bars,
3446 // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3447 mPendingPanicGestureUptime = 0;
3448 mStatusBarController.showTransient();
3449 if (!isNavBarEmpty(vis)) {
3450 mNavigationBarController.showTransient();
3451 }
3452 }
3453
3454 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3455 && !transientStatusBarAllowed && hideStatusBarSysui;
3456 final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3457 && !transientNavBarAllowed;
3458 if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3459 // clear the clearable flags instead
3460 clearClearableFlagsLw();
3461 vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3462 }
3463
3464 final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3465 immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3466 final boolean navAllowedHidden = immersive || immersiveSticky;
3467
3468 if (hideNavBarSysui && !navAllowedHidden
3469 && mService.mPolicy.getWindowLayerLw(win)
3470 > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3471 // We can't hide the navbar from this window otherwise the input consumer would not get
3472 // the input events.
3473 vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3474 }
3475
3476 vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3477
3478 // update navigation bar
3479 boolean oldImmersiveMode = isImmersiveMode(oldVis);
3480 boolean newImmersiveMode = isImmersiveMode(vis);
3481 if (oldImmersiveMode != newImmersiveMode) {
3482 final String pkg = win.getOwningPackage();
3483 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3484 mService.mPolicy.isUserSetupComplete(),
3485 isNavBarEmpty(win.getSystemUiVisibility()));
3486 }
3487
3488 vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3489
3490 final WindowState navColorWin = chooseNavigationColorWindowLw(
3491 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3492 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3493 vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3494 mTopFullscreenOpaqueOrDimmingWindowState,
3495 mDisplayContent.mInputMethodWindow, navColorWin);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003496 // Navbar color is controlled by the IME.
3497 final boolean isManagedByIme =
3498 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003499
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003500 return Pair.create(vis, isManagedByIme);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003501 }
3502
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003503 private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
3504 int translucentFlag) {
3505 if (!controller.isTransparentAllowed(win)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003506 return false;
3507 }
3508 if (win == null) {
3509 return true;
3510 }
3511
3512 final boolean drawsSystemBars =
3513 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3514 final boolean forceDrawsSystemBars =
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003515 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003516
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003517 return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
3518 }
3519
3520 private boolean drawsStatusBarBackground(int vis, WindowState win) {
3521 return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
3522 }
3523
3524 private boolean drawsNavigationBarBackground(int vis, WindowState win) {
3525 return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003526 }
3527
3528 /**
3529 * @return the current visibility flags with the nav-bar opacity related flags toggled based
3530 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3531 */
3532 private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003533 boolean freeformStackVisible, boolean isDockedDividerResizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003534 boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
3535 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
3536 if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
3537 visibility = setNavBarTransparentFlag(visibility);
3538 } else if (dockedStackVisible) {
3539 visibility = setNavBarOpaqueFlag(visibility);
3540 }
3541 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003542 if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003543 if (mIsFreeformWindowOverlappingWithNavBar) {
3544 visibility = setNavBarTranslucentFlag(visibility);
3545 } else {
3546 visibility = setNavBarOpaqueFlag(visibility);
3547 }
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003548 } else if (fullscreenDrawsBackground) {
3549 visibility = setNavBarTransparentFlag(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003550 }
3551 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3552 if (isDockedDividerResizing) {
3553 visibility = setNavBarOpaqueFlag(visibility);
3554 } else if (freeformStackVisible) {
3555 visibility = setNavBarTranslucentFlag(visibility);
3556 } else {
3557 visibility = setNavBarOpaqueFlag(visibility);
3558 }
3559 }
3560
Tiger Huang7c610aa2018-10-27 00:01:01 +08003561 return visibility;
3562 }
3563
3564 private int setNavBarOpaqueFlag(int visibility) {
3565 return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3566 }
3567
3568 private int setNavBarTranslucentFlag(int visibility) {
3569 visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3570 return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3571 }
3572
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003573 private int setNavBarTransparentFlag(int visibility) {
3574 visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3575 return visibility | View.NAVIGATION_BAR_TRANSPARENT;
3576 }
3577
Tiger Huang7c610aa2018-10-27 00:01:01 +08003578 private void clearClearableFlagsLw() {
3579 int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3580 if (newVal != mResettingSystemUiFlags) {
3581 mResettingSystemUiFlags = newVal;
3582 mDisplayContent.reevaluateStatusBarVisibility();
3583 }
3584 }
3585
3586 private boolean isImmersiveMode(int vis) {
3587 final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3588 return mNavigationBar != null
3589 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3590 && (vis & flags) != 0
3591 && canHideNavigationBar();
3592 }
3593
3594 /**
3595 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3596 */
3597 private boolean canHideNavigationBar() {
3598 return hasNavigationBar();
3599 }
3600
3601 private static boolean isNavBarEmpty(int systemUiFlags) {
3602 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3603 | View.STATUS_BAR_DISABLE_BACK
3604 | View.STATUS_BAR_DISABLE_RECENT);
3605
3606 return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3607 }
3608
Tiger Huang7c610aa2018-10-27 00:01:01 +08003609 private final Runnable mHiddenNavPanic = new Runnable() {
3610 @Override
3611 public void run() {
3612 synchronized (mLock) {
3613 if (!mService.mPolicy.isUserSetupComplete()) {
3614 // Swipe-up for navigation bar is disabled during setup
3615 return;
3616 }
3617 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3618 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3619 mNavigationBarController.showTransient();
Jorim Jaggi956ca412019-01-07 14:49:14 +01003620 mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
Tiger Huang332793b2019-10-29 23:21:27 +08003621 new int[] {ITYPE_NAVIGATION_BAR}));
Tiger Huang7c610aa2018-10-27 00:01:01 +08003622 }
3623 }
3624 }
3625 };
3626
3627 void onPowerKeyDown(boolean isScreenOn) {
3628 // Detect user pressing the power button in panic when an application has
3629 // taken over the whole screen.
3630 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3631 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3632 isNavBarEmpty(mLastSystemUiFlags));
3633 if (panic) {
3634 mHandler.post(mHiddenNavPanic);
3635 }
3636 }
3637
3638 void onVrStateChangedLw(boolean enabled) {
3639 mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3640 }
3641
3642 /**
3643 * Called when the state of lock task mode changes. This should be used to disable immersive
3644 * mode confirmation.
3645 *
3646 * @param lockTaskState the new lock task mode state. One of
3647 * {@link ActivityManager#LOCK_TASK_MODE_NONE},
3648 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3649 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3650 */
3651 public void onLockTaskStateChangedLw(int lockTaskState) {
3652 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3653 }
3654
3655 /**
3656 * Request a screenshot be taken.
3657 *
3658 * @param screenshotType The type of screenshot, for example either
3659 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3660 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3661 */
3662 public void takeScreenshot(int screenshotType) {
3663 if (mScreenshotHelper != null) {
3664 mScreenshotHelper.takeScreenshot(screenshotType,
3665 mStatusBar != null && mStatusBar.isVisibleLw(),
James O'Learyfa5bb7a2019-09-05 13:43:29 -04003666 mNavigationBar != null && mNavigationBar.isVisibleLw(),
3667 mHandler, null /* completionConsumer */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003668 }
3669 }
3670
Ady Abrahamf3e05312019-05-13 18:04:59 -07003671 RefreshRatePolicy getRefreshRatePolicy() {
3672 return mRefreshRatePolicy;
3673 }
3674
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003675 void dump(String prefix, PrintWriter pw) {
Riddle Hsuccf09402019-08-13 00:33:06 +08003676 pw.print(prefix); pw.println("DisplayPolicy");
Tiger Huang7c610aa2018-10-27 00:01:01 +08003677 prefix += " ";
3678 pw.print(prefix);
3679 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3680 pw.print(" mDeskDockEnablesAccelerometer=");
3681 pw.println(mDeskDockEnablesAccelerometer);
3682 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3683 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3684 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3685 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3686 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3687 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3688 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3689 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3690 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3691 || mForceClearedSystemUiFlags != 0) {
3692 pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3693 pw.print(Integer.toHexString(mLastSystemUiFlags));
3694 pw.print(" mResettingSystemUiFlags=0x");
3695 pw.print(Integer.toHexString(mResettingSystemUiFlags));
3696 pw.print(" mForceClearedSystemUiFlags=0x");
3697 pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3698 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003699 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3700 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3701 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3702 if (mStatusBar != null) {
3703 pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003704 }
wilsonshihe8321942019-10-18 18:39:46 +08003705 if (mNotificationShade != null) {
3706 pw.print(prefix); pw.print("mExpandedPanel="); pw.print(mNotificationShade);
3707 }
3708 pw.print(" isKeyguardShowing="); pw.println(isKeyguardShowing());
Tiger Huang7c610aa2018-10-27 00:01:01 +08003709 if (mNavigationBar != null) {
3710 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
Winson Chung4723b4e2019-03-25 16:49:36 -07003711 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
3712 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
3713 pw.print(prefix); pw.print("mNavigationBarPosition=");
3714 pw.println(mNavigationBarPosition);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003715 }
3716 if (mFocusedWindow != null) {
3717 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3718 }
3719 if (mFocusedApp != null) {
3720 pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3721 }
3722 if (mTopFullscreenOpaqueWindowState != null) {
3723 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3724 pw.println(mTopFullscreenOpaqueWindowState);
3725 }
3726 if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3727 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3728 pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3729 }
3730 if (mForcingShowNavBar) {
3731 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3732 pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3733 pw.println(mForcingShowNavBarLayer);
3734 }
Riddle Hsuccf09402019-08-13 00:33:06 +08003735 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003736 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
Riddle Hsuccf09402019-08-13 00:33:06 +08003737 pw.print(prefix); pw.print("mForceShowSystemBarsFromExternal=");
3738 pw.print(mForceShowSystemBarsFromExternal);
3739 pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003740 mStatusBarController.dump(pw, prefix);
3741 mNavigationBarController.dump(pw, prefix);
3742
3743 pw.print(prefix); pw.println("Looper state:");
3744 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003745 }
Arthur Hung20479922019-02-27 17:13:22 +08003746
3747 private boolean supportsPointerLocation() {
3748 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
3749 }
3750
3751 void setPointerLocationEnabled(boolean pointerLocationEnabled) {
3752 if (!supportsPointerLocation()) {
3753 return;
3754 }
3755
3756 mHandler.sendEmptyMessage(pointerLocationEnabled
3757 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
3758 }
3759
3760 private void enablePointerLocation() {
3761 if (mPointerLocationView != null) {
3762 return;
3763 }
3764
3765 mPointerLocationView = new PointerLocationView(mContext);
3766 mPointerLocationView.setPrintCoords(false);
3767 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
3768 WindowManager.LayoutParams.MATCH_PARENT,
3769 WindowManager.LayoutParams.MATCH_PARENT);
3770 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3771 lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
3772 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3773 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3774 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3775 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3776 if (ActivityManager.isHighEndGfx()) {
3777 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3778 lp.privateFlags |=
3779 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3780 }
3781 lp.format = PixelFormat.TRANSLUCENT;
3782 lp.setTitle("PointerLocation - display " + getDisplayId());
3783 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3784 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3785 wm.addView(mPointerLocationView, lp);
3786 mDisplayContent.registerPointerEventListener(mPointerLocationView);
3787 }
3788
3789 private void disablePointerLocation() {
3790 if (mPointerLocationView == null) {
3791 return;
3792 }
3793
3794 mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3795 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3796 wm.removeView(mPointerLocationView);
3797 mPointerLocationView = null;
3798 }
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003799
Arthur Hungfbc8f412019-08-01 19:57:54 +08003800 /**
3801 * Check if the window could be excluded from checking if the display has content.
3802 *
3803 * @param w WindowState to check if should be excluded.
3804 * @return True if the window type is PointerLocation which is excluded.
3805 */
3806 boolean isWindowExcludedFromContent(WindowState w) {
3807 if (w != null && mPointerLocationView != null) {
3808 return w.mClient == mPointerLocationView.getWindowToken();
3809 }
3810
3811 return false;
3812 }
3813
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003814 @VisibleForTesting
3815 static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
3816 if (navBarWindow == null || !navBarWindow.isVisibleLw()
Garfield Tane8d84ab2019-10-11 09:49:40 -07003817 || targetWindow.mActivityRecord == null || !targetWindow.isVisibleLw()) {
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003818 return false;
3819 }
3820
3821 return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw());
3822 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003823}