blob: f9ad03f407237bfe0169a3ccabea8676e9ade7ca [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;
Arthur Hung20479922019-02-27 17:13:22 +080061import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
Jorim Jaggia6aabac2019-03-11 14:23:16 -070062import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
Tiger Huang7c610aa2018-10-27 00:01:01 +080063import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +080064import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
65import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
Tiger Huang4a7835f2019-11-06 00:07:56 +080066import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND;
Tiger Huang7c610aa2018-10-27 00:01:01 +080067import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +080068import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
69import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
70import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
71import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
72import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
73import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
74import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
75import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
76import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
Charles Chen64172bb2019-04-22 17:30:29 +080077import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
Tiger Huang7c610aa2018-10-27 00:01:01 +080078import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
79import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
80import 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;
292 private final int[] mStatusBarHeightForRotation = new int[4];
293 private WindowState mNavigationBar = null;
294 @NavigationBarPosition
295 private int mNavigationBarPosition = NAV_BAR_BOTTOM;
296 private int[] mNavigationBarHeightForRotationDefault = new int[4];
297 private int[] mNavigationBarWidthForRotationDefault = new int[4];
298 private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
299 private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
300
Matthew Nga7f24bc2019-04-09 17:06:41 -0700301 /** See {@link #getNavigationBarFrameHeight} */
302 private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
303
HEO SEUNG22d3ec22019-05-30 20:28:53 +0900304 private boolean mIsFreeformWindowOverlappingWithNavBar;
305
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800306 private final StatusBarController mStatusBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800307
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800308 private final BarController mNavigationBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800309
310 private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
311 new BarController.OnBarVisibilityChangedListener() {
312 @Override
313 public void onBarVisibilityChanged(boolean visible) {
314 if (mAccessibilityManager == null) {
315 return;
316 }
317 mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
318 }
319 };
320
Tiger Huang7c610aa2018-10-27 00:01:01 +0800321 @GuardedBy("mHandler")
322 private SleepToken mDreamingSleepToken;
323
324 @GuardedBy("mHandler")
325 private SleepToken mWindowSleepToken;
326
327 private final Runnable mAcquireSleepTokenRunnable;
328 private final Runnable mReleaseSleepTokenRunnable;
329
330 // The windows we were told about in focusChanged.
331 private WindowState mFocusedWindow;
332 private WindowState mLastFocusedWindow;
333
334 IApplicationToken mFocusedApp;
335
336 int mLastSystemUiFlags;
337 // Bits that we are in the process of clearing, so we want to prevent
338 // them from being set by applications until everything has been updated
339 // to have them clear.
340 private int mResettingSystemUiFlags = 0;
341 // Bits that we are currently always keeping cleared.
342 private int mForceClearedSystemUiFlags = 0;
Jorim Jaggi956ca412019-01-07 14:49:14 +0100343 private int mLastAppearance;
344 private int mLastFullscreenAppearance;
345 private int mLastDockedAppearance;
Tiger Huang4a7835f2019-11-06 00:07:56 +0800346 private int mLastBehavior;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800347 private final Rect mNonDockedStackBounds = new Rect();
348 private final Rect mDockedStackBounds = new Rect();
349 private final Rect mLastNonDockedStackBounds = new Rect();
350 private final Rect mLastDockedStackBounds = new Rect();
351
Jorim Jaggi956ca412019-01-07 14:49:14 +0100352 // What we last reported to system UI about whether the focused window is fullscreen/immersive.
353 private boolean mLastFocusIsFullscreen = false;
354 private boolean mLastFocusIsImmersive = false;
355
Tiger Huang7c610aa2018-10-27 00:01:01 +0800356 // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
357 private long mPendingPanicGestureUptime;
358
359 private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
360 private static final Rect sTmpRect = new Rect();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800361 private static final Rect sTmpNavFrame = new Rect();
362 private static final Rect sTmpLastParentFrame = new Rect();
Tiger Huang4a7835f2019-11-06 00:07:56 +0800363 private static final int[] sTmpTypesAndSides = new int[2];
Tiger Huang7c610aa2018-10-27 00:01:01 +0800364
365 private WindowState mTopFullscreenOpaqueWindowState;
366 private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
367 private WindowState mTopDockedOpaqueWindowState;
368 private WindowState mTopDockedOpaqueOrDimmingWindowState;
369 private boolean mTopIsFullscreen;
370 private boolean mForceStatusBar;
371 private boolean mForceStatusBarFromKeyguard;
372 private boolean mForceStatusBarTransparent;
373 private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
374 private boolean mForcingShowNavBar;
375 private int mForcingShowNavBarLayer;
376 private boolean mForceShowSystemBars;
377
Brad Stenninge0573692019-03-11 13:52:46 -0700378 /**
379 * Force the display of system bars regardless of other settings.
380 */
381 private boolean mForceShowSystemBarsFromExternal;
382
Tiger Huang7c610aa2018-10-27 00:01:01 +0800383 private boolean mShowingDream;
384 private boolean mLastShowingDream;
385 private boolean mDreamingLockscreen;
386 private boolean mDreamingSleepTokenNeeded;
387 private boolean mWindowSleepTokenNeeded;
388 private boolean mLastWindowSleepTokenNeeded;
389 private boolean mAllowLockscreenWhenOn;
390
391 private InputConsumer mInputConsumer = null;
392
Arthur Hung20479922019-02-27 17:13:22 +0800393 private PointerLocationView mPointerLocationView;
394
Issei Suzukia5dbf522019-02-01 17:58:15 +0100395 /**
396 * The area covered by system windows which belong to another display. Forwarded insets is set
397 * in case this is a virtual display, this is displayed on another display that has insets, and
398 * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
399 * displayed on the host display, and it covers a part of this virtual display.)
400 * The forwarded insets is used to compute display frames of this virtual display, which will
401 * be then used to layout windows in the virtual display.
402 */
403 @NonNull private Insets mForwardedInsets = Insets.NONE;
404
Ady Abrahamf3e05312019-05-13 18:04:59 -0700405 private RefreshRatePolicy mRefreshRatePolicy;
406
Tiger Huang7c610aa2018-10-27 00:01:01 +0800407 // -------- PolicyHandler --------
408 private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
409 private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
410 private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
Arthur Hung20479922019-02-27 17:13:22 +0800411 private static final int MSG_ENABLE_POINTER_LOCATION = 4;
412 private static final int MSG_DISABLE_POINTER_LOCATION = 5;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800413
414 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
415 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
416
417 private class PolicyHandler extends Handler {
418
419 PolicyHandler(Looper looper) {
420 super(looper);
421 }
422
423 @Override
424 public void handleMessage(Message msg) {
425 switch (msg.what) {
426 case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
427 updateDreamingSleepToken(msg.arg1 != 0);
428 break;
429 case MSG_REQUEST_TRANSIENT_BARS:
430 WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
431 ? mStatusBar : mNavigationBar;
432 if (targetBar != null) {
433 requestTransientBars(targetBar);
434 }
435 break;
436 case MSG_DISPOSE_INPUT_CONSUMER:
437 disposeInputConsumer((InputConsumer) msg.obj);
438 break;
Arthur Hung20479922019-02-27 17:13:22 +0800439 case MSG_ENABLE_POINTER_LOCATION:
440 enablePointerLocation();
441 break;
442 case MSG_DISABLE_POINTER_LOCATION:
443 disablePointerLocation();
444 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800445 }
446 }
447 }
448
449 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800450 mService = service;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800451 mContext = displayContent.isDefaultDisplay ? service.mContext
452 : service.mContext.createDisplayContext(displayContent.getDisplay());
Charles Chen173ae782019-11-11 20:39:02 +0800453 mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
454 : service.mAtmService.mSystemThread
455 .createSystemUiContext(displayContent.getDisplayId());
Tiger Huang7c610aa2018-10-27 00:01:01 +0800456 mDisplayContent = displayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800457 mLock = service.getWindowManagerLock();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800458
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800459 final int displayId = displayContent.getDisplayId();
460 mStatusBarController = new StatusBarController(displayId);
461 mNavigationBarController = new BarController("NavigationBar",
462 displayId,
463 View.NAVIGATION_BAR_TRANSIENT,
464 View.NAVIGATION_BAR_UNHIDE,
465 View.NAVIGATION_BAR_TRANSLUCENT,
466 StatusBarManager.WINDOW_NAVIGATION_BAR,
467 FLAG_TRANSLUCENT_NAVIGATION,
468 View.NAVIGATION_BAR_TRANSPARENT);
469
Tiger Huang7c610aa2018-10-27 00:01:01 +0800470 final Resources r = mContext.getResources();
471 mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
472 mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
Brad Stenninge0573692019-03-11 13:52:46 -0700473 mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800474
475 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
476 Context.ACCESSIBILITY_SERVICE);
477 if (!displayContent.isDefaultDisplay) {
478 mAwake = true;
479 mScreenOnEarly = true;
480 mScreenOnFully = true;
481 }
482
483 final Looper looper = UiThread.getHandler().getLooper();
484 mHandler = new PolicyHandler(looper);
485 mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
486 new SystemGesturesPointerEventListener.Callbacks() {
487 @Override
488 public void onSwipeFromTop() {
489 if (mStatusBar != null) {
490 requestTransientBars(mStatusBar);
491 }
492 }
493
494 @Override
495 public void onSwipeFromBottom() {
Winson Chung36941632019-04-19 15:21:38 -0700496 if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800497 requestTransientBars(mNavigationBar);
498 }
499 }
500
501 @Override
502 public void onSwipeFromRight() {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200503 final Region excludedRegion = Region.obtain();
Jeff Chang3cf3e562019-06-18 11:51:25 +0800504 synchronized (mLock) {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200505 mDisplayContent.calculateSystemGestureExclusion(
506 excludedRegion, null /* outUnrestricted */);
Jeff Chang3cf3e562019-06-18 11:51:25 +0800507 }
Winson Chung36941632019-04-19 15:21:38 -0700508 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
509 || mNavigationBarPosition == NAV_BAR_RIGHT;
510 if (mNavigationBar != null && sideAllowed
511 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800512 requestTransientBars(mNavigationBar);
513 }
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200514 excludedRegion.recycle();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800515 }
516
517 @Override
518 public void onSwipeFromLeft() {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200519 final Region excludedRegion = Region.obtain();
Jeff Chang3cf3e562019-06-18 11:51:25 +0800520 synchronized (mLock) {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200521 mDisplayContent.calculateSystemGestureExclusion(
522 excludedRegion, null /* outUnrestricted */);
Jeff Chang3cf3e562019-06-18 11:51:25 +0800523 }
Winson Chung36941632019-04-19 15:21:38 -0700524 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
525 || mNavigationBarPosition == NAV_BAR_LEFT;
526 if (mNavigationBar != null && sideAllowed
527 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800528 requestTransientBars(mNavigationBar);
529 }
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200530 excludedRegion.recycle();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800531 }
532
533 @Override
534 public void onFling(int duration) {
535 if (mService.mPowerManagerInternal != null) {
536 mService.mPowerManagerInternal.powerHint(
537 PowerHint.INTERACTION, duration);
538 }
539 }
540
541 @Override
542 public void onDebug() {
543 // no-op
544 }
545
546 private WindowOrientationListener getOrientationListener() {
547 final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
548 return rotation != null ? rotation.getOrientationListener() : null;
549 }
550
551 @Override
552 public void onDown() {
553 final WindowOrientationListener listener = getOrientationListener();
554 if (listener != null) {
555 listener.onTouchStart();
556 }
557 }
558
559 @Override
560 public void onUpOrCancel() {
561 final WindowOrientationListener listener = getOrientationListener();
562 if (listener != null) {
563 listener.onTouchEnd();
564 }
565 }
566
567 @Override
568 public void onMouseHoverAtTop() {
569 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
570 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
571 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
572 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
573 }
574
575 @Override
576 public void onMouseHoverAtBottom() {
577 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
578 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
579 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
580 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
581 }
582
583 @Override
584 public void onMouseLeaveFromEdge() {
585 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
586 }
587 });
588 displayContent.registerPointerEventListener(mSystemGestures);
589 displayContent.mAppTransition.registerListenerLocked(
590 mStatusBarController.getAppTransitionListener());
591 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
592 mService.mVrModeEnabled);
593 mAcquireSleepTokenRunnable = () -> {
594 if (mWindowSleepToken != null) {
595 return;
596 }
Tiger Huang7c610aa2018-10-27 00:01:01 +0800597 mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
598 "WindowSleepTokenOnDisplay" + displayId, displayId);
599 };
600 mReleaseSleepTokenRunnable = () -> {
601 if (mWindowSleepToken == null) {
602 return;
603 }
604 mWindowSleepToken.release();
605 mWindowSleepToken = null;
606 };
607
608 // TODO: Make it can take screenshot on external display
609 mScreenshotHelper = displayContent.isDefaultDisplay
610 ? new ScreenshotHelper(mContext) : null;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800611
Tiger Huang7c610aa2018-10-27 00:01:01 +0800612 if (mDisplayContent.isDefaultDisplay) {
Louis Changfc64c832018-12-04 11:38:26 +0800613 mHasStatusBar = true;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800614 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800615
Tiger Huang7c610aa2018-10-27 00:01:01 +0800616 // Allow a system property to override this. Used by the emulator.
617 // See also hasNavigationBar().
618 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
619 if ("1".equals(navBarOverride)) {
620 mHasNavigationBar = false;
621 } else if ("0".equals(navBarOverride)) {
622 mHasNavigationBar = true;
623 }
624 } else {
Louis Changfc64c832018-12-04 11:38:26 +0800625 mHasStatusBar = false;
Andrii Kuliandd989612019-02-21 12:13:28 -0800626 mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800627 }
Ady Abrahamf3e05312019-05-13 18:04:59 -0700628
629 mRefreshRatePolicy = new RefreshRatePolicy(mService,
630 mDisplayContent.getDisplayInfo(),
631 mService.mHighRefreshRateBlacklist);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800632 }
633
Charles Chen5bdd3e22018-12-18 17:51:56 +0800634 void systemReady() {
635 mSystemGestures.systemReady();
Arthur Hung20479922019-02-27 17:13:22 +0800636 if (mService.mPointerLocationEnabled) {
637 setPointerLocationEnabled(true);
638 }
Charles Chen5bdd3e22018-12-18 17:51:56 +0800639 }
640
641 private int getDisplayId() {
642 return mDisplayContent.getDisplayId();
643 }
644
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800645 public void setHdmiPlugged(boolean plugged) {
646 setHdmiPlugged(plugged, false /* force */);
647 }
648
649 public void setHdmiPlugged(boolean plugged, boolean force) {
650 if (force || mHdmiPlugged != plugged) {
651 mHdmiPlugged = plugged;
652 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
653 final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
654 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
655 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800656 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800657 }
658 }
659
660 boolean isHdmiPlugged() {
661 return mHdmiPlugged;
662 }
663
664 boolean isCarDockEnablesAccelerometer() {
665 return mCarDockEnablesAccelerometer;
666 }
667
668 boolean isDeskDockEnablesAccelerometer() {
669 return mDeskDockEnablesAccelerometer;
670 }
671
672 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
673 mPersistentVrModeEnabled = persistentVrModeEnabled;
674 }
675
676 public boolean isPersistentVrModeEnabled() {
677 return mPersistentVrModeEnabled;
678 }
679
680 public void setDockMode(int dockMode) {
681 mDockMode = dockMode;
682 }
683
684 public int getDockMode() {
685 return mDockMode;
686 }
687
Brad Stenninge0573692019-03-11 13:52:46 -0700688 /**
689 * @see WindowManagerService.setForceShowSystemBars
690 */
691 void setForceShowSystemBars(boolean forceShowSystemBars) {
692 mForceShowSystemBarsFromExternal = forceShowSystemBars;
693 }
694
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800695 public boolean hasNavigationBar() {
696 return mHasNavigationBar;
697 }
698
Louis Changfc64c832018-12-04 11:38:26 +0800699 public boolean hasStatusBar() {
700 return mHasStatusBar;
701 }
702
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200703 boolean hasSideGestures() {
704 return mHasNavigationBar && mSideGestureInset > 0;
705 }
706
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800707 public boolean navigationBarCanMove() {
708 return mNavigationBarCanMove;
709 }
710
711 public void setLidState(int lidState) {
712 mLidState = lidState;
713 }
714
715 public int getLidState() {
716 return mLidState;
717 }
718
719 public void setAwake(boolean awake) {
720 mAwake = awake;
721 }
722
723 public boolean isAwake() {
724 return mAwake;
725 }
726
727 public boolean isScreenOnEarly() {
728 return mScreenOnEarly;
729 }
730
731 public boolean isScreenOnFully() {
732 return mScreenOnFully;
733 }
734
735 public boolean isKeyguardDrawComplete() {
736 return mKeyguardDrawComplete;
737 }
738
739 public boolean isWindowManagerDrawComplete() {
740 return mWindowManagerDrawComplete;
741 }
742
743 public ScreenOnListener getScreenOnListener() {
744 return mScreenOnListener;
745 }
746
747 public void screenTurnedOn(ScreenOnListener screenOnListener) {
748 synchronized (mLock) {
749 mScreenOnEarly = true;
750 mScreenOnFully = false;
751 mKeyguardDrawComplete = false;
752 mWindowManagerDrawComplete = false;
753 mScreenOnListener = screenOnListener;
754 }
755 }
756
757 public void screenTurnedOff() {
758 synchronized (mLock) {
759 mScreenOnEarly = false;
760 mScreenOnFully = false;
761 mKeyguardDrawComplete = false;
762 mWindowManagerDrawComplete = false;
763 mScreenOnListener = null;
764 }
765 }
766
767 /** Return false if we are not awake yet or we have already informed of this event. */
768 public boolean finishKeyguardDrawn() {
769 synchronized (mLock) {
770 if (!mScreenOnEarly || mKeyguardDrawComplete) {
771 return false;
772 }
773
774 mKeyguardDrawComplete = true;
775 mWindowManagerDrawComplete = false;
776 }
777 return true;
778 }
779
780 /** Return false if screen is not turned on or we did already handle this case earlier. */
781 public boolean finishWindowsDrawn() {
782 synchronized (mLock) {
783 if (!mScreenOnEarly || mWindowManagerDrawComplete) {
784 return false;
785 }
786
787 mWindowManagerDrawComplete = true;
788 }
789 return true;
790 }
791
792 /** Return false if it is not ready to turn on. */
793 public boolean finishScreenTurningOn() {
794 synchronized (mLock) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200795 ProtoLog.d(WM_DEBUG_SCREEN_ON,
796 "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, "
797 + "mScreenOnFully=%b, mKeyguardDrawComplete=%b, "
798 + "mWindowManagerDrawComplete=%b",
799 mAwake, mScreenOnEarly, mScreenOnFully, mKeyguardDrawComplete,
800 mWindowManagerDrawComplete);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800801
802 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
803 || (mAwake && !mKeyguardDrawComplete)) {
804 return false;
805 }
806
Adrian Roosb125e0b2019-10-02 14:55:14 +0200807 ProtoLog.i(WM_DEBUG_SCREEN_ON, "Finished screen turning on...");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800808 mScreenOnListener = null;
809 mScreenOnFully = true;
810 }
811 return true;
812 }
813
Jorim Jaggi4981f152019-03-26 18:58:45 +0100814 private boolean hasStatusBarServicePermission(int pid, int uid) {
815 return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
816 == PackageManager.PERMISSION_GRANTED;
817 }
818
Tiger Huang7c610aa2018-10-27 00:01:01 +0800819 /**
820 * Sanitize the layout parameters coming from a client. Allows the policy
821 * to do things like ensure that windows of a specific type can't take
822 * input focus.
823 *
824 * @param attrs The window layout parameters to be modified. These values
825 * are modified in-place.
826 */
827 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
Jorim Jaggi4981f152019-03-26 18:58:45 +0100828 int callingPid, int callingUid) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800829
830 final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
831 if (mScreenDecorWindows.contains(win)) {
832 if (!isScreenDecor) {
833 // No longer has the flag set, so remove from the set.
834 mScreenDecorWindows.remove(win);
835 }
Jorim Jaggi4981f152019-03-26 18:58:45 +0100836 } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800837 mScreenDecorWindows.add(win);
838 }
839
840 switch (attrs.type) {
841 case TYPE_SYSTEM_OVERLAY:
842 case TYPE_SECURE_SYSTEM_OVERLAY:
843 // These types of windows can't receive input events.
844 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
845 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
846 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
847 break;
848 case TYPE_DREAM:
849 case TYPE_WALLPAPER:
850 // Dreams and wallpapers don't have an app window token and can thus not be
851 // letterboxed. Hence always let them extend under the cutout.
Arthur Hung20479922019-02-27 17:13:22 +0800852 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800853 break;
854 case TYPE_STATUS_BAR:
855
856 // If the Keyguard is in a hidden state (occluded by another window), we force to
857 // remove the wallpaper and keyguard flag so that any change in-flight after setting
858 // the keyguard as occluded wouldn't set these flags again.
859 // See {@link #processKeyguardSetHiddenResultLw}.
860 if (mService.mPolicy.isKeyguardOccluded()) {
861 attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
862 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
863 }
864 break;
865
866 case TYPE_SCREENSHOT:
867 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
868 break;
869
870 case TYPE_TOAST:
871 // While apps should use the dedicated toast APIs to add such windows
872 // it possible legacy apps to add the window directly. Therefore, we
873 // make windows added directly by the app behave as a toast as much
874 // as possible in terms of timeout and animation.
875 if (attrs.hideTimeoutMilliseconds < 0
876 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
877 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
878 }
Rhed Jao406d3a22018-11-30 19:28:58 +0800879 // Accessibility users may need longer timeout duration. This api compares
880 // original timeout with user's preference and return longer one. It returns
881 // original timeout if there's no preference.
882 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
883 (int) attrs.hideTimeoutMilliseconds,
884 AccessibilityManager.FLAG_CONTENT_TEXT);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800885 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
Jeff Changb10fac72019-04-09 17:28:30 +0800886 // Toast can show with below conditions when the screen is locked.
887 if (canToastShowWhenLocked(callingPid)) {
888 attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
889 }
Bernardo Rufino974de952019-10-22 11:53:42 +0100890 // Toasts can't be clickable
891 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800892 break;
893 }
894
895 if (attrs.type != TYPE_STATUS_BAR) {
896 // The status bar is the only window allowed to exhibit keyguard behavior.
897 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
898 }
899 }
900
901 /**
Jeff Changb10fac72019-04-09 17:28:30 +0800902 * @return {@code true} if the calling activity initiate toast and is visible with
903 * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
904 */
905 boolean canToastShowWhenLocked(int callingPid) {
906 return mDisplayContent.forAllWindows(w -> {
907 return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
908 }, true /* traverseTopToBottom */);
909 }
910
911 /**
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800912 * Check if a window can be added to the system.
Tiger Huang7c610aa2018-10-27 00:01:01 +0800913 *
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800914 * Currently enforces that two window types are singletons per display:
Tiger Huang7c610aa2018-10-27 00:01:01 +0800915 * <ul>
916 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
917 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
918 * </ul>
919 *
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800920 * @param attrs Information about the window to be added.
Tiger Huang7c610aa2018-10-27 00:01:01 +0800921 *
922 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
923 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
924 */
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800925 int validateAddingWindowLw(WindowManager.LayoutParams attrs) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800926 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
927 mContext.enforceCallingOrSelfPermission(
928 android.Manifest.permission.STATUS_BAR_SERVICE,
929 "DisplayPolicy");
Tiger Huang7c610aa2018-10-27 00:01:01 +0800930 }
931
932 switch (attrs.type) {
933 case TYPE_STATUS_BAR:
934 mContext.enforceCallingOrSelfPermission(
935 android.Manifest.permission.STATUS_BAR_SERVICE,
936 "DisplayPolicy");
937 if (mStatusBar != null) {
938 if (mStatusBar.isAlive()) {
939 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
940 }
941 }
Tiger Huang5f6cbca2019-07-18 19:00:01 +0800942 break;
943 case TYPE_NAVIGATION_BAR:
944 mContext.enforceCallingOrSelfPermission(
945 android.Manifest.permission.STATUS_BAR_SERVICE,
946 "DisplayPolicy");
947 if (mNavigationBar != null) {
948 if (mNavigationBar.isAlive()) {
949 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
950 }
951 }
952 break;
953 case TYPE_NAVIGATION_BAR_PANEL:
954 case TYPE_STATUS_BAR_PANEL:
955 case TYPE_STATUS_BAR_SUB_PANEL:
956 case TYPE_VOICE_INTERACTION_STARTING:
957 mContext.enforceCallingOrSelfPermission(
958 android.Manifest.permission.STATUS_BAR_SERVICE,
959 "DisplayPolicy");
960 break;
961 }
962 return ADD_OKAY;
963 }
964
965 /**
966 * Called when a window is being added to the system. Must not throw an exception.
967 *
968 * @param win The window being added.
969 * @param attrs Information about the window to be added.
970 */
971 void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
972 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
973 mScreenDecorWindows.add(win);
974 }
975
976 switch (attrs.type) {
977 case TYPE_STATUS_BAR:
Tiger Huang7c610aa2018-10-27 00:01:01 +0800978 mStatusBar = win;
979 mStatusBarController.setWindow(win);
980 if (mDisplayContent.isDefaultDisplay) {
981 mService.mPolicy.setKeyguardCandidateLw(win);
982 }
Adrian Roos11dfd272019-03-25 19:21:26 +0100983 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200984 (displayFrames, windowState, rect) -> {
985 rect.top = 0;
986 rect.bottom = getStatusBarHeight(displayFrames);
Adrian Roos11dfd272019-03-25 19:21:26 +0100987 };
Tiger Huang332793b2019-10-29 23:21:27 +0800988 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider);
989 mDisplayContent.setInsetProvider(ITYPE_TOP_GESTURES, win, frameProvider);
990 mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800991 break;
992 case TYPE_NAVIGATION_BAR:
Tiger Huang7c610aa2018-10-27 00:01:01 +0800993 mNavigationBar = win;
994 mNavigationBarController.setWindow(win);
995 mNavigationBarController.setOnBarVisibilityChangedListener(
996 mNavBarVisibilityListener, true);
Tiger Huang332793b2019-10-29 23:21:27 +0800997 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR,
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200998 win, null /* frameProvider */);
Tiger Huang332793b2019-10-29 23:21:27 +0800999 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001000 (displayFrames, windowState, inOutFrame) -> {
1001 inOutFrame.top -= mBottomGestureAdditionalInset;
1002 });
Tiger Huang332793b2019-10-29 23:21:27 +08001003 mDisplayContent.setInsetProvider(ITYPE_LEFT_GESTURES, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001004 (displayFrames, windowState, inOutFrame) -> {
1005 inOutFrame.left = 0;
1006 inOutFrame.top = 0;
1007 inOutFrame.bottom = displayFrames.mDisplayHeight;
1008 inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
1009 });
Tiger Huang332793b2019-10-29 23:21:27 +08001010 mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001011 (displayFrames, windowState, inOutFrame) -> {
1012 inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
1013 inOutFrame.top = 0;
1014 inOutFrame.bottom = displayFrames.mDisplayHeight;
1015 inOutFrame.right = displayFrames.mDisplayWidth;
1016 });
Tiger Huang332793b2019-10-29 23:21:27 +08001017 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_TAPPABLE_ELEMENT, win,
Adrian Roos11dfd272019-03-25 19:21:26 +01001018 (displayFrames, windowState, inOutFrame) -> {
1019 if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
1020 || mNavigationBarLetsThroughTaps) {
1021 inOutFrame.setEmpty();
1022 }
1023 });
Tiger Huang7c610aa2018-10-27 00:01:01 +08001024 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
1025 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001026 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001027 }
1028
1029 /**
1030 * Called when a window is being removed from a window manager. Must not
1031 * throw an exception -- clean up as much as possible.
1032 *
1033 * @param win The window being removed.
1034 */
Tiger Huang5f6cbca2019-07-18 19:00:01 +08001035 void removeWindowLw(WindowState win) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001036 if (mStatusBar == win) {
1037 mStatusBar = null;
1038 mStatusBarController.setWindow(null);
1039 if (mDisplayContent.isDefaultDisplay) {
1040 mService.mPolicy.setKeyguardCandidateLw(null);
1041 }
Tiger Huang332793b2019-10-29 23:21:27 +08001042 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001043 } else if (mNavigationBar == win) {
1044 mNavigationBar = null;
1045 mNavigationBarController.setWindow(null);
Tiger Huang332793b2019-10-29 23:21:27 +08001046 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001047 }
1048 if (mLastFocusedWindow == win) {
1049 mLastFocusedWindow = null;
1050 }
1051 mScreenDecorWindows.remove(win);
1052 }
1053
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001054 private int getStatusBarHeight(DisplayFrames displayFrames) {
1055 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1056 displayFrames.mDisplayCutoutSafe.top);
1057 }
1058
Jorim Jaggi28620472019-01-02 23:21:49 +01001059 WindowState getStatusBar() {
1060 return mStatusBar;
1061 }
1062
1063 WindowState getNavigationBar() {
1064 return mNavigationBar;
1065 }
1066
Tiger Huang7c610aa2018-10-27 00:01:01 +08001067 /**
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001068 * Control the animation to run when a window's state changes. Return a positive number to
1069 * force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the
1070 * style resource defining the animation, or {@link #ANIMATION_NONE} for no animation.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001071 *
1072 * @param win The window that is changing.
1073 * @param transit What is happening to the window:
1074 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1075 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1076 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1077 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1078 *
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001079 * @return Resource ID of the actual animation to use, or {@link #ANIMATION_NONE} for none.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001080 */
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001081 int selectAnimation(WindowState win, int transit) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001082 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1083 + ": transit=" + transit);
1084 if (win == mStatusBar) {
1085 final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
1086 final boolean expanded = win.getAttrs().height == MATCH_PARENT
1087 && win.getAttrs().width == MATCH_PARENT;
1088 if (isKeyguard || expanded) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001089 return ANIMATION_NONE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001090 }
1091 if (transit == TRANSIT_EXIT
1092 || transit == TRANSIT_HIDE) {
1093 return R.anim.dock_top_exit;
1094 } else if (transit == TRANSIT_ENTER
1095 || transit == TRANSIT_SHOW) {
1096 return R.anim.dock_top_enter;
1097 }
1098 } else if (win == mNavigationBar) {
1099 if (win.getAttrs().windowAnimations != 0) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001100 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001101 }
1102 // This can be on either the bottom or the right or the left.
1103 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1104 if (transit == TRANSIT_EXIT
1105 || transit == TRANSIT_HIDE) {
1106 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1107 return R.anim.dock_bottom_exit_keyguard;
1108 } else {
1109 return R.anim.dock_bottom_exit;
1110 }
1111 } else if (transit == TRANSIT_ENTER
1112 || transit == TRANSIT_SHOW) {
1113 return R.anim.dock_bottom_enter;
1114 }
1115 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1116 if (transit == TRANSIT_EXIT
1117 || transit == TRANSIT_HIDE) {
1118 return R.anim.dock_right_exit;
1119 } else if (transit == TRANSIT_ENTER
1120 || transit == TRANSIT_SHOW) {
1121 return R.anim.dock_right_enter;
1122 }
1123 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1124 if (transit == TRANSIT_EXIT
1125 || transit == TRANSIT_HIDE) {
1126 return R.anim.dock_left_exit;
1127 } else if (transit == TRANSIT_ENTER
1128 || transit == TRANSIT_SHOW) {
1129 return R.anim.dock_left_enter;
1130 }
1131 }
1132 } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001133 return selectDockedDividerAnimation(win, transit);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001134 }
1135
1136 if (transit == TRANSIT_PREVIEW_DONE) {
1137 if (win.hasAppShownWindows()) {
1138 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1139 return R.anim.app_starting_exit;
1140 }
1141 } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
1142 && transit == TRANSIT_ENTER) {
1143 // Special case: we are animating in a dream, while the keyguard
1144 // is shown. We don't want an animation on the dream, because
1145 // we need it shown immediately with the keyguard animating away
1146 // to reveal it.
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001147 return ANIMATION_NONE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001148 }
1149
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001150 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001151 }
1152
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001153 private int selectDockedDividerAnimation(WindowState win, int transit) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001154 int insets = mDisplayContent.getDockedDividerController().getContentInsets();
1155
1156 // If the divider is behind the navigation bar, don't animate.
1157 final Rect frame = win.getFrameLw();
1158 final boolean behindNavBar = mNavigationBar != null
1159 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
1160 && frame.top + insets >= mNavigationBar.getFrameLw().top)
1161 || (mNavigationBarPosition == NAV_BAR_RIGHT
1162 && frame.left + insets >= mNavigationBar.getFrameLw().left)
1163 || (mNavigationBarPosition == NAV_BAR_LEFT
1164 && frame.right - insets <= mNavigationBar.getFrameLw().right));
1165 final boolean landscape = frame.height() > frame.width();
1166 final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
1167 || frame.left + insets >= win.getDisplayFrameLw().right);
1168 final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
1169 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1170 final boolean offscreen = offscreenLandscape || offscreenPortrait;
1171 if (behindNavBar || offscreen) {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001172 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001173 }
1174 if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1175 return R.anim.fade_in;
1176 } else if (transit == TRANSIT_EXIT) {
1177 return R.anim.fade_out;
1178 } else {
Riddle Hsu2ca561b2019-10-08 21:58:58 +08001179 return ANIMATION_STYLEABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001180 }
1181 }
1182
1183 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08001184 * Called when a new system UI visibility is being reported, allowing
1185 * the policy to adjust what is actually reported.
1186 * @param visibility The raw visibility reported by the status bar.
1187 * @return The new desired visibility.
1188 */
1189 public int adjustSystemUiVisibilityLw(int visibility) {
1190 mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1191 mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1192
1193 // Reset any bits in mForceClearingStatusBarVisibility that
1194 // are now clear.
1195 mResettingSystemUiFlags &= visibility;
1196 // Clear any bits in the new visibility that are currently being
1197 // force cleared, before reporting it.
1198 return visibility & ~mResettingSystemUiFlags
1199 & ~mForceClearedSystemUiFlags;
1200 }
1201
1202 /**
Brad Stenninge0573692019-03-11 13:52:46 -07001203 * @return true if the system bars are forced to stay visible
Tiger Huang7c610aa2018-10-27 00:01:01 +08001204 */
Brad Stenninge0573692019-03-11 13:52:46 -07001205 public boolean areSystemBarsForcedShownLw(WindowState windowState) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001206 return mForceShowSystemBars;
1207 }
1208
1209 // TODO: Should probably be moved into DisplayFrames.
1210 /**
1211 * Return the layout hints for a newly added window. These values are computed on the
1212 * most recent layout, so they are not guaranteed to be correct.
1213 *
1214 * @param attrs The LayoutParams of the window.
1215 * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1216 * associated with the window.
1217 * @param displayFrames display frames.
1218 * @param floatingStack Whether the window's stack is floating.
1219 * @param outFrame The frame of the window.
1220 * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1221 * @param outStableInsets The areas covered by stable system windows irrespective of their
1222 * current visibility. Expressed as positive insets.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001223 * @param outDisplayCutout The area that has been cut away from the display.
Brad Stenninge0573692019-03-11 13:52:46 -07001224 * @return Whether to always consume the system bars.
1225 * See {@link #areSystemBarsForcedShownLw(WindowState)}.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001226 */
1227 public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1228 DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1229 Rect outContentInsets, Rect outStableInsets,
Jorim Jaggif081f062019-10-24 16:24:54 +02001230 DisplayCutout.ParcelableWrapper outDisplayCutout) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001231 final int fl = PolicyControl.getWindowFlags(null, attrs);
1232 final int pfl = attrs.privateFlags;
1233 final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1234 final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001235
1236 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1237 final boolean layoutInScreenAndInsetDecor = layoutInScreen
1238 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1239 final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1240
1241 if (layoutInScreenAndInsetDecor && !screenDecor) {
Tiger Huang4a7835f2019-11-06 00:07:56 +08001242 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
1243 || (attrs.getFitWindowInsetsTypes() & Type.navigationBars()) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001244 outFrame.set(displayFrames.mUnrestricted);
1245 } else {
1246 outFrame.set(displayFrames.mRestricted);
1247 }
1248
1249 final Rect sf;
1250 if (floatingStack) {
1251 sf = null;
1252 } else {
1253 sf = displayFrames.mStable;
1254 }
1255
1256 final Rect cf;
1257 if (floatingStack) {
1258 cf = null;
1259 } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1260 if ((fl & FLAG_FULLSCREEN) != 0) {
1261 cf = displayFrames.mStableFullscreen;
1262 } else {
1263 cf = displayFrames.mStable;
1264 }
Jorim Jaggif081f062019-10-24 16:24:54 +02001265 } else if ((fl & FLAG_FULLSCREEN) != 0) {
1266 cf = displayFrames.mUnrestricted;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001267 } else {
1268 cf = displayFrames.mCurrent;
1269 }
1270
1271 if (taskBounds != null) {
1272 outFrame.intersect(taskBounds);
1273 }
1274 InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1275 InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1276 outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1277 .getDisplayCutout());
1278 return mForceShowSystemBars;
1279 } else {
1280 if (layoutInScreen) {
1281 outFrame.set(displayFrames.mUnrestricted);
1282 } else {
1283 outFrame.set(displayFrames.mStable);
1284 }
1285 if (taskBounds != null) {
1286 outFrame.intersect(taskBounds);
1287 }
1288
1289 outContentInsets.setEmpty();
1290 outStableInsets.setEmpty();
1291 outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1292 return mForceShowSystemBars;
1293 }
1294 }
1295
Tiger Huang4a7835f2019-11-06 00:07:56 +08001296 private static void getImpliedTypesAndSidesToFit(LayoutParams attrs, int[] typesAndSides) {
1297 typesAndSides[0] = attrs.getFitWindowInsetsTypes();
1298 typesAndSides[1] = attrs.getFitWindowInsetsSides();
1299 final boolean forceDrawsBarBackgrounds =
1300 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1301 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
1302 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 || forceDrawsBarBackgrounds) {
1303 if ((attrs.privateFlags & PRIVATE_FLAG_ONLY_DRAW_BOTTOM_BAR_BACKGROUND) != 0) {
1304 typesAndSides[1] &= ~Side.BOTTOM;
1305 } else {
1306 typesAndSides[0] &= ~Type.systemBars();
1307 }
1308 }
1309 }
1310
1311 // TODO(b/118118435): remove after migration
Tiger Huang7c610aa2018-10-27 00:01:01 +08001312 private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1313 int impliedFlags = 0;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001314 final boolean forceWindowDrawsBarBackgrounds =
1315 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
Tiger Huang4a7835f2019-11-06 00:07:56 +08001316 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001317 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001318 || forceWindowDrawsBarBackgrounds) {
Jorim Jaggid6490572019-04-16 14:57:56 +02001319 impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001320 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1321 }
1322 return impliedFlags;
1323 }
1324
Tiger Huang7c610aa2018-10-27 00:01:01 +08001325 private final Runnable mClearHideNavigationFlag = new Runnable() {
1326 @Override
1327 public void run() {
1328 synchronized (mLock) {
1329 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1330 mDisplayContent.reevaluateStatusBarVisibility();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001331 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL && mNavigationBar != null) {
1332 final InsetsControlTarget target =
1333 mNavigationBar.getControllableInsetProvider().getControlTarget();
1334 if (target != null) {
1335 target.showInsets(Type.navigationBars(), false /* fromIme */);
1336 }
1337 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001338 }
1339 }
1340 };
1341
1342 /**
1343 * Input handler used while nav bar is hidden. Captures any touch on the screen,
1344 * to determine when the nav bar should be shown and prevent applications from
1345 * receiving those touches.
1346 */
1347 private final class HideNavInputEventReceiver extends InputEventReceiver {
1348 HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1349 super(inputChannel, looper);
1350 }
1351
1352 @Override
1353 public void onInputEvent(InputEvent event) {
1354 try {
1355 if (event instanceof MotionEvent
1356 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1357 final MotionEvent motionEvent = (MotionEvent) event;
1358 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1359 // When the user taps down, we re-show the nav bar.
1360 boolean changed = false;
1361 synchronized (mLock) {
1362 if (mInputConsumer == null) {
1363 return;
1364 }
1365 // Any user activity always causes us to show the
1366 // navigation controls, if they had been hidden.
1367 // We also clear the low profile and only content
1368 // flags so that tapping on the screen will atomically
1369 // restore all currently hidden screen decorations.
1370 int newVal = mResettingSystemUiFlags
1371 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1372 | View.SYSTEM_UI_FLAG_LOW_PROFILE
1373 | View.SYSTEM_UI_FLAG_FULLSCREEN;
1374 if (mResettingSystemUiFlags != newVal) {
1375 mResettingSystemUiFlags = newVal;
1376 changed = true;
1377 }
1378 // We don't allow the system's nav bar to be hidden
1379 // again for 1 second, to prevent applications from
1380 // spamming us and keeping it from being shown.
1381 newVal = mForceClearedSystemUiFlags
1382 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1383 if (mForceClearedSystemUiFlags != newVal) {
1384 mForceClearedSystemUiFlags = newVal;
1385 changed = true;
1386 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1387 }
1388 if (changed) {
1389 mDisplayContent.reevaluateStatusBarVisibility();
1390 }
1391 }
1392 }
1393 }
1394 } finally {
1395 finishInputEvent(event, false /* handled */);
1396 }
1397 }
1398 }
1399
1400 /**
1401 * Called when layout of the windows is about to start.
1402 *
1403 * @param displayFrames frames of the display we are doing layout on.
1404 * @param uiMode The current uiMode in configuration.
1405 */
1406 public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1407 displayFrames.onBeginLayout();
1408 mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1409 mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1410
1411 // For purposes of putting out fake window up to steal focus, we will
1412 // drive nav being hidden only by whether it is requested.
1413 final int sysui = mLastSystemUiFlags;
Tiger Huang4a7835f2019-11-06 00:07:56 +08001414 final int behavior = mLastBehavior;
1415 boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
1416 ? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
1417 : mNavigationBar != null && mNavigationBar.getControllableInsetProvider() != null
1418 && mNavigationBar.getControllableInsetProvider().isClientVisible()
1419 && !mDisplayContent.getInsetsPolicy().isTransient(ITYPE_NAVIGATION_BAR);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001420 boolean navTranslucent = (sysui
1421 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
Tiger Huang4a7835f2019-11-06 00:07:56 +08001422 boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
1423 || (behavior & BEHAVIOR_SHOW_BARS_BY_SWIPE) != 0;
1424 boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0
1425 || (behavior & BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001426 boolean navAllowedHidden = immersive || immersiveSticky;
1427 navTranslucent &= !immersiveSticky; // transient trumps translucent
1428 boolean isKeyguardShowing = isStatusBarKeyguard()
1429 && !mService.mPolicy.isKeyguardOccluded();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001430 boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
1431 && (mStatusBar.getAttrs().privateFlags
1432 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1433
1434 // When the navigation bar isn't visible, we put up a fake input window to catch all
1435 // touch events. This way we can detect when the user presses anywhere to bring back the
1436 // nav bar and ensure the application doesn't see the event.
1437 if (navVisible || navAllowedHidden) {
1438 if (mInputConsumer != null) {
1439 mHandler.sendMessage(
1440 mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1441 mInputConsumer = null;
1442 }
1443 } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1444 mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1445 INPUT_CONSUMER_NAVIGATION,
1446 HideNavInputEventReceiver::new,
1447 displayFrames.mDisplayId);
1448 // As long as mInputConsumer is active, hover events are not dispatched to the app
1449 // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1450 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1451 }
1452
1453 // For purposes of positioning and showing the nav bar, if we have decided that it can't
1454 // be hidden (because of the screen aspect ratio), then take that into account.
1455 navVisible |= !canHideNavigationBar();
1456
1457 boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
1458 navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
1459 if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1460 updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1461 if (updateSysUiVisibility) {
1462 updateSystemUiVisibilityLw();
1463 }
1464 layoutScreenDecorWindows(displayFrames);
1465
1466 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1467 // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1468 // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1469 // bar.
1470 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1471 displayFrames.mStable.top);
1472 }
Issei Suzukia5dbf522019-02-01 17:58:15 +01001473
1474 // In case this is a virtual display, and the host display has insets that overlap this
1475 // virtual display, apply the insets of the overlapped area onto the current and content
1476 // frame of this virtual display. This let us layout windows in the virtual display as
1477 // expected when the window needs to avoid overlap with the system windows.
1478 // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1479 // IME.
1480 displayFrames.mCurrent.inset(mForwardedInsets);
1481 displayFrames.mContent.inset(mForwardedInsets);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001482 }
1483
1484 private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1485 if (mScreenDecorWindows.isEmpty()) {
1486 return;
1487 }
1488
1489 sTmpRect.setEmpty();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001490 final int displayId = displayFrames.mDisplayId;
1491 final Rect dockFrame = displayFrames.mDock;
1492 final int displayHeight = displayFrames.mDisplayHeight;
1493 final int displayWidth = displayFrames.mDisplayWidth;
1494
1495 for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1496 final WindowState w = mScreenDecorWindows.valueAt(i);
1497 if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1498 // Skip if not on the same display or not visible.
1499 continue;
1500 }
1501
chaviw0d833762019-06-20 17:09:53 -07001502 w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1503 displayFrames.mUnrestricted /* displayFrame */,
chaviw0d833762019-06-20 17:09:53 -07001504 displayFrames.mUnrestricted /* contentFrame */,
1505 displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001506 displayFrames.mUnrestricted /* stableFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001507 w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1508 w.computeFrameLw();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001509 if (w.getControllableInsetProvider() != null) {
1510 w.getControllableInsetProvider().updateSourceFrame();
1511 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001512 final Rect frame = w.getFrameLw();
1513
1514 if (frame.left <= 0 && frame.top <= 0) {
1515 // Docked at left or top.
1516 if (frame.bottom >= displayHeight) {
1517 // Docked left.
1518 dockFrame.left = Math.max(frame.right, dockFrame.left);
1519 } else if (frame.right >= displayWidth) {
1520 // Docked top.
1521 dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1522 } else {
1523 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1524 + " not docked on left or top of display. frame=" + frame
1525 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1526 }
1527 } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1528 // Docked at right or bottom.
1529 if (frame.top <= 0) {
1530 // Docked right.
1531 dockFrame.right = Math.min(frame.left, dockFrame.right);
1532 } else if (frame.left <= 0) {
1533 // Docked bottom.
1534 dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1535 } else {
1536 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1537 + " not docked on right or bottom" + " of display. frame=" + frame
1538 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1539 }
1540 } else {
1541 // Screen decor windows are required to be docked on one of the sides of the screen.
1542 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1543 + " not docked on one of the sides of the display. frame=" + frame
1544 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1545 }
1546 }
1547
1548 displayFrames.mRestricted.set(dockFrame);
1549 displayFrames.mCurrent.set(dockFrame);
1550 displayFrames.mVoiceContent.set(dockFrame);
1551 displayFrames.mSystem.set(dockFrame);
1552 displayFrames.mContent.set(dockFrame);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001553 }
1554
1555 private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1556 boolean isKeyguardShowing) {
1557 // decide where the status bar goes ahead of time
1558 if (mStatusBar == null) {
1559 return false;
1560 }
1561 // apply any navigation bar insets
1562 sTmpRect.setEmpty();
Jorim Jaggi4981f152019-03-26 18:58:45 +01001563 final WindowFrames windowFrames = mStatusBar.getWindowFrames();
1564 windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001565 displayFrames.mUnrestricted /* displayFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001566 displayFrames.mStable /* contentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001567 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001568 displayFrames.mStable /* stableFrame */);
Jorim Jaggi4981f152019-03-26 18:58:45 +01001569 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001570
1571 // Let the status bar determine its size.
1572 mStatusBar.computeFrameLw();
1573
Tiger Huang4a7835f2019-11-06 00:07:56 +08001574 // Update the source frame to provide insets to other windows during layout.
1575 if (mStatusBar.getControllableInsetProvider() != null) {
1576 mStatusBar.getControllableInsetProvider().updateSourceFrame();
1577 }
1578
Tiger Huang7c610aa2018-10-27 00:01:01 +08001579 // For layout, the status bar is always at the top with our fixed height.
1580 displayFrames.mStable.top = displayFrames.mUnrestricted.top
1581 + mStatusBarHeightForRotation[displayFrames.mRotation];
1582 // Make sure the status bar covers the entire cutout height
1583 displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1584 displayFrames.mDisplayCutoutSafe.top);
1585
1586 // Tell the bar controller where the collapsed status bar content is
1587 sTmpRect.set(mStatusBar.getContentFrameLw());
1588 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1589 sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
1590 sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
1591 mStatusBarController.setContentFrame(sTmpRect);
1592
Tiger Huang4a7835f2019-11-06 00:07:56 +08001593 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0
1594 || mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001595 boolean statusBarTranslucent = (sysui
1596 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001597
1598 // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1599 if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1600 // Status bar may go away, so the screen area it occupies is available to apps but just
1601 // covering them when the status bar is visible.
1602 final Rect dockFrame = displayFrames.mDock;
1603 dockFrame.top = displayFrames.mStable.top;
1604 displayFrames.mContent.set(dockFrame);
1605 displayFrames.mVoiceContent.set(dockFrame);
1606 displayFrames.mCurrent.set(dockFrame);
1607
1608 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1609 "dock=%s content=%s cur=%s", dockFrame.toString(),
1610 displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1611
Jorim Jaggi4981f152019-03-26 18:58:45 +01001612 if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
1613 && !mStatusBar.isAnimatingLw()) {
1614
Tiger Huang7c610aa2018-10-27 00:01:01 +08001615 // If the opaque status bar is currently requested to be visible, and not in the
1616 // process of animating on or off, then we can tell the app that it is covered by
1617 // it.
1618 displayFrames.mSystem.top = displayFrames.mStable.top;
1619 }
1620 }
1621 return mStatusBarController.checkHiddenLw();
1622 }
1623
1624 private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1625 boolean navTranslucent, boolean navAllowedHidden,
1626 boolean statusBarForcesShowingNavigation) {
1627 if (mNavigationBar == null) {
1628 return false;
1629 }
1630
1631 final Rect navigationFrame = sTmpNavFrame;
1632 boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1633 // Force the navigation bar to its appropriate place and size. We need to do this directly,
1634 // instead of relying on it to bubble up from the nav bar, because this needs to change
1635 // atomically with screen rotations.
1636 final int rotation = displayFrames.mRotation;
1637 final int displayHeight = displayFrames.mDisplayHeight;
1638 final int displayWidth = displayFrames.mDisplayWidth;
1639 final Rect dockFrame = displayFrames.mDock;
1640 mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1641
1642 final Rect cutoutSafeUnrestricted = sTmpRect;
1643 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1644 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1645
1646 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1647 // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1648 final int top = cutoutSafeUnrestricted.bottom
1649 - getNavigationBarHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001650 final int topNavBar = cutoutSafeUnrestricted.bottom
Matthew Nga7f24bc2019-04-09 17:06:41 -07001651 - getNavigationBarFrameHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001652 navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001653 displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1654 if (transientNavBarShowing) {
1655 mNavigationBarController.setBarShowingLw(true);
1656 } else if (navVisible) {
1657 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001658 dockFrame.bottom = displayFrames.mRestricted.bottom = top;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001659 } else {
1660 // We currently want to hide the navigation UI - unless we expanded the status bar.
1661 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1662 }
1663 if (navVisible && !navTranslucent && !navAllowedHidden
1664 && !mNavigationBar.isAnimatingLw()
1665 && !mNavigationBarController.wasRecentlyTranslucent()) {
1666 // If the opaque nav bar is currently requested to be visible and not in the process
1667 // of animating on or off, then we can tell the app that it is covered by it.
1668 displayFrames.mSystem.bottom = top;
1669 }
1670 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1671 // Landscape screen; nav bar goes to the right.
1672 final int left = cutoutSafeUnrestricted.right
1673 - getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001674 navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001675 displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1676 if (transientNavBarShowing) {
1677 mNavigationBarController.setBarShowingLw(true);
1678 } else if (navVisible) {
1679 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001680 dockFrame.right = displayFrames.mRestricted.right = left;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001681 } else {
1682 // We currently want to hide the navigation UI - unless we expanded the status bar.
1683 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1684 }
1685 if (navVisible && !navTranslucent && !navAllowedHidden
1686 && !mNavigationBar.isAnimatingLw()
1687 && !mNavigationBarController.wasRecentlyTranslucent()) {
1688 // If the nav bar is currently requested to be visible, and not in the process of
1689 // animating on or off, then we can tell the app that it is covered by it.
1690 displayFrames.mSystem.right = left;
1691 }
1692 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1693 // Seascape screen; nav bar goes to the left.
1694 final int right = cutoutSafeUnrestricted.left
1695 + getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001696 navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001697 displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1698 if (transientNavBarShowing) {
1699 mNavigationBarController.setBarShowingLw(true);
1700 } else if (navVisible) {
1701 mNavigationBarController.setBarShowingLw(true);
Jorim Jaggif081f062019-10-24 16:24:54 +02001702 dockFrame.left = displayFrames.mRestricted.left = right;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001703 } else {
1704 // We currently want to hide the navigation UI - unless we expanded the status bar.
1705 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1706 }
1707 if (navVisible && !navTranslucent && !navAllowedHidden
1708 && !mNavigationBar.isAnimatingLw()
1709 && !mNavigationBarController.wasRecentlyTranslucent()) {
1710 // If the nav bar is currently requested to be visible, and not in the process of
1711 // animating on or off, then we can tell the app that it is covered by it.
1712 displayFrames.mSystem.left = right;
1713 }
1714 }
1715
1716 // Make sure the content and current rectangles are updated to account for the restrictions
1717 // from the navigation bar.
1718 displayFrames.mCurrent.set(dockFrame);
1719 displayFrames.mVoiceContent.set(dockFrame);
1720 displayFrames.mContent.set(dockFrame);
1721 // And compute the final frame.
1722 sTmpRect.setEmpty();
1723 mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001724 navigationFrame /* displayFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001725 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1726 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
Jorim Jaggif081f062019-10-24 16:24:54 +02001727 navigationFrame /* stableFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001728 mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1729 mNavigationBar.computeFrameLw();
Tiger Huang4a7835f2019-11-06 00:07:56 +08001730 if (mNavigationBar.getControllableInsetProvider() != null) {
1731 mNavigationBar.getControllableInsetProvider().updateSourceFrame();
1732 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001733 mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1734
1735 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1736 return mNavigationBarController.checkHiddenLw();
1737 }
1738
1739 private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
Jorim Jaggif081f062019-10-24 16:24:54 +02001740 boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001741 DisplayFrames displayFrames) {
1742 if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1743 // Here's a special case: if the child window is not the 'dock window'
1744 // or input method target, and the window it is attached to is below
1745 // the dock window, then the frames we computed for the window it is
1746 // attached to can not be used because the dock is effectively part
1747 // of the underlying window and the attached window is floating on top
1748 // of the whole thing. So, we ignore the attached window and explicitly
1749 // compute the frames that would be appropriate without the dock.
1750 vf.set(displayFrames.mDock);
1751 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001752 df.set(displayFrames.mDock);
1753 } else {
Jorim Jaggid6490572019-04-16 14:57:56 +02001754
Jorim Jaggif081f062019-10-24 16:24:54 +02001755 // In case we forced the window to draw behind the navigation bar, restrict df to
1756 // DF.Restricted to simulate old compat behavior.
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001757 Rect parentDisplayFrame = attached.getDisplayFrameLw();
Jorim Jaggid6490572019-04-16 14:57:56 +02001758 final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
1759 if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1760 && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1761 && (attachedAttrs.systemUiVisibility
1762 & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001763 parentDisplayFrame = new Rect(parentDisplayFrame);
Jorim Jaggif081f062019-10-24 16:24:54 +02001764 parentDisplayFrame.intersect(displayFrames.mRestricted);
Jorim Jaggid6490572019-04-16 14:57:56 +02001765 }
1766
Tiger Huang7c610aa2018-10-27 00:01:01 +08001767 // The effective display frame of the attached window depends on whether it is taking
1768 // care of insetting its content. If not, we need to use the parent's content frame so
1769 // that the entire window is positioned within that content. Otherwise we can use the
Jorim Jaggif081f062019-10-24 16:24:54 +02001770 // parent display frame and let the attached window take care of positioning its content
Tiger Huang7c610aa2018-10-27 00:01:01 +08001771 // appropriately.
1772 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1773 // Set the content frame of the attached window to the parent's decor frame
1774 // (same as content frame when IME isn't present) if specifically requested by
1775 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1776 // Otherwise, use the overscan frame.
1777 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
Jorim Jaggif081f062019-10-24 16:24:54 +02001778 ? attached.getContentFrameLw() : parentDisplayFrame);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001779 } else {
1780 // If the window is resizing, then we want to base the content frame on our attached
1781 // content frame to resize...however, things can be tricky if the attached window is
1782 // NOT in resize mode, in which case its content frame will be larger.
1783 // Ungh. So to deal with that, make sure the content frame we end up using is not
1784 // covering the IM dock.
1785 cf.set(attached.getContentFrameLw());
1786 if (attached.isVoiceInteraction()) {
1787 cf.intersectUnchecked(displayFrames.mVoiceContent);
1788 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1789 cf.intersectUnchecked(displayFrames.mContent);
1790 }
1791 }
Jorim Jaggid6490572019-04-16 14:57:56 +02001792 df.set(insetDecors ? parentDisplayFrame : cf);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001793 vf.set(attached.getVisibleFrameLw());
1794 }
1795 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1796 // positioned relative to its parent or the entire screen.
1797 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1798 }
1799
1800 private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1801 if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1802 return;
1803 }
1804 // If app is requesting a stable layout, don't let the content insets go below the stable
1805 // values.
1806 if ((fl & FLAG_FULLSCREEN) != 0) {
1807 r.intersectUnchecked(displayFrames.mStableFullscreen);
1808 } else {
1809 r.intersectUnchecked(displayFrames.mStable);
1810 }
1811 }
1812
1813 private boolean canReceiveInput(WindowState win) {
1814 boolean notFocusable =
1815 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1816 boolean altFocusableIm =
1817 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1818 boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1819 return !notFocusableForIm;
1820 }
1821
1822 /**
1823 * Called for each window attached to the window manager as layout is proceeding. The
1824 * implementation of this function must take care of setting the window's frame, either here or
1825 * in finishLayout().
1826 *
1827 * @param win The window being positioned.
1828 * @param attached For sub-windows, the window it is attached to; this
1829 * window will already have had layoutWindow() called on it
1830 * so you can use its Rect. Otherwise null.
1831 * @param displayFrames The display frames.
1832 */
1833 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1834 // We've already done the navigation bar, status bar, and all screen decor windows. If the
1835 // status bar can receive input, we need to layout it again to accommodate for the IME
1836 // window.
1837 if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1838 || mScreenDecorWindows.contains(win)) {
1839 return;
1840 }
1841 final WindowManager.LayoutParams attrs = win.getAttrs();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001842
1843 final int type = attrs.type;
1844 final int fl = PolicyControl.getWindowFlags(win, attrs);
1845 final int pfl = attrs.privateFlags;
1846 final int sim = attrs.softInputMode;
1847 final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1848 final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1849
1850 final WindowFrames windowFrames = win.getWindowFrames();
1851
Tiger Huang7c610aa2018-10-27 00:01:01 +08001852 sTmpLastParentFrame.set(windowFrames.mParentFrame);
1853 final Rect pf = windowFrames.mParentFrame;
1854 final Rect df = windowFrames.mDisplayFrame;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001855 final Rect cf = windowFrames.mContentFrame;
1856 final Rect vf = windowFrames.mVisibleFrame;
1857 final Rect dcf = windowFrames.mDecorFrame;
1858 final Rect sf = windowFrames.mStableFrame;
1859 dcf.setEmpty();
1860 windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1861 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1862
1863 final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1864 && mNavigationBar.isVisibleLw();
1865
1866 final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1867
Tiger Huang7c610aa2018-10-27 00:01:01 +08001868 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1869 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1870
1871 sf.set(displayFrames.mStable);
1872
Tiger Huang4a7835f2019-11-06 00:07:56 +08001873 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
1874 getImpliedTypesAndSidesToFit(attrs, sTmpTypesAndSides);
1875 final @InsetsType int typesToFit = sTmpTypesAndSides[0];
1876 final @InsetsSide int sidesToFit = sTmpTypesAndSides[1];
1877 final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
1878 final Rect dfu = displayFrames.mUnrestricted;
1879 Insets insets = Insets.of(0, 0, 0, 0);
1880 for (int i = types.size() - 1; i >= 0; i--) {
Tiger Huang82520fc2019-12-19 22:29:20 +08001881 insets = Insets.max(insets, mDisplayContent.getInsetsPolicy()
Tiger Huang4a7835f2019-11-06 00:07:56 +08001882 .getInsetsForDispatch(win).getSource(types.valueAt(i))
1883 .calculateInsets(dfu, attrs.getFitIgnoreVisibility()));
1884 }
1885 final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
1886 final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
1887 final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
1888 final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
1889 df.set(left, top, dfu.right - right, dfu.bottom - bottom);
1890 if (attached == null) {
1891 pf.set(df);
1892 vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
1893 ? displayFrames.mCurrent : displayFrames.mDock);
1894 } else {
1895 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1896 vf.set(attached.getVisibleFrameLw());
1897 }
1898 cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
1899 ? displayFrames.mDock : displayFrames.mContent);
1900 dcf.set(displayFrames.mSystem);
1901 } else if (type == TYPE_INPUT_METHOD) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001902 vf.set(displayFrames.mDock);
1903 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001904 df.set(displayFrames.mDock);
Tiger Huang4a7835f2019-11-06 00:07:56 +08001905 pf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001906 // IM dock windows layout below the nav bar...
Jorim Jaggif081f062019-10-24 16:24:54 +02001907 pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001908 // ...with content insets above the nav bar
1909 cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1910 if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1911 // The status bar forces the navigation bar while it's visible. Make sure the IME
1912 // avoids the navigation bar in that case.
1913 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001914 pf.right = df.right = cf.right = vf.right =
Tiger Huang7c610aa2018-10-27 00:01:01 +08001915 displayFrames.mStable.right;
1916 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001917 pf.left = df.left = cf.left = vf.left = displayFrames.mStable.left;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001918 }
1919 }
1920
Matthew Nga7f24bc2019-04-09 17:06:41 -07001921 // In case the navigation bar is on the bottom, we use the frame height instead of the
1922 // regular height for the insets we send to the IME as we need some space to show
1923 // additional buttons in SystemUI when the IME is up.
1924 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1925 final int rotation = displayFrames.mRotation;
1926 final int uimode = mService.mPolicy.getUiMode();
1927 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
1928 - getNavigationBarHeight(rotation, uimode);
1929 if (navHeightOffset > 0) {
1930 cf.bottom -= navHeightOffset;
1931 sf.bottom -= navHeightOffset;
1932 vf.bottom -= navHeightOffset;
1933 dcf.bottom -= navHeightOffset;
1934 }
1935 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001936
1937 // IM dock windows always go to the bottom of the screen.
1938 attrs.gravity = Gravity.BOTTOM;
1939 } else if (type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001940 df.set(displayFrames.mUnrestricted);
1941 pf.set(displayFrames.mUnrestricted);
1942 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1943 cf.set(displayFrames.mDock);
1944 } else {
1945 cf.set(displayFrames.mContent);
1946 }
1947 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1948 vf.set(displayFrames.mCurrent);
1949 } else {
1950 vf.set(cf);
1951 }
1952 } else if (type == TYPE_WALLPAPER) {
Jorim Jaggif081f062019-10-24 16:24:54 +02001953 layoutWallpaper(displayFrames, pf, df, cf);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001954 } else if (win == mStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001955 df.set(displayFrames.mUnrestricted);
1956 pf.set(displayFrames.mUnrestricted);
1957 cf.set(displayFrames.mStable);
1958 vf.set(displayFrames.mStable);
1959
1960 if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7fe7f682019-10-26 01:11:23 +08001961 // cf.bottom should not be below the stable bottom, or the content might be obscured
1962 // by the navigation bar.
1963 if (cf.bottom > displayFrames.mContent.bottom) {
1964 cf.bottom = displayFrames.mContent.bottom;
1965 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001966 } else {
Tiger Huang7fe7f682019-10-26 01:11:23 +08001967 if (cf.bottom > displayFrames.mDock.bottom) {
1968 cf.bottom = displayFrames.mDock.bottom;
1969 }
1970 if (vf.bottom > displayFrames.mContent.bottom) {
1971 vf.bottom = displayFrames.mContent.bottom;
1972 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001973 }
1974 } else {
1975 dcf.set(displayFrames.mSystem);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001976 final boolean isAppWindow =
1977 type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1978 final boolean topAtRest =
1979 win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
Jorim Jaggia2e648e2019-10-25 15:06:53 +02001980 if (isAppWindow && !topAtRest) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001981 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
1982 && (fl & FLAG_FULLSCREEN) == 0
1983 && (fl & FLAG_TRANSLUCENT_STATUS) == 0
1984 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001985 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001986 // Ensure policy decor includes status bar
1987 dcf.top = displayFrames.mStable.top;
1988 }
1989 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
1990 && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001991 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1992 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001993 // Ensure policy decor includes navigation bar
1994 dcf.bottom = displayFrames.mStable.bottom;
1995 dcf.right = displayFrames.mStable.right;
1996 }
1997 }
1998
1999 if (layoutInScreen && layoutInsetDecor) {
2000 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2001 + "): IN_SCREEN, INSET_DECOR");
2002 // This is the case for a normal activity window: we want it to cover all of the
2003 // screen space, and it can take care of moving its contents to account for screen
2004 // decorations that intrude into that space.
2005 if (attached != null) {
2006 // If this window is attached to another, our display
2007 // frame is the same as the one we are attached to.
Jorim Jaggif081f062019-10-24 16:24:54 +02002008 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08002009 displayFrames);
2010 } else {
2011 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2012 // Status bar panels are the only windows who can go on top of the status
2013 // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
2014 // have the same privileges as the status bar itself.
2015 //
2016 // However, they should still dodge the navigation bar if it exists.
2017
Jorim Jaggif081f062019-10-24 16:24:54 +02002018 pf.left = df.left = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002019 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
Jorim Jaggif081f062019-10-24 16:24:54 +02002020 pf.top = df.top = displayFrames.mUnrestricted.top;
2021 pf.right = df.right = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002022 ? displayFrames.mRestricted.right
2023 : displayFrames.mUnrestricted.right;
Jorim Jaggif081f062019-10-24 16:24:54 +02002024 pf.bottom = df.bottom = hasNavBar
Tiger Huang7c610aa2018-10-27 00:01:01 +08002025 ? displayFrames.mRestricted.bottom
2026 : displayFrames.mUnrestricted.bottom;
2027
2028 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
Jorim Jaggid6490572019-04-16 14:57:56 +02002029 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08002030 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
Charles Chen64172bb2019-04-22 17:30:29 +08002031 || type == TYPE_VOLUME_OVERLAY
2032 || type == TYPE_KEYGUARD_DIALOG)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002033 // Asking for layout as if the nav bar is hidden, lets the application
2034 // extend into the unrestricted overscan screen area. We only do this for
2035 // application windows and certain system windows to ensure no window that
2036 // can be above the nav bar can do this.
Jorim Jaggif081f062019-10-24 16:24:54 +02002037 df.set(displayFrames.mUnrestricted);
2038 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002039 } else {
Jorim Jaggif081f062019-10-24 16:24:54 +02002040 df.set(displayFrames.mRestricted);
2041 pf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002042 }
2043
2044 if ((fl & FLAG_FULLSCREEN) == 0) {
2045 if (win.isVoiceInteraction()) {
2046 cf.set(displayFrames.mVoiceContent);
2047 } else {
Jorim Jaggi648e5882019-01-24 13:24:02 +01002048 // IME Insets are handled on the client for ADJUST_RESIZE in the new
2049 // insets world
2050 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2051 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002052 cf.set(displayFrames.mDock);
2053 } else {
2054 cf.set(displayFrames.mContent);
2055 }
2056 }
2057 } else {
2058 // Full screen windows are always given a layout that is as if the status
2059 // bar and other transient decors are gone. This is to avoid bad states when
2060 // moving from a window that is not hiding the status bar to one that is.
2061 cf.set(displayFrames.mRestricted);
2062 }
2063 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2064 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2065 vf.set(displayFrames.mCurrent);
2066 } else {
2067 vf.set(cf);
2068 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002069 }
2070 } else if (layoutInScreen || (sysUiFl
Tiger Huang4a7835f2019-11-06 00:07:56 +08002071 & (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Jorim Jaggid6490572019-04-16 14:57:56 +02002072 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002073 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2074 + "): IN_SCREEN");
2075 // A window that has requested to fill the entire screen just
2076 // gets everything, period.
2077 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2078 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002079 df.set(displayFrames.mUnrestricted);
2080 pf.set(displayFrames.mUnrestricted);
2081 if (hasNavBar) {
Jorim Jaggif081f062019-10-24 16:24:54 +02002082 pf.left = df.left = cf.left = displayFrames.mDock.left;
2083 pf.right = df.right = cf.right = displayFrames.mRestricted.right;
2084 pf.bottom = df.bottom = cf.bottom =
Tiger Huang7c610aa2018-10-27 00:01:01 +08002085 displayFrames.mRestricted.bottom;
2086 }
2087 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
2088 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
2089 // The navigation bar has Real Ultimate Power.
Tiger Huang7c610aa2018-10-27 00:01:01 +08002090 df.set(displayFrames.mUnrestricted);
2091 pf.set(displayFrames.mUnrestricted);
2092 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
2093 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
2094 && ((fl & FLAG_FULLSCREEN) != 0)) {
2095 // Fullscreen secure system overlays get what they ask for. Screenshot region
2096 // selection overlay should also expand to full screen.
Jorim Jaggif081f062019-10-24 16:24:54 +02002097 cf.set(displayFrames.mUnrestricted);
2098 df.set(displayFrames.mUnrestricted);
2099 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002100 } else if (type == TYPE_BOOT_PROGRESS) {
2101 // Boot progress screen always covers entire display.
Jorim Jaggif081f062019-10-24 16:24:54 +02002102 cf.set(displayFrames.mUnrestricted);
2103 df.set(displayFrames.mUnrestricted);
2104 pf.set(displayFrames.mUnrestricted);
Jorim Jaggid6490572019-04-16 14:57:56 +02002105 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08002106 && (type == TYPE_STATUS_BAR
2107 || type == TYPE_TOAST
2108 || type == TYPE_DOCK_DIVIDER
2109 || type == TYPE_VOICE_INTERACTION_STARTING
2110 || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
2111 // Asking for layout as if the nav bar is hidden, lets the
2112 // application extend into the unrestricted screen area. We
2113 // only do this for application windows (or toasts) to ensure no window that
2114 // can be above the nav bar can do this.
2115 // XXX This assumes that an app asking for this will also
2116 // ask for layout in only content. We can't currently figure out
2117 // what the screen would be if only laying out to hide the nav bar.
2118 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002119 df.set(displayFrames.mUnrestricted);
2120 pf.set(displayFrames.mUnrestricted);
Tiger Huang4a7835f2019-11-06 00:07:56 +08002121 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002122 df.set(displayFrames.mRestricted);
2123 pf.set(displayFrames.mRestricted);
Jorim Jaggi648e5882019-01-24 13:24:02 +01002124
2125 // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2126 // world
2127 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2128 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002129 cf.set(displayFrames.mDock);
2130 } else {
2131 cf.set(displayFrames.mContent);
2132 }
2133 } else {
2134 cf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002135 df.set(displayFrames.mRestricted);
2136 pf.set(displayFrames.mRestricted);
2137 }
2138
2139 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2140
2141 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2142 vf.set(displayFrames.mCurrent);
2143 } else {
2144 vf.set(cf);
2145 }
2146 } else if (attached != null) {
2147 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2148 + "): attached to " + attached);
2149 // A child window should be placed inside of the same visible
2150 // frame that its parent had.
Jorim Jaggif081f062019-10-24 16:24:54 +02002151 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf,
Tiger Huang7c610aa2018-10-27 00:01:01 +08002152 displayFrames);
2153 } else {
2154 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2155 + "): normal window");
2156 // Otherwise, a normal window must be placed inside the content
2157 // of all screen decorations.
2158 if (type == TYPE_STATUS_BAR_PANEL) {
2159 // Status bar panels can go on
2160 // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2161 // permission, so they have the same privileges as the status bar itself.
2162 cf.set(displayFrames.mRestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002163 df.set(displayFrames.mRestricted);
2164 pf.set(displayFrames.mRestricted);
Vishnu Nair9ccb1d22019-03-20 16:32:44 +00002165 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002166 // These dialogs are stable to interim decor changes.
2167 cf.set(displayFrames.mStable);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002168 df.set(displayFrames.mStable);
2169 pf.set(displayFrames.mStable);
2170 } else {
2171 pf.set(displayFrames.mContent);
2172 if (win.isVoiceInteraction()) {
2173 cf.set(displayFrames.mVoiceContent);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002174 df.set(displayFrames.mVoiceContent);
2175 } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2176 cf.set(displayFrames.mDock);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002177 df.set(displayFrames.mDock);
2178 } else {
2179 cf.set(displayFrames.mContent);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002180 df.set(displayFrames.mContent);
2181 }
2182 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2183 vf.set(displayFrames.mCurrent);
2184 } else {
2185 vf.set(cf);
2186 }
2187 }
2188 }
2189 }
2190
2191 final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2192 final boolean attachedInParent = attached != null && !layoutInScreen;
Tiger Huang4a7835f2019-11-06 00:07:56 +08002193 final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
2194 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
Jorim Jaggi0dd0cf92019-12-27 15:17:44 +01002195 || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
2196 && !win.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002197 final boolean requestedHideNavigation =
Tiger Huang4a7835f2019-11-06 00:07:56 +08002198 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
Jorim Jaggi0dd0cf92019-12-27 15:17:44 +01002199 || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
2200 && !win.getRequestedInsetsState().getSource(ITYPE_NAVIGATION_BAR)
2201 .isVisible());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002202
2203 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2204 // cropped / shifted to the displayFrame in WindowState.
2205 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2206 && type != TYPE_BASE_APPLICATION;
2207
2208 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2209 // the cutout safe zone.
Arthur Hung20479922019-02-27 17:13:22 +08002210 if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002211 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2212 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2213 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2214 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2215 // At the top we have the status bar, so apps that are
2216 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2217 // already expect that there's an inset there and we don't need to exclude
2218 // the window from that area.
2219 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2220 }
2221 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2222 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2223 // Same for the navigation bar.
2224 switch (mNavigationBarPosition) {
2225 case NAV_BAR_BOTTOM:
2226 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2227 break;
2228 case NAV_BAR_RIGHT:
2229 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2230 break;
2231 case NAV_BAR_LEFT:
2232 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2233 break;
2234 }
2235 }
2236 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2237 // The IME can always extend under the bottom cutout if the navbar is there.
2238 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2239 }
2240 // Windows that are attached to a parent and laid out in said parent already avoid
2241 // the cutout according to that parent and don't need to be further constrained.
2242 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2243 // They will later be cropped or shifted using the displayFrame in WindowState,
2244 // which prevents overlap with the DisplayCutout.
2245 if (!attachedInParent && !floatingInScreenWindow) {
2246 sTmpRect.set(pf);
2247 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2248 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2249 }
2250 // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2251 // cutout.
2252 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2253 }
2254
2255 // Content should never appear in the cutout.
2256 cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2257
2258 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2259 // Also, we don't allow windows in multi-window mode to extend out of the screen.
2260 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
Evan Rosky4fb1e912019-03-06 13:54:43 -08002261 && !win.inMultiWindowMode()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002262 df.left = df.top = -10000;
2263 df.right = df.bottom = 10000;
2264 if (type != TYPE_WALLPAPER) {
Jorim Jaggif081f062019-10-24 16:24:54 +02002265 cf.left = cf.top = vf.left = vf.top = -10000;
2266 cf.right = cf.bottom = vf.right = vf.bottom = 10000;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002267 }
2268 }
2269
2270 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2271 + ": sim=#" + Integer.toHexString(sim)
2272 + " attach=" + attached + " type=" + type
2273 + String.format(" flags=0x%08x", fl)
2274 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
Tiger Huang7c610aa2018-10-27 00:01:01 +08002275 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2276 + " dcf=" + dcf.toShortString()
Jorim Jaggif081f062019-10-24 16:24:54 +02002277 + " sf=" + sf.toShortString());
Tiger Huang7c610aa2018-10-27 00:01:01 +08002278
2279 if (!sTmpLastParentFrame.equals(pf)) {
2280 windowFrames.setContentChanged(true);
2281 }
2282
2283 win.computeFrameLw();
Tiger Huang4a7835f2019-11-06 00:07:56 +08002284 if (win.getControllableInsetProvider() != null) {
2285 win.getControllableInsetProvider().updateSourceFrame();
2286 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002287 // Dock windows carve out the bottom of the screen, so normal windows
2288 // can't appear underneath them.
2289 if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2290 && !win.getGivenInsetsPendingLw()) {
2291 offsetInputMethodWindowLw(win, displayFrames);
2292 }
2293 if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2294 && !win.getGivenInsetsPendingLw()) {
2295 offsetVoiceInputWindowLw(win, displayFrames);
2296 }
2297 }
2298
Jorim Jaggif081f062019-10-24 16:24:54 +02002299 private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect cf) {
2300 // The wallpaper has Real Ultimate Power
2301 df.set(displayFrames.mUnrestricted);
2302 pf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002303 cf.set(displayFrames.mUnrestricted);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002304 }
2305
2306 private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
Winson Chung913690d2019-11-14 16:06:01 -08002307 final int rotation = displayFrames.mRotation;
2308 final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
2309 displayFrames.mDisplayHeight, rotation);
2310
Tiger Huang7c610aa2018-10-27 00:01:01 +08002311 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2312 top += win.getGivenContentInsetsLw().top;
2313 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
Winson Chung913690d2019-11-14 16:06:01 -08002314 if (navBarPosition == NAV_BAR_BOTTOM) {
2315 // Always account for the nav bar frame height on the bottom since in all navigation
2316 // modes we make room to show the dismiss-ime button, even if the IME does not report
2317 // insets (ie. when floating)
2318 final int uimode = mService.mPolicy.getUiMode();
2319 final int navFrameHeight = getNavigationBarFrameHeight(rotation, uimode);
2320 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom,
2321 displayFrames.mUnrestricted.bottom - navFrameHeight);
2322 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002323 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2324 top = win.getVisibleFrameLw().top;
2325 top += win.getGivenVisibleInsetsLw().top;
2326 displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2327 if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2328 + displayFrames.mDock.bottom + " mContentBottom="
2329 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2330 }
2331
2332 private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2333 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2334 top += win.getGivenContentInsetsLw().top;
2335 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2336 }
2337
Riddle Hsuccf09402019-08-13 00:33:06 +08002338 WindowState getTopFullscreenOpaqueWindow() {
2339 return mTopFullscreenOpaqueWindowState;
2340 }
2341
2342 boolean isTopLayoutFullscreen() {
2343 return mTopIsFullscreen;
2344 }
2345
Tiger Huang7c610aa2018-10-27 00:01:01 +08002346 /**
2347 * Called following layout of all windows before each window has policy applied.
2348 */
2349 public void beginPostLayoutPolicyLw() {
2350 mTopFullscreenOpaqueWindowState = null;
2351 mTopFullscreenOpaqueOrDimmingWindowState = null;
2352 mTopDockedOpaqueWindowState = null;
2353 mTopDockedOpaqueOrDimmingWindowState = null;
2354 mForceStatusBar = false;
2355 mForceStatusBarFromKeyguard = false;
2356 mForceStatusBarTransparent = false;
2357 mForcingShowNavBar = false;
2358 mForcingShowNavBarLayer = -1;
2359
2360 mAllowLockscreenWhenOn = false;
2361 mShowingDream = false;
2362 mWindowSleepTokenNeeded = false;
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002363 mIsFreeformWindowOverlappingWithNavBar = false;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002364 }
2365
2366 /**
2367 * Called following layout of all window to apply policy to each window.
2368 *
2369 * @param win The window being positioned.
2370 * @param attrs The LayoutParams of the window.
2371 * @param attached For sub-windows, the window it is attached to. Otherwise null.
2372 */
2373 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2374 WindowState attached, WindowState imeTarget) {
2375 final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2376 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2377 mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2378 final int fl = PolicyControl.getWindowFlags(win, attrs);
2379 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2380 && attrs.type == TYPE_INPUT_METHOD) {
2381 mForcingShowNavBar = true;
2382 mForcingShowNavBarLayer = win.getSurfaceLayer();
2383 }
2384 if (attrs.type == TYPE_STATUS_BAR) {
2385 if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
2386 mForceStatusBarFromKeyguard = true;
2387 }
2388 if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
2389 mForceStatusBarTransparent = true;
2390 }
2391 }
2392
2393 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2394 && attrs.type < FIRST_SYSTEM_WINDOW;
2395 final int windowingMode = win.getWindowingMode();
2396 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2397 windowingMode == WINDOWING_MODE_FULLSCREEN
2398 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2399 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2400 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2401 mForceStatusBar = true;
2402 }
2403 if (attrs.type == TYPE_DREAM) {
2404 // If the lockscreen was showing when the dream started then wait
2405 // for the dream to draw before hiding the lockscreen.
2406 if (!mDreamingLockscreen
2407 || (win.isVisibleLw() && win.hasDrawnLw())) {
2408 mShowingDream = true;
2409 appWindow = true;
2410 }
2411 }
2412
2413 // For app windows that are not attached, we decide if all windows in the app they
2414 // represent should be hidden or if we should hide the lockscreen. For attached app
2415 // windows we defer the decision to the window it is attached to.
2416 if (appWindow && attached == null) {
2417 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2418 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2419 mTopFullscreenOpaqueWindowState = win;
2420 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2421 mTopFullscreenOpaqueOrDimmingWindowState = win;
2422 }
2423 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2424 mAllowLockscreenWhenOn = true;
2425 }
2426 }
2427 }
2428 }
2429
2430 // Voice interaction overrides both top fullscreen and top docked.
Jorim Jaggi50150152019-03-27 23:08:58 +01002431 if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002432 if (mTopFullscreenOpaqueWindowState == null) {
2433 mTopFullscreenOpaqueWindowState = win;
2434 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2435 mTopFullscreenOpaqueOrDimmingWindowState = win;
2436 }
2437 }
2438 if (mTopDockedOpaqueWindowState == null) {
2439 mTopDockedOpaqueWindowState = win;
2440 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2441 mTopDockedOpaqueOrDimmingWindowState = win;
2442 }
2443 }
2444 }
2445
2446 // Keep track of the window if it's dimming but not necessarily fullscreen.
2447 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2448 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2449 mTopFullscreenOpaqueOrDimmingWindowState = win;
2450 }
2451
2452 // We need to keep track of the top "fullscreen" opaque window for the docked stack
2453 // separately, because both the "real fullscreen" opaque window and the one for the docked
2454 // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2455 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2456 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2457 mTopDockedOpaqueWindowState = win;
2458 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2459 mTopDockedOpaqueOrDimmingWindowState = win;
2460 }
2461 }
2462
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002463 // Check if the freeform window overlaps with the navigation bar area.
2464 final WindowState navBarWin = hasNavigationBar() ? mNavigationBar : null;
2465 if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode()
2466 && isOverlappingWithNavBar(win, navBarWin)) {
2467 mIsFreeformWindowOverlappingWithNavBar = true;
2468 }
2469
Tiger Huang7c610aa2018-10-27 00:01:01 +08002470 // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2471 // docked stack.
2472 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2473 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2474 mTopDockedOpaqueOrDimmingWindowState = win;
2475 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002476 }
2477
2478 /**
2479 * Called following layout of all windows and after policy has been applied
2480 * to each window. If in this function you do
2481 * something that may have modified the animation state of another window,
2482 * be sure to return non-zero in order to perform another pass through layout.
2483 *
2484 * @return Return any bit set of
2485 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2486 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2487 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2488 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2489 */
2490 public int finishPostLayoutPolicyLw() {
2491 int changes = 0;
2492 boolean topIsFullscreen = false;
2493
2494 // If we are not currently showing a dream then remember the current
2495 // lockscreen state. We will use this to determine whether the dream
2496 // started while the lockscreen was showing and remember this state
2497 // while the dream is showing.
2498 if (!mShowingDream) {
2499 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2500 if (mDreamingSleepTokenNeeded) {
2501 mDreamingSleepTokenNeeded = false;
2502 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2503 }
2504 } else {
2505 if (!mDreamingSleepTokenNeeded) {
2506 mDreamingSleepTokenNeeded = true;
2507 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2508 }
2509 }
2510
2511 if (mStatusBar != null) {
2512 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
2513 + " forcefkg=" + mForceStatusBarFromKeyguard
2514 + " top=" + mTopFullscreenOpaqueWindowState);
2515 boolean shouldBeTransparent = mForceStatusBarTransparent
2516 && !mForceStatusBar
2517 && !mForceStatusBarFromKeyguard;
2518 if (!shouldBeTransparent) {
2519 mStatusBarController.setShowTransparent(false /* transparent */);
2520 } else if (!mStatusBar.isVisibleLw()) {
2521 mStatusBarController.setShowTransparent(true /* transparent */);
2522 }
2523
2524 boolean statusBarForcesShowingNavigation =
2525 (mStatusBar.getAttrs().privateFlags
2526 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
2527 boolean topAppHidesStatusBar = topAppHidesStatusBar();
2528 if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
2529 || statusBarForcesShowingNavigation) {
2530 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2531 if (mStatusBarController.setBarShowingLw(true)) {
2532 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2533 }
2534 // Maintain fullscreen layout until incoming animation is complete.
2535 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
2536 // Transient status bar is not allowed if status bar is on lockscreen or status bar
2537 // is expecting the navigation keys from the user.
2538 if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
2539 && mStatusBarController.isTransientShowing()) {
2540 mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2541 mLastSystemUiFlags, mLastSystemUiFlags);
2542 }
2543 } else if (mTopFullscreenOpaqueWindowState != null) {
2544 topIsFullscreen = topAppHidesStatusBar;
2545 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2546 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2547 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
2548 // case though.
2549 if (mStatusBarController.isTransientShowing()) {
2550 if (mStatusBarController.setBarShowingLw(true)) {
2551 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2552 }
2553 } else if (topIsFullscreen
Tiger Huang7c610aa2018-10-27 00:01:01 +08002554 && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2555 if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2556 if (mStatusBarController.setBarShowingLw(false)) {
2557 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2558 } else {
2559 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2560 }
2561 } else {
2562 if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2563 if (mStatusBarController.setBarShowingLw(true)) {
2564 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2565 }
2566 topAppHidesStatusBar = false;
2567 }
2568 }
2569 mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2570 }
2571
2572 if (mTopIsFullscreen != topIsFullscreen) {
2573 if (!topIsFullscreen) {
2574 // Force another layout when status bar becomes fully shown.
2575 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2576 }
2577 mTopIsFullscreen = topIsFullscreen;
2578 }
2579
2580 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2581 // If the navigation bar has been hidden or shown, we need to do another
2582 // layout pass to update that window.
2583 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2584 }
2585
2586 if (mShowingDream != mLastShowingDream) {
2587 mLastShowingDream = mShowingDream;
2588 mService.notifyShowingDreamChanged();
2589 }
2590
2591 updateWindowSleepToken();
2592
2593 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2594 return changes;
2595 }
2596
2597 private void updateWindowSleepToken() {
2598 if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2599 mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2600 mHandler.post(mAcquireSleepTokenRunnable);
2601 } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2602 mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2603 mHandler.post(mReleaseSleepTokenRunnable);
2604 }
2605 mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2606 }
2607
2608 /**
2609 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2610 * window.
2611 */
2612 private boolean topAppHidesStatusBar() {
hyok.kim332ccfc2019-07-02 15:39:43 +09002613 if (mTopFullscreenOpaqueWindowState == null || mForceShowSystemBars) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002614 return false;
2615 }
2616 final int fl = PolicyControl.getWindowFlags(null,
2617 mTopFullscreenOpaqueWindowState.getAttrs());
Adam Pardyl8c2d19c2019-09-16 17:15:38 +02002618 if (WindowManagerDebugConfig.DEBUG) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002619 Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2620 Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2621 + " lp.flags=0x" + Integer.toHexString(fl));
2622 }
2623 return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2624 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2625 }
2626
2627 /**
Winson Chungda20fec2019-04-10 12:19:59 -07002628 * Called when the user is switched.
2629 */
2630 public void switchUser() {
2631 updateCurrentUserResources();
2632 }
2633
2634 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002635 * Called when the resource overlays change.
2636 */
2637 public void onOverlayChangedLw() {
Winson Chungda20fec2019-04-10 12:19:59 -07002638 updateCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002639 onConfigurationChanged();
Jeff Changb0a061e2019-03-11 11:39:54 +08002640 mSystemGestures.onConfigurationChanged();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002641 }
2642
2643 /**
2644 * Called when the configuration has changed, and it's safe to load new values from resources.
2645 */
2646 public void onConfigurationChanged() {
2647 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2648
Winson Chungda20fec2019-04-10 12:19:59 -07002649 final Resources res = getCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002650 final int portraitRotation = displayRotation.getPortraitRotation();
2651 final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2652 final int landscapeRotation = displayRotation.getLandscapeRotation();
2653 final int seascapeRotation = displayRotation.getSeascapeRotation();
Matthew Nga7f24bc2019-04-09 17:06:41 -07002654 final int uiMode = mService.mPolicy.getUiMode();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002655
Louis Changfc64c832018-12-04 11:38:26 +08002656 if (hasStatusBar()) {
2657 mStatusBarHeightForRotation[portraitRotation] =
2658 mStatusBarHeightForRotation[upsideDownRotation] =
2659 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2660 mStatusBarHeightForRotation[landscapeRotation] =
2661 mStatusBarHeightForRotation[seascapeRotation] =
2662 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2663 } else {
2664 mStatusBarHeightForRotation[portraitRotation] =
2665 mStatusBarHeightForRotation[upsideDownRotation] =
2666 mStatusBarHeightForRotation[landscapeRotation] =
2667 mStatusBarHeightForRotation[seascapeRotation] = 0;
2668 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002669
2670 // Height of the navigation bar when presented horizontally at bottom
2671 mNavigationBarHeightForRotationDefault[portraitRotation] =
2672 mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2673 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2674 mNavigationBarHeightForRotationDefault[landscapeRotation] =
2675 mNavigationBarHeightForRotationDefault[seascapeRotation] =
2676 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2677
Matthew Nga7f24bc2019-04-09 17:06:41 -07002678 // Height of the navigation bar frame when presented horizontally at bottom
2679 mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2680 mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2681 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2682 mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2683 mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2684 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2685
Tiger Huang7c610aa2018-10-27 00:01:01 +08002686 // Width of the navigation bar when presented vertically along one side
2687 mNavigationBarWidthForRotationDefault[portraitRotation] =
2688 mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2689 mNavigationBarWidthForRotationDefault[landscapeRotation] =
2690 mNavigationBarWidthForRotationDefault[seascapeRotation] =
2691 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2692
2693 if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2694 // Height of the navigation bar when presented horizontally at bottom
2695 mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2696 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2697 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2698 mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2699 mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2700 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2701
2702 // Width of the navigation bar when presented vertically along one side
2703 mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2704 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2705 mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2706 mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2707 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2708 }
2709
Winson Chung4723b4e2019-03-25 16:49:36 -07002710 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002711 mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
2712 mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
Winson Chung36941632019-04-19 15:21:38 -07002713 mNavigationBarAlwaysShowOnSideGesture =
2714 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
Winson Chung4723b4e2019-03-25 16:49:36 -07002715
Matthew Nga7f24bc2019-04-09 17:06:41 -07002716 // This should calculate how much above the frame we accept gestures.
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002717 mBottomGestureAdditionalInset =
Matthew Nga7f24bc2019-04-09 17:06:41 -07002718 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002719 - getNavigationBarFrameHeight(portraitRotation, uiMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002720
Winson Chung4723b4e2019-03-25 16:49:36 -07002721 updateConfigurationAndScreenSizeDependentBehaviors();
2722 }
2723
2724 void updateConfigurationAndScreenSizeDependentBehaviors() {
Winson Chungda20fec2019-04-10 12:19:59 -07002725 final Resources res = getCurrentUserResources();
Winson Chung4723b4e2019-03-25 16:49:36 -07002726 mNavigationBarCanMove =
2727 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2728 && res.getBoolean(R.bool.config_navBarCanMove);
Riddle Hsuccf09402019-08-13 00:33:06 +08002729 mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002730 }
2731
Winson Chungda20fec2019-04-10 12:19:59 -07002732 /**
2733 * Updates the current user's resources to pick up any changes for the current user (including
2734 * overlay paths)
2735 */
2736 private void updateCurrentUserResources() {
2737 final int userId = mService.mAmInternal.getCurrentUserId();
2738 final Context uiContext = getSystemUiContext();
Winson Chung203e1522019-05-02 15:42:22 -07002739
2740 if (userId == UserHandle.USER_SYSTEM) {
2741 // Skip the (expensive) recreation of resources for the system user below and just
2742 // use the resources from the system ui context
2743 mCurrentUserResources = uiContext.getResources();
2744 return;
2745 }
2746
2747 // For non-system users, ensure that the resources are loaded from the current
2748 // user's package info (see ContextImpl.createDisplayContext)
Winson Chungda20fec2019-04-10 12:19:59 -07002749 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2750 uiContext.getPackageName(), null, 0, userId);
Winson Chungda20fec2019-04-10 12:19:59 -07002751 mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2752 pi.getResDir(),
2753 null /* splitResDirs */,
2754 pi.getOverlayDirs(),
2755 pi.getApplicationInfo().sharedLibraryFiles,
2756 mDisplayContent.getDisplayId(),
2757 null /* overrideConfig */,
2758 uiContext.getResources().getCompatibilityInfo(),
2759 null /* classLoader */);
2760 }
2761
Tiger Huang7c610aa2018-10-27 00:01:01 +08002762 @VisibleForTesting
Winson Chungda20fec2019-04-10 12:19:59 -07002763 Resources getCurrentUserResources() {
2764 if (mCurrentUserResources == null) {
2765 updateCurrentUserResources();
2766 }
2767 return mCurrentUserResources;
2768 }
2769
2770 @VisibleForTesting
2771 Context getContext() {
2772 return mContext;
2773 }
2774
Charles Chen173ae782019-11-11 20:39:02 +08002775 Context getSystemUiContext() {
2776 return mUiContext;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002777 }
2778
2779 private int getNavigationBarWidth(int rotation, int uiMode) {
2780 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2781 return mNavigationBarWidthForRotationInCarMode[rotation];
2782 } else {
2783 return mNavigationBarWidthForRotationDefault[rotation];
2784 }
2785 }
2786
Charles Chen3dedec32019-01-24 22:19:37 +08002787 void notifyDisplayReady() {
wilsonshih643bf132019-02-27 12:49:19 +08002788 mHandler.post(() -> {
2789 final int displayId = getDisplayId();
2790 getStatusBarManagerInternal().onDisplayReady(displayId);
Felipe Leme34a861a2019-08-05 16:00:12 -07002791 final WallpaperManagerInternal wpMgr = LocalServices
2792 .getService(WallpaperManagerInternal.class);
2793 if (wpMgr != null) {
2794 wpMgr.onDisplayReady(displayId);
2795 }
wilsonshih643bf132019-02-27 12:49:19 +08002796 });
Charles Chen3dedec32019-01-24 22:19:37 +08002797 }
2798
Tiger Huang7c610aa2018-10-27 00:01:01 +08002799 /**
2800 * Return the display width available after excluding any screen
2801 * decorations that could never be removed in Honeycomb. That is, system bar or
2802 * button bar.
2803 */
2804 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2805 DisplayCutout displayCutout) {
2806 int width = fullWidth;
2807 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002808 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2809 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002810 width -= getNavigationBarWidth(rotation, uiMode);
2811 }
2812 }
2813 if (displayCutout != null) {
2814 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2815 }
2816 return width;
2817 }
2818
2819 private int getNavigationBarHeight(int rotation, int uiMode) {
2820 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2821 return mNavigationBarHeightForRotationInCarMode[rotation];
2822 } else {
2823 return mNavigationBarHeightForRotationDefault[rotation];
2824 }
2825 }
2826
2827 /**
Matthew Nga7f24bc2019-04-09 17:06:41 -07002828 * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2829 * is used for spacing to show additional buttons on the navigation bar (such as the ime
2830 * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2831 * height that we send to the app as content insets that can be smaller.
2832 * <p>
2833 * In car mode it will return the same height as {@link #getNavigationBarHeight}
2834 *
2835 * @param rotation specifies rotation to return dimension from
2836 * @param uiMode to determine if in car mode
2837 * @return navigation bar frame height
2838 */
2839 private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2840 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2841 return mNavigationBarHeightForRotationInCarMode[rotation];
2842 } else {
2843 return mNavigationBarFrameHeightForRotationDefault[rotation];
2844 }
2845 }
2846
2847 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002848 * Return the display height available after excluding any screen
2849 * decorations that could never be removed in Honeycomb. That is, system bar or
2850 * button bar.
2851 */
2852 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2853 DisplayCutout displayCutout) {
2854 int height = fullHeight;
2855 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002856 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2857 if (navBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002858 height -= getNavigationBarHeight(rotation, uiMode);
2859 }
2860 }
2861 if (displayCutout != null) {
2862 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2863 }
2864 return height;
2865 }
2866
2867 /**
2868 * Return the available screen width that we should report for the
2869 * configuration. This must be no larger than
2870 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2871 * than that to account for more transient decoration like a status bar.
2872 */
2873 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2874 DisplayCutout displayCutout) {
2875 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2876 }
2877
2878 /**
2879 * Return the available screen height that we should report for the
2880 * configuration. This must be no larger than
2881 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2882 * than that to account for more transient decoration like a status bar.
2883 */
2884 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2885 DisplayCutout displayCutout) {
2886 // There is a separate status bar at the top of the display. We don't count that as part
2887 // of the fixed decor, since it can hide; however, for purposes of configurations,
2888 // we do want to exclude it since applications can't generally use that part
2889 // of the screen.
2890 int statusBarHeight = mStatusBarHeightForRotation[rotation];
2891 if (displayCutout != null) {
2892 // If there is a cutout, it may already have accounted for some part of the status
2893 // bar height.
2894 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2895 }
2896 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2897 - statusBarHeight;
2898 }
2899
Tiger Huang43b8fc22019-04-26 11:49:29 +08002900 /**
2901 * Return corner radius in pixels that should be used on windows in order to cover the display.
2902 * The radius is only valid for built-in displays since the one who configures window corner
2903 * radius cannot know the corner radius of non-built-in display.
2904 */
2905 float getWindowCornerRadius() {
2906 return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN
2907 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2908 }
2909
Tiger Huang7c610aa2018-10-27 00:01:01 +08002910 boolean isShowingDreamLw() {
2911 return mShowingDream;
2912 }
2913
2914 /**
Riddle Hsu61987bc2019-04-03 13:08:47 +08002915 * Calculates the stable insets if we already have the non-decor insets.
2916 *
2917 * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2918 * @param rotation The current display rotation.
2919 */
2920 void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2921 inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2922 }
2923
2924 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002925 * Calculates the stable insets without running a layout.
2926 *
2927 * @param displayRotation the current display rotation
2928 * @param displayWidth the current display width
2929 * @param displayHeight the current display height
2930 * @param displayCutout the current display cutout
2931 * @param outInsets the insets to return
2932 */
2933 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2934 DisplayCutout displayCutout, Rect outInsets) {
2935 outInsets.setEmpty();
2936
2937 // Navigation bar and status bar.
2938 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
Riddle Hsu61987bc2019-04-03 13:08:47 +08002939 convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002940 }
2941
2942 /**
2943 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2944 * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2945 *
2946 * @param displayRotation the current display rotation
2947 * @param displayWidth the current display width
2948 * @param displayHeight the current display height
2949 * @param displayCutout the current display cutout
2950 * @param outInsets the insets to return
2951 */
2952 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2953 DisplayCutout displayCutout, Rect outInsets) {
2954 outInsets.setEmpty();
2955
2956 // Only navigation bar
2957 if (hasNavigationBar()) {
2958 final int uiMode = mService.mPolicy.getUiMode();
2959 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2960 if (position == NAV_BAR_BOTTOM) {
2961 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2962 } else if (position == NAV_BAR_RIGHT) {
2963 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2964 } else if (position == NAV_BAR_LEFT) {
2965 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2966 }
2967 }
2968
2969 if (displayCutout != null) {
2970 outInsets.left += displayCutout.getSafeInsetLeft();
2971 outInsets.top += displayCutout.getSafeInsetTop();
2972 outInsets.right += displayCutout.getSafeInsetRight();
2973 outInsets.bottom += displayCutout.getSafeInsetBottom();
2974 }
2975 }
2976
Issei Suzukia5dbf522019-02-01 17:58:15 +01002977 /**
2978 * @see IWindowManager#setForwardedInsets
2979 */
2980 public void setForwardedInsets(@NonNull Insets forwardedInsets) {
2981 mForwardedInsets = forwardedInsets;
2982 }
2983
2984 @NonNull
2985 public Insets getForwardedInsets() {
2986 return mForwardedInsets;
2987 }
2988
Tiger Huang7c610aa2018-10-27 00:01:01 +08002989 @NavigationBarPosition
2990 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
2991 if (navigationBarCanMove() && displayWidth > displayHeight) {
2992 if (displayRotation == Surface.ROTATION_270) {
2993 return NAV_BAR_LEFT;
2994 } else if (displayRotation == Surface.ROTATION_90) {
2995 return NAV_BAR_RIGHT;
2996 }
2997 }
2998 return NAV_BAR_BOTTOM;
2999 }
3000
3001 /**
3002 * @return The side of the screen where navigation bar is positioned.
3003 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
3004 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
3005 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
3006 */
3007 @NavigationBarPosition
3008 public int getNavBarPosition() {
3009 return mNavigationBarPosition;
3010 }
3011
3012 /**
3013 * A new window has been focused.
3014 */
3015 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
3016 mFocusedWindow = newFocus;
3017 mLastFocusedWindow = lastFocus;
Issei Suzuki9f840c72018-12-07 15:09:30 -08003018 if (mDisplayContent.isDefaultDisplay) {
3019 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
3020 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003021 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
3022 // If the navigation bar has been hidden or shown, we need to do another
3023 // layout pass to update that window.
3024 return FINISH_LAYOUT_REDO_LAYOUT;
3025 }
3026 return 0;
3027 }
3028
3029 /**
3030 * Return true if it is okay to perform animations for an app transition
3031 * that is about to occur. You may return false for this if, for example,
3032 * the dream window is currently displayed so the switch should happen
3033 * immediately.
3034 */
3035 public boolean allowAppAnimationsLw() {
3036 return !mShowingDream;
3037 }
3038
3039 private void updateDreamingSleepToken(boolean acquire) {
3040 if (acquire) {
3041 final int displayId = getDisplayId();
3042 if (mDreamingSleepToken == null) {
3043 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
3044 "DreamOnDisplay" + displayId, displayId);
3045 }
3046 } else {
3047 if (mDreamingSleepToken != null) {
3048 mDreamingSleepToken.release();
3049 mDreamingSleepToken = null;
3050 }
3051 }
3052 }
3053
3054 private void requestTransientBars(WindowState swipeTarget) {
3055 synchronized (mLock) {
3056 if (!mService.mPolicy.isUserSetupComplete()) {
3057 // Swipe-up for navigation bar is disabled during setup
3058 return;
3059 }
Jorim Jaggi956ca412019-01-07 14:49:14 +01003060 if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
3061 if (swipeTarget == mNavigationBar
Tiger Huang332793b2019-10-29 23:21:27 +08003062 && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
Jorim Jaggi956ca412019-01-07 14:49:14 +01003063 // Don't show status bar when swiping on already visible navigation bar
Tiger Huang7c610aa2018-10-27 00:01:01 +08003064 return;
3065 }
Jorim Jaggi956ca412019-01-07 14:49:14 +01003066 final InsetsControlTarget controlTarget =
3067 swipeTarget.getControllableInsetProvider().getControlTarget();
3068 if (controlTarget == null) {
3069 return;
3070 }
3071 if (controlTarget.canShowTransient()) {
3072 mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
Tiger Huang332793b2019-10-29 23:21:27 +08003073 new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
Jorim Jaggi956ca412019-01-07 14:49:14 +01003074 } else {
Tiger Huang4a7835f2019-11-06 00:07:56 +08003075 controlTarget.showInsets(Type.systemBars(), false);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003076 }
3077 } else {
3078 boolean sb = mStatusBarController.checkShowTransientBarLw();
3079 boolean nb = mNavigationBarController.checkShowTransientBarLw()
3080 && !isNavBarEmpty(mLastSystemUiFlags);
3081 if (sb || nb) {
3082 // Don't show status bar when swiping on already visible navigation bar
3083 if (!nb && swipeTarget == mNavigationBar) {
3084 if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
3085 return;
3086 }
3087 if (sb) mStatusBarController.showTransient();
3088 if (nb) mNavigationBarController.showTransient();
3089 updateSystemUiVisibilityLw();
3090 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003091 mImmersiveModeConfirmation.confirmCurrentPrompt();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003092 }
3093 }
3094 }
3095
3096 private void disposeInputConsumer(InputConsumer inputConsumer) {
3097 if (inputConsumer != null) {
3098 inputConsumer.dismiss();
3099 }
3100 }
3101
3102 private boolean isStatusBarKeyguard() {
3103 return mStatusBar != null
3104 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
3105 }
3106
3107 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());
3139 winCandidate = isStatusBarKeyguard() ? mStatusBar
3140 : lastFocusCanReceiveKeys ? mLastFocusedWindow
3141 : mTopFullscreenOpaqueWindowState;
3142 if (winCandidate == null) {
3143 return 0;
3144 }
3145 }
3146 final WindowState win = winCandidate;
3147 if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) {
3148 // We are updating at a point where the keyguard has gotten
3149 // focus, but we were last in a state where the top window is
3150 // hiding it. This is probably because the keyguard as been
3151 // shown while the top window was displayed, so we want to ignore
3152 // it here because this is just a very transient change and it
3153 // will quickly lose focus once it correctly gets hidden.
3154 return 0;
3155 }
3156
Jorim Jaggi28620472019-01-02 23:21:49 +01003157 mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
Jorim Jaggib6030952018-10-23 18:31:52 +02003158
Tiger Huang7c610aa2018-10-27 00:01:01 +08003159 int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
3160 & ~mResettingSystemUiFlags
3161 & ~mForceClearedSystemUiFlags;
3162 if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
3163 tmpVisibility
3164 &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
3165 }
3166
Jorim Jaggi956ca412019-01-07 14:49:14 +01003167 final int fullscreenAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
3168 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
3169 final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */,
3170 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003171 mService.getStackBounds(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003172 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003173 final boolean inSplitScreen = !mDockedStackBounds.isEmpty();
3174 mService.getStackBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
3175 : WINDOWING_MODE_FULLSCREEN,
Tiger Huangd5f0b9a2019-10-10 10:34:57 +02003176 ACTIVITY_TYPE_UNDEFINED, mNonDockedStackBounds);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003177 final Pair<Integer, Boolean> result =
3178 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
3179 final int visibility = result.first;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003180 final int appearance = win.mAttrs.insetsFlags.appearance
3181 | InsetsFlags.getAppearance(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003182 final int diff = visibility ^ mLastSystemUiFlags;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003183 final InsetsPolicy insetsPolicy = getInsetsPolicy();
3184 final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
3185 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) != 0
3186 || (PolicyControl.getWindowFlags(win, win.mAttrs) & FLAG_FULLSCREEN) != 0
Tiger Huang332793b2019-10-29 23:21:27 +08003187 || (mStatusBar != null && insetsPolicy.isHidden(ITYPE_STATUS_BAR))
Jorim Jaggi956ca412019-01-07 14:49:14 +01003188 || (mNavigationBar != null && insetsPolicy.isHidden(
Tiger Huang332793b2019-10-29 23:21:27 +08003189 ITYPE_NAVIGATION_BAR));
Jorim Jaggi956ca412019-01-07 14:49:14 +01003190 final int behavior = win.mAttrs.insetsFlags.behavior;
3191 final boolean isImmersive = (visibility & (View.SYSTEM_UI_FLAG_IMMERSIVE
3192 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)) != 0
3193 || behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
3194 || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003195 if (diff == 0
Jorim Jaggi956ca412019-01-07 14:49:14 +01003196 && mLastAppearance == appearance
3197 && mLastFullscreenAppearance == fullscreenAppearance
3198 && mLastDockedAppearance == dockedAppearance
Tiger Huang4a7835f2019-11-06 00:07:56 +08003199 && mLastBehavior == behavior
Jorim Jaggi956ca412019-01-07 14:49:14 +01003200 && mLastFocusIsFullscreen == isFullscreen
3201 && mLastFocusIsImmersive == isImmersive
Tiger Huang7c610aa2018-10-27 00:01:01 +08003202 && mFocusedApp == win.getAppToken()
3203 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
3204 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
3205 return 0;
3206 }
Tiger Huang0dbd5372019-10-26 00:24:22 +08003207
3208 // Obtains which types should show transient and which types should abort transient.
3209 // If there is no transient state change, this pair will contain two empty arrays.
3210 final Pair<int[], int[]> transientState = getTransientState(visibility, mLastSystemUiFlags);
3211
Tiger Huang7c610aa2018-10-27 00:01:01 +08003212 mLastSystemUiFlags = visibility;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003213 mLastAppearance = appearance;
3214 mLastFullscreenAppearance = fullscreenAppearance;
3215 mLastDockedAppearance = dockedAppearance;
Tiger Huang4a7835f2019-11-06 00:07:56 +08003216 mLastBehavior = behavior;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003217 mLastFocusIsFullscreen = isFullscreen;
3218 mLastFocusIsImmersive = isImmersive;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003219 mFocusedApp = win.getAppToken();
Riddle Hsu4d6a63f2019-03-29 19:14:43 +08003220 mLastNonDockedStackBounds.set(mNonDockedStackBounds);
3221 mLastDockedStackBounds.set(mDockedStackBounds);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003222 final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
3223 final Rect dockedStackBounds = new Rect(mDockedStackBounds);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003224 final AppearanceRegion[] appearanceRegions = inSplitScreen
3225 ? new AppearanceRegion[]{
3226 new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds),
3227 new AppearanceRegion(dockedAppearance, dockedStackBounds)}
3228 : new AppearanceRegion[]{
3229 new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds)};
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003230 final boolean isNavbarColorManagedByIme = result.second;
Vishnu Nair015d8cd2019-11-18 15:56:30 -08003231 String cause = win.toString();
Tiger Huang7c610aa2018-10-27 00:01:01 +08003232 mHandler.post(() -> {
3233 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
3234 if (statusBar != null) {
3235 final int displayId = getDisplayId();
Tiger Huang0dbd5372019-10-26 00:24:22 +08003236 statusBar.setDisableFlags(displayId, visibility & StatusBarManager.DISABLE_MASK,
Vishnu Nair015d8cd2019-11-18 15:56:30 -08003237 cause);
Tiger Huang0dbd5372019-10-26 00:24:22 +08003238 if (transientState.first.length > 0) {
3239 statusBar.showTransient(displayId, transientState.first);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003240 }
Tiger Huang0dbd5372019-10-26 00:24:22 +08003241 if (transientState.second.length > 0) {
3242 statusBar.abortTransient(displayId, transientState.second);
3243 }
3244 statusBar.onSystemBarAppearanceChanged(displayId, appearance,
3245 appearanceRegions, isNavbarColorManagedByIme);
Jorim Jaggi956ca412019-01-07 14:49:14 +01003246 statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive);
3247
3248 // TODO(b/118118435): Remove this after removing system UI visibilities.
Vishnu Nair015d8cd2019-11-18 15:56:30 -08003249 synchronized (mLock) {
3250 mDisplayContent.statusBarVisibilityChanged(
3251 visibility & ~(View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE));
3252 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003253 }
3254 });
3255 return diff;
3256 }
3257
Tiger Huang0dbd5372019-10-26 00:24:22 +08003258 private static Pair<int[], int[]> getTransientState(int vis, int oldVis) {
3259 final IntArray typesToShow = new IntArray(0);
3260 final IntArray typesToAbort = new IntArray(0);
Tiger Huang332793b2019-10-29 23:21:27 +08003261 updateTransientState(vis, oldVis, View.STATUS_BAR_TRANSIENT, ITYPE_STATUS_BAR, typesToShow,
Tiger Huang0dbd5372019-10-26 00:24:22 +08003262 typesToAbort);
3263 updateTransientState(vis, oldVis, View.NAVIGATION_BAR_TRANSIENT,
Tiger Huang332793b2019-10-29 23:21:27 +08003264 ITYPE_NAVIGATION_BAR, typesToShow, typesToAbort);
Tiger Huang0dbd5372019-10-26 00:24:22 +08003265 return Pair.create(typesToShow.toArray(), typesToAbort.toArray());
Tiger Huang7c610aa2018-10-27 00:01:01 +08003266 }
3267
Tiger Huang0dbd5372019-10-26 00:24:22 +08003268 private static void updateTransientState(int vis, int oldVis, int transientFlag,
Tiger Huang332793b2019-10-29 23:21:27 +08003269 @InternalInsetsType int type, IntArray typesToShow, IntArray typesToAbort) {
Tiger Huang0dbd5372019-10-26 00:24:22 +08003270 final boolean wasTransient = (oldVis & transientFlag) != 0;
3271 final boolean isTransient = (vis & transientFlag) != 0;
3272 if (!wasTransient && isTransient) {
3273 typesToShow.add(type);
3274 } else if (wasTransient && !isTransient) {
3275 typesToAbort.add(type);
3276 }
3277 }
3278
3279 private int updateLightStatusBarAppearanceLw(@Appearance int appearance, WindowState opaque,
Jorim Jaggi956ca412019-01-07 14:49:14 +01003280 WindowState opaqueOrDimming) {
3281 final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded();
3282 final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
3283 if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
3284 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
3285 // its light flag.
Tiger Huang332793b2019-10-29 23:21:27 +08003286 appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
Tiger Huang0dbd5372019-10-26 00:24:22 +08003287 final int legacyAppearance = InsetsFlags.getAppearance(
3288 PolicyControl.getSystemUiVisibility(statusColorWin, null));
3289 appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance)
Tiger Huang332793b2019-10-29 23:21:27 +08003290 & APPEARANCE_LIGHT_STATUS_BARS;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003291 } else if (statusColorWin != null && statusColorWin.isDimming()) {
3292 // Otherwise if it's dimming, clear the light flag.
Tiger Huang332793b2019-10-29 23:21:27 +08003293 appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
Jorim Jaggi956ca412019-01-07 14:49:14 +01003294 }
3295 return appearance;
3296 }
3297
Tiger Huang7c610aa2018-10-27 00:01:01 +08003298 @VisibleForTesting
3299 @Nullable
3300 static WindowState chooseNavigationColorWindowLw(WindowState opaque,
3301 WindowState opaqueOrDimming, WindowState imeWindow,
3302 @NavigationBarPosition int navBarPosition) {
3303 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
3304 // window can be navigation color window.
3305 final boolean imeWindowCanNavColorWindow = imeWindow != null
3306 && imeWindow.isVisibleLw()
3307 && navBarPosition == NAV_BAR_BOTTOM
3308 && (PolicyControl.getWindowFlags(imeWindow, null)
3309 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3310
3311 if (opaque != null && opaqueOrDimming == opaque) {
3312 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
3313 // unless IME window is also eligible, since currently the IME window is always show
3314 // above the opaque fullscreen app window, regardless of the IME target window.
3315 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
3316 return imeWindowCanNavColorWindow ? imeWindow : opaque;
3317 }
3318
3319 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
3320 // No dimming window is involved. Determine the result only with the IME window.
3321 return imeWindowCanNavColorWindow ? imeWindow : null;
3322 }
3323
3324 if (!imeWindowCanNavColorWindow) {
3325 // No IME window is involved. Determine the result only with opaqueOrDimming.
3326 return opaqueOrDimming;
3327 }
3328
3329 // The IME window and the dimming window are competing. Check if the dimming window can be
3330 // IME target or not.
3331 if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3332 // The IME window is above the dimming window.
3333 return imeWindow;
3334 } else {
3335 // The dimming window is above the IME window.
3336 return opaqueOrDimming;
3337 }
3338 }
3339
3340 @VisibleForTesting
3341 static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3342 WindowState imeWindow, WindowState navColorWin) {
3343
3344 if (navColorWin != null) {
3345 if (navColorWin == imeWindow || navColorWin == opaque) {
3346 // Respect the light flag.
3347 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3348 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3349 & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3350 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3351 // Clear the light flag for dimming window.
3352 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3353 }
3354 }
3355 return vis;
3356 }
3357
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003358 private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003359 final boolean dockedStackVisible =
3360 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3361 final boolean freeformStackVisible =
3362 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3363 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3364
3365 // We need to force system bars when the docked stack is visible, when the freeform stack
hyok.kim332ccfc2019-07-02 15:39:43 +09003366 // is focused but also when we are resizing for the transitions when docked stack
Tiger Huang7c610aa2018-10-27 00:01:01 +08003367 // visibility changes.
hyok.kim332ccfc2019-07-02 15:39:43 +09003368 mForceShowSystemBars = dockedStackVisible || win.inFreeformWindowingMode() || resizing
Brad Stenninge0573692019-03-11 13:52:46 -07003369 || mForceShowSystemBarsFromExternal;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003370 final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
3371
3372 // apply translucent bar vis flags
3373 WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded()
3374 ? mStatusBar
3375 : mTopFullscreenOpaqueWindowState;
3376 vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3377 vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
Adrian Roosfaba4062019-05-14 15:27:17 +02003378 int dockedVis = mStatusBarController.applyTranslucentFlagLw(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003379 mTopDockedOpaqueWindowState, 0, 0);
Adrian Roosfaba4062019-05-14 15:27:17 +02003380 dockedVis = mNavigationBarController.applyTranslucentFlagLw(
3381 mTopDockedOpaqueWindowState, dockedVis, 0);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003382
3383 final boolean fullscreenDrawsStatusBarBackground =
3384 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3385 final boolean dockedDrawsStatusBarBackground =
3386 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003387 final boolean fullscreenDrawsNavBarBackground =
3388 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
Adrian Roosfaba4062019-05-14 15:27:17 +02003389 final boolean dockedDrawsNavigationBarBackground =
3390 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003391
3392 // prevent status bar interaction from clearing certain flags
3393 int type = win.getAttrs().type;
3394 boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
3395 if (statusBarHasFocus && !isStatusBarKeyguard()) {
3396 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3397 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3398 | View.SYSTEM_UI_FLAG_IMMERSIVE
3399 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3400 | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3401 if (isKeyguardOccluded()) {
3402 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3403 }
3404 vis = (vis & ~flags) | (oldVis & flags);
3405 }
3406
3407 if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3408 vis |= View.STATUS_BAR_TRANSPARENT;
3409 vis &= ~View.STATUS_BAR_TRANSLUCENT;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003410 } else if (forceOpaqueStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003411 vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3412 }
3413
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003414 vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003415 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003416
3417 // update status bar
3418 boolean immersiveSticky =
3419 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3420 final boolean hideStatusBarWM =
3421 mTopFullscreenOpaqueWindowState != null
3422 && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3423 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3424 final boolean hideStatusBarSysui =
3425 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3426 final boolean hideNavBarSysui =
3427 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3428
3429 final boolean transientStatusBarAllowed = mStatusBar != null
3430 && (statusBarHasFocus || (!mForceShowSystemBars
3431 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3432
3433 final boolean transientNavBarAllowed = mNavigationBar != null
3434 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3435
3436 final long now = SystemClock.uptimeMillis();
3437 final boolean pendingPanic = mPendingPanicGestureUptime != 0
3438 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3439 final DisplayPolicy defaultDisplayPolicy =
3440 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
3441 if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
3442 // TODO (b/111955725): Show keyguard presentation on all external displays
3443 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3444 // The user performed the panic gesture recently, we're about to hide the bars,
3445 // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3446 mPendingPanicGestureUptime = 0;
3447 mStatusBarController.showTransient();
3448 if (!isNavBarEmpty(vis)) {
3449 mNavigationBarController.showTransient();
3450 }
3451 }
3452
3453 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3454 && !transientStatusBarAllowed && hideStatusBarSysui;
3455 final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3456 && !transientNavBarAllowed;
3457 if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3458 // clear the clearable flags instead
3459 clearClearableFlagsLw();
3460 vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3461 }
3462
3463 final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3464 immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3465 final boolean navAllowedHidden = immersive || immersiveSticky;
3466
3467 if (hideNavBarSysui && !navAllowedHidden
3468 && mService.mPolicy.getWindowLayerLw(win)
3469 > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3470 // We can't hide the navbar from this window otherwise the input consumer would not get
3471 // the input events.
3472 vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3473 }
3474
3475 vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3476
3477 // update navigation bar
3478 boolean oldImmersiveMode = isImmersiveMode(oldVis);
3479 boolean newImmersiveMode = isImmersiveMode(vis);
3480 if (oldImmersiveMode != newImmersiveMode) {
3481 final String pkg = win.getOwningPackage();
3482 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3483 mService.mPolicy.isUserSetupComplete(),
3484 isNavBarEmpty(win.getSystemUiVisibility()));
3485 }
3486
3487 vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3488
3489 final WindowState navColorWin = chooseNavigationColorWindowLw(
3490 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3491 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3492 vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3493 mTopFullscreenOpaqueOrDimmingWindowState,
3494 mDisplayContent.mInputMethodWindow, navColorWin);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003495 // Navbar color is controlled by the IME.
3496 final boolean isManagedByIme =
3497 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003498
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003499 return Pair.create(vis, isManagedByIme);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003500 }
3501
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003502 private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
3503 int translucentFlag) {
3504 if (!controller.isTransparentAllowed(win)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003505 return false;
3506 }
3507 if (win == null) {
3508 return true;
3509 }
3510
3511 final boolean drawsSystemBars =
3512 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3513 final boolean forceDrawsSystemBars =
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003514 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003515
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003516 return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
3517 }
3518
3519 private boolean drawsStatusBarBackground(int vis, WindowState win) {
3520 return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
3521 }
3522
3523 private boolean drawsNavigationBarBackground(int vis, WindowState win) {
3524 return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003525 }
3526
3527 /**
3528 * @return the current visibility flags with the nav-bar opacity related flags toggled based
3529 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3530 */
3531 private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003532 boolean freeformStackVisible, boolean isDockedDividerResizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003533 boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
3534 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
3535 if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
3536 visibility = setNavBarTransparentFlag(visibility);
3537 } else if (dockedStackVisible) {
3538 visibility = setNavBarOpaqueFlag(visibility);
3539 }
3540 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003541 if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003542 if (mIsFreeformWindowOverlappingWithNavBar) {
3543 visibility = setNavBarTranslucentFlag(visibility);
3544 } else {
3545 visibility = setNavBarOpaqueFlag(visibility);
3546 }
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003547 } else if (fullscreenDrawsBackground) {
3548 visibility = setNavBarTransparentFlag(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003549 }
3550 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3551 if (isDockedDividerResizing) {
3552 visibility = setNavBarOpaqueFlag(visibility);
3553 } else if (freeformStackVisible) {
3554 visibility = setNavBarTranslucentFlag(visibility);
3555 } else {
3556 visibility = setNavBarOpaqueFlag(visibility);
3557 }
3558 }
3559
Tiger Huang7c610aa2018-10-27 00:01:01 +08003560 return visibility;
3561 }
3562
3563 private int setNavBarOpaqueFlag(int visibility) {
3564 return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3565 }
3566
3567 private int setNavBarTranslucentFlag(int visibility) {
3568 visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3569 return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3570 }
3571
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003572 private int setNavBarTransparentFlag(int visibility) {
3573 visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3574 return visibility | View.NAVIGATION_BAR_TRANSPARENT;
3575 }
3576
Tiger Huang7c610aa2018-10-27 00:01:01 +08003577 private void clearClearableFlagsLw() {
3578 int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3579 if (newVal != mResettingSystemUiFlags) {
3580 mResettingSystemUiFlags = newVal;
3581 mDisplayContent.reevaluateStatusBarVisibility();
3582 }
3583 }
3584
3585 private boolean isImmersiveMode(int vis) {
3586 final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3587 return mNavigationBar != null
3588 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3589 && (vis & flags) != 0
3590 && canHideNavigationBar();
3591 }
3592
3593 /**
3594 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3595 */
3596 private boolean canHideNavigationBar() {
3597 return hasNavigationBar();
3598 }
3599
3600 private static boolean isNavBarEmpty(int systemUiFlags) {
3601 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3602 | View.STATUS_BAR_DISABLE_BACK
3603 | View.STATUS_BAR_DISABLE_RECENT);
3604
3605 return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3606 }
3607
Tiger Huang7c610aa2018-10-27 00:01:01 +08003608 private final Runnable mHiddenNavPanic = new Runnable() {
3609 @Override
3610 public void run() {
3611 synchronized (mLock) {
3612 if (!mService.mPolicy.isUserSetupComplete()) {
3613 // Swipe-up for navigation bar is disabled during setup
3614 return;
3615 }
3616 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3617 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3618 mNavigationBarController.showTransient();
Jorim Jaggi956ca412019-01-07 14:49:14 +01003619 mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
Tiger Huang332793b2019-10-29 23:21:27 +08003620 new int[] {ITYPE_NAVIGATION_BAR}));
Tiger Huang7c610aa2018-10-27 00:01:01 +08003621 }
3622 }
3623 }
3624 };
3625
3626 void onPowerKeyDown(boolean isScreenOn) {
3627 // Detect user pressing the power button in panic when an application has
3628 // taken over the whole screen.
3629 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3630 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3631 isNavBarEmpty(mLastSystemUiFlags));
3632 if (panic) {
3633 mHandler.post(mHiddenNavPanic);
3634 }
3635 }
3636
3637 void onVrStateChangedLw(boolean enabled) {
3638 mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3639 }
3640
3641 /**
3642 * Called when the state of lock task mode changes. This should be used to disable immersive
3643 * mode confirmation.
3644 *
3645 * @param lockTaskState the new lock task mode state. One of
3646 * {@link ActivityManager#LOCK_TASK_MODE_NONE},
3647 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3648 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3649 */
3650 public void onLockTaskStateChangedLw(int lockTaskState) {
3651 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3652 }
3653
3654 /**
3655 * Request a screenshot be taken.
3656 *
3657 * @param screenshotType The type of screenshot, for example either
3658 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3659 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3660 */
3661 public void takeScreenshot(int screenshotType) {
3662 if (mScreenshotHelper != null) {
3663 mScreenshotHelper.takeScreenshot(screenshotType,
3664 mStatusBar != null && mStatusBar.isVisibleLw(),
James O'Learyfa5bb7a2019-09-05 13:43:29 -04003665 mNavigationBar != null && mNavigationBar.isVisibleLw(),
3666 mHandler, null /* completionConsumer */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003667 }
3668 }
3669
Ady Abrahamf3e05312019-05-13 18:04:59 -07003670 RefreshRatePolicy getRefreshRatePolicy() {
3671 return mRefreshRatePolicy;
3672 }
3673
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003674 void dump(String prefix, PrintWriter pw) {
Riddle Hsuccf09402019-08-13 00:33:06 +08003675 pw.print(prefix); pw.println("DisplayPolicy");
Tiger Huang7c610aa2018-10-27 00:01:01 +08003676 prefix += " ";
3677 pw.print(prefix);
3678 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3679 pw.print(" mDeskDockEnablesAccelerometer=");
3680 pw.println(mDeskDockEnablesAccelerometer);
3681 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3682 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3683 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3684 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3685 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3686 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3687 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3688 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3689 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3690 || mForceClearedSystemUiFlags != 0) {
3691 pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3692 pw.print(Integer.toHexString(mLastSystemUiFlags));
3693 pw.print(" mResettingSystemUiFlags=0x");
3694 pw.print(Integer.toHexString(mResettingSystemUiFlags));
3695 pw.print(" mForceClearedSystemUiFlags=0x");
3696 pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3697 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003698 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3699 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3700 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3701 if (mStatusBar != null) {
3702 pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
3703 pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard());
3704 }
3705 if (mNavigationBar != null) {
3706 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
Winson Chung4723b4e2019-03-25 16:49:36 -07003707 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
3708 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
3709 pw.print(prefix); pw.print("mNavigationBarPosition=");
3710 pw.println(mNavigationBarPosition);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003711 }
3712 if (mFocusedWindow != null) {
3713 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3714 }
3715 if (mFocusedApp != null) {
3716 pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3717 }
3718 if (mTopFullscreenOpaqueWindowState != null) {
3719 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3720 pw.println(mTopFullscreenOpaqueWindowState);
3721 }
3722 if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3723 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3724 pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3725 }
3726 if (mForcingShowNavBar) {
3727 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3728 pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3729 pw.println(mForcingShowNavBarLayer);
3730 }
Riddle Hsuccf09402019-08-13 00:33:06 +08003731 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003732 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
3733 pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
Riddle Hsuccf09402019-08-13 00:33:06 +08003734 pw.print(prefix); pw.print("mForceShowSystemBarsFromExternal=");
3735 pw.print(mForceShowSystemBarsFromExternal);
3736 pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003737 mStatusBarController.dump(pw, prefix);
3738 mNavigationBarController.dump(pw, prefix);
3739
3740 pw.print(prefix); pw.println("Looper state:");
3741 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003742 }
Arthur Hung20479922019-02-27 17:13:22 +08003743
3744 private boolean supportsPointerLocation() {
3745 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
3746 }
3747
3748 void setPointerLocationEnabled(boolean pointerLocationEnabled) {
3749 if (!supportsPointerLocation()) {
3750 return;
3751 }
3752
3753 mHandler.sendEmptyMessage(pointerLocationEnabled
3754 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
3755 }
3756
3757 private void enablePointerLocation() {
3758 if (mPointerLocationView != null) {
3759 return;
3760 }
3761
3762 mPointerLocationView = new PointerLocationView(mContext);
3763 mPointerLocationView.setPrintCoords(false);
3764 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
3765 WindowManager.LayoutParams.MATCH_PARENT,
3766 WindowManager.LayoutParams.MATCH_PARENT);
3767 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3768 lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
3769 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3770 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3771 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3772 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3773 if (ActivityManager.isHighEndGfx()) {
3774 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3775 lp.privateFlags |=
3776 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3777 }
3778 lp.format = PixelFormat.TRANSLUCENT;
3779 lp.setTitle("PointerLocation - display " + getDisplayId());
3780 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3781 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3782 wm.addView(mPointerLocationView, lp);
3783 mDisplayContent.registerPointerEventListener(mPointerLocationView);
3784 }
3785
3786 private void disablePointerLocation() {
3787 if (mPointerLocationView == null) {
3788 return;
3789 }
3790
3791 mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3792 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3793 wm.removeView(mPointerLocationView);
3794 mPointerLocationView = null;
3795 }
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003796
Arthur Hungfbc8f412019-08-01 19:57:54 +08003797 /**
3798 * Check if the window could be excluded from checking if the display has content.
3799 *
3800 * @param w WindowState to check if should be excluded.
3801 * @return True if the window type is PointerLocation which is excluded.
3802 */
3803 boolean isWindowExcludedFromContent(WindowState w) {
3804 if (w != null && mPointerLocationView != null) {
3805 return w.mClient == mPointerLocationView.getWindowToken();
3806 }
3807
3808 return false;
3809 }
3810
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003811 @VisibleForTesting
3812 static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
3813 if (navBarWindow == null || !navBarWindow.isVisibleLw()
Garfield Tane8d84ab2019-10-11 09:49:40 -07003814 || targetWindow.mActivityRecord == null || !targetWindow.isVisibleLw()) {
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003815 return false;
3816 }
3817
3818 return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw());
3819 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003820}