blob: 61ba69fdf40470a5c55e947e7aa9c0f2a51a8df7 [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_HOME;
20import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
21import 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;
25import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
26import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
27import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
Tiger Huang43b8fc22019-04-26 11:49:29 +080028import static android.view.Display.TYPE_BUILT_IN;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020029import static android.view.InsetsState.TYPE_TOP_BAR;
Adrian Roos11dfd272019-03-25 19:21:26 +010030import static android.view.InsetsState.TYPE_TOP_GESTURES;
31import static android.view.InsetsState.TYPE_TOP_TAPPABLE_ELEMENT;
Jorim Jaggid6490572019-04-16 14:57:56 +020032import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +080033import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
Jorim Jaggi648e5882019-01-24 13:24:02 +010034import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080035import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
36import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
37import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
38import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
39import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
40import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
41import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
42import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
43import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
44import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
45import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
46import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
Adrian Roos11dfd272019-03-25 19:21:26 +010047import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080048import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
49import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
50import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
51import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
Tiger Huang7c610aa2018-10-27 00:01:01 +080052import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
Arthur Hung20479922019-02-27 17:13:22 +080053import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
Jorim Jaggia6aabac2019-03-11 14:23:16 -070054import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
Tiger Huang7c610aa2018-10-27 00:01:01 +080055import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
56import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
57import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
58import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
59import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
60import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
61import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
62import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
63import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
64import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
65import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
66import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
67import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
68import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
69import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
70import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
71import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
72import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
Charles Chen64172bb2019-04-22 17:30:29 +080073import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
Tiger Huang7c610aa2018-10-27 00:01:01 +080074import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
75import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
76import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
77import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
78import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
79import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
80import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
81import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
82import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
83import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
84import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
85import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
86import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
87import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
88import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
89import static android.view.WindowManagerGlobal.ADD_OKAY;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080090import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
91import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080092import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
93import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
94import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
95
96import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
97import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
98import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
99import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
100import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
101import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
102import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800103import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800104import static com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
105import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
106import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800107import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
108import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
109import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800110import static com.android.server.wm.WindowManagerService.localLOGV;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800111
Jorim Jaggi4981f152019-03-26 18:58:45 +0100112import android.Manifest.permission;
Issei Suzukia5dbf522019-02-01 17:58:15 +0100113import android.annotation.NonNull;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800114import android.annotation.Nullable;
Jorim Jaggi4981f152019-03-26 18:58:45 +0100115import android.annotation.Px;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800116import android.app.ActivityManager;
117import android.app.ActivityThread;
Winson Chungda20fec2019-04-10 12:19:59 -0700118import android.app.LoadedApk;
119import android.app.ResourcesManager;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800120import android.app.StatusBarManager;
121import android.content.Context;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800122import android.content.Intent;
Jorim Jaggi4981f152019-03-26 18:58:45 +0100123import android.content.pm.PackageManager;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800124import android.content.res.Resources;
Issei Suzukia5dbf522019-02-01 17:58:15 +0100125import android.graphics.Insets;
Arthur Hung20479922019-02-27 17:13:22 +0800126import android.graphics.PixelFormat;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800127import android.graphics.Rect;
Winson Chung36941632019-04-19 15:21:38 -0700128import android.graphics.Region;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800129import android.hardware.input.InputManager;
130import android.hardware.power.V1_0.PowerHint;
131import android.os.Handler;
132import android.os.Looper;
133import android.os.Message;
134import android.os.SystemClock;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800135import android.os.SystemProperties;
136import android.os.UserHandle;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800137import android.util.ArraySet;
Tarandeep Singhe439dec2019-04-22 12:28:43 -0700138import android.util.Pair;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800139import android.util.PrintWriterPrinter;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800140import android.util.Slog;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800141import android.view.DisplayCutout;
142import android.view.Gravity;
143import android.view.IApplicationToken;
144import android.view.InputChannel;
145import android.view.InputDevice;
146import android.view.InputEvent;
147import android.view.InputEventReceiver;
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200148import android.view.InsetsState;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800149import android.view.MotionEvent;
150import android.view.PointerIcon;
151import android.view.Surface;
152import android.view.View;
Jorim Jaggi648e5882019-01-24 13:24:02 +0100153import android.view.ViewRootImpl;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800154import android.view.WindowManager;
155import android.view.WindowManager.LayoutParams;
156import android.view.WindowManagerGlobal;
157import android.view.WindowManagerPolicyConstants;
158import android.view.accessibility.AccessibilityManager;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800159
Tiger Huang7c610aa2018-10-27 00:01:01 +0800160import com.android.internal.R;
161import com.android.internal.annotations.GuardedBy;
162import com.android.internal.annotations.VisibleForTesting;
Tiger Huang43b8fc22019-04-26 11:49:29 +0800163import com.android.internal.policy.ScreenDecorationsUtils;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800164import com.android.internal.util.ScreenShapeHelper;
165import com.android.internal.util.ScreenshotHelper;
Adrian Roos11dfd272019-03-25 19:21:26 +0100166import com.android.internal.util.function.TriConsumer;
Arthur Hung20479922019-02-27 17:13:22 +0800167import com.android.internal.widget.PointerLocationView;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800168import com.android.server.LocalServices;
169import com.android.server.UiThread;
170import com.android.server.policy.WindowManagerPolicy;
171import com.android.server.policy.WindowManagerPolicy.InputConsumer;
172import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800173import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
174import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800175import com.android.server.policy.WindowOrientationListener;
176import com.android.server.statusbar.StatusBarManagerInternal;
wilsonshih643bf132019-02-27 12:49:19 +0800177import com.android.server.wallpaper.WallpaperManagerInternal;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800178import com.android.server.wm.utils.InsetUtils;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800179
180import java.io.PrintWriter;
181
182/**
183 * The policy that provides the basic behaviors and states of a display to show UI.
184 */
185public class DisplayPolicy {
186 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800187 private static final boolean DEBUG = false;
188
189 private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
190
191 // The panic gesture may become active only after the keyguard is dismissed and the immersive
192 // app shows again. If that doesn't happen for 30s we drop the gesture.
193 private static final long PANIC_GESTURE_EXPIRATION = 30000;
194
195 // Controls navigation bar opacity depending on which workspace stacks are currently
196 // visible.
197 // Nav bar is always opaque when either the freeform stack or docked stack is visible.
198 private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
199 // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
200 private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
Adrian Roosfaba4062019-05-14 15:27:17 +0200201 // Nav bar is never forced opaque.
202 private static final int NAV_BAR_FORCE_TRANSPARENT = 2;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800203
204 /**
205 * These are the system UI flags that, when changing, can cause the layout
206 * of the screen to change.
207 */
208 private static final int SYSTEM_UI_CHANGING_LAYOUT =
209 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
210 | View.SYSTEM_UI_FLAG_FULLSCREEN
211 | View.STATUS_BAR_TRANSLUCENT
212 | View.NAVIGATION_BAR_TRANSLUCENT
213 | View.STATUS_BAR_TRANSPARENT
214 | View.NAVIGATION_BAR_TRANSPARENT;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800215
216 private final WindowManagerService mService;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800217 private final Context mContext;
218 private final DisplayContent mDisplayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800219 private final Object mLock;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800220 private final Handler mHandler;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800221
Winson Chungda20fec2019-04-10 12:19:59 -0700222 private Resources mCurrentUserResources;
223
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800224 private final boolean mCarDockEnablesAccelerometer;
225 private final boolean mDeskDockEnablesAccelerometer;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800226 private final AccessibilityManager mAccessibilityManager;
227 private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
228 private final ScreenshotHelper mScreenshotHelper;
229
230 private final Object mServiceAcquireLock = new Object();
231 private StatusBarManagerInternal mStatusBarManagerInternal;
232
Adrian Roos11dfd272019-03-25 19:21:26 +0100233 @Px
234 private int mBottomGestureAdditionalInset;
235 @Px
236 private int mSideGestureInset;
Adrian Roos11dfd272019-03-25 19:21:26 +0100237
Tiger Huang7c610aa2018-10-27 00:01:01 +0800238 private StatusBarManagerInternal getStatusBarManagerInternal() {
239 synchronized (mServiceAcquireLock) {
240 if (mStatusBarManagerInternal == null) {
241 mStatusBarManagerInternal =
242 LocalServices.getService(StatusBarManagerInternal.class);
243 }
244 return mStatusBarManagerInternal;
245 }
246 }
247
Tiger Huang7c610aa2018-10-27 00:01:01 +0800248 private final SystemGesturesPointerEventListener mSystemGestures;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800249
250 private volatile int mLidState = LID_ABSENT;
251 private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
252 private volatile boolean mHdmiPlugged;
253
Louis Changfc64c832018-12-04 11:38:26 +0800254 private volatile boolean mHasStatusBar;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800255 private volatile boolean mHasNavigationBar;
256 // Can the navigation bar ever move to the side?
257 private volatile boolean mNavigationBarCanMove;
Winson Chung36941632019-04-19 15:21:38 -0700258 private volatile boolean mNavigationBarLetsThroughTaps;
259 private volatile boolean mNavigationBarAlwaysShowOnSideGesture;
Adrian Roosd3b40862019-04-16 15:39:23 +0200260 private volatile boolean mAllowSeamlessRotationDespiteNavBarMoving;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800261
262 // Written by vr manager thread, only read in this class.
263 private volatile boolean mPersistentVrModeEnabled;
264
265 private volatile boolean mAwake;
266 private volatile boolean mScreenOnEarly;
267 private volatile boolean mScreenOnFully;
268 private volatile ScreenOnListener mScreenOnListener;
269
270 private volatile boolean mKeyguardDrawComplete;
271 private volatile boolean mWindowManagerDrawComplete;
272
Tiger Huang7c610aa2018-10-27 00:01:01 +0800273 private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
274 private WindowState mStatusBar = null;
275 private final int[] mStatusBarHeightForRotation = new int[4];
276 private WindowState mNavigationBar = null;
277 @NavigationBarPosition
278 private int mNavigationBarPosition = NAV_BAR_BOTTOM;
279 private int[] mNavigationBarHeightForRotationDefault = new int[4];
280 private int[] mNavigationBarWidthForRotationDefault = new int[4];
281 private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
282 private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
283
Matthew Nga7f24bc2019-04-09 17:06:41 -0700284 /** See {@link #getNavigationBarFrameHeight} */
285 private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
286
HEO SEUNG22d3ec22019-05-30 20:28:53 +0900287 private boolean mIsFreeformWindowOverlappingWithNavBar;
288
Jorim Jaggi4981f152019-03-26 18:58:45 +0100289 /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
290 @Px private int mWindowOutsetBottom;
291
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800292 private final StatusBarController mStatusBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800293
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800294 private final BarController mNavigationBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800295
296 private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
297 new BarController.OnBarVisibilityChangedListener() {
298 @Override
299 public void onBarVisibilityChanged(boolean visible) {
300 if (mAccessibilityManager == null) {
301 return;
302 }
303 mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
304 }
305 };
306
Tiger Huang7c610aa2018-10-27 00:01:01 +0800307 @GuardedBy("mHandler")
308 private SleepToken mDreamingSleepToken;
309
310 @GuardedBy("mHandler")
311 private SleepToken mWindowSleepToken;
312
313 private final Runnable mAcquireSleepTokenRunnable;
314 private final Runnable mReleaseSleepTokenRunnable;
315
316 // The windows we were told about in focusChanged.
317 private WindowState mFocusedWindow;
318 private WindowState mLastFocusedWindow;
319
320 IApplicationToken mFocusedApp;
321
322 int mLastSystemUiFlags;
323 // Bits that we are in the process of clearing, so we want to prevent
324 // them from being set by applications until everything has been updated
325 // to have them clear.
326 private int mResettingSystemUiFlags = 0;
327 // Bits that we are currently always keeping cleared.
328 private int mForceClearedSystemUiFlags = 0;
329 private int mLastFullscreenStackSysUiFlags;
330 private int mLastDockedStackSysUiFlags;
331 private final Rect mNonDockedStackBounds = new Rect();
332 private final Rect mDockedStackBounds = new Rect();
333 private final Rect mLastNonDockedStackBounds = new Rect();
334 private final Rect mLastDockedStackBounds = new Rect();
335
336 // What we last reported to system UI about whether the compatibility
337 // menu needs to be displayed.
338 private boolean mLastFocusNeedsMenu = false;
339 // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
340 private long mPendingPanicGestureUptime;
341
342 private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
343 private static final Rect sTmpRect = new Rect();
344 private static final Rect sTmpDockedFrame = new Rect();
345 private static final Rect sTmpNavFrame = new Rect();
346 private static final Rect sTmpLastParentFrame = new Rect();
347
348 private WindowState mTopFullscreenOpaqueWindowState;
349 private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
350 private WindowState mTopDockedOpaqueWindowState;
351 private WindowState mTopDockedOpaqueOrDimmingWindowState;
352 private boolean mTopIsFullscreen;
353 private boolean mForceStatusBar;
354 private boolean mForceStatusBarFromKeyguard;
355 private boolean mForceStatusBarTransparent;
356 private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
357 private boolean mForcingShowNavBar;
358 private int mForcingShowNavBarLayer;
359 private boolean mForceShowSystemBars;
360
Brad Stenninge0573692019-03-11 13:52:46 -0700361 /**
362 * Force the display of system bars regardless of other settings.
363 */
364 private boolean mForceShowSystemBarsFromExternal;
365
Tiger Huang7c610aa2018-10-27 00:01:01 +0800366 private boolean mShowingDream;
367 private boolean mLastShowingDream;
368 private boolean mDreamingLockscreen;
369 private boolean mDreamingSleepTokenNeeded;
370 private boolean mWindowSleepTokenNeeded;
371 private boolean mLastWindowSleepTokenNeeded;
372 private boolean mAllowLockscreenWhenOn;
373
374 private InputConsumer mInputConsumer = null;
375
Arthur Hung20479922019-02-27 17:13:22 +0800376 private PointerLocationView mPointerLocationView;
377
Issei Suzukia5dbf522019-02-01 17:58:15 +0100378 /**
379 * The area covered by system windows which belong to another display. Forwarded insets is set
380 * in case this is a virtual display, this is displayed on another display that has insets, and
381 * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
382 * displayed on the host display, and it covers a part of this virtual display.)
383 * The forwarded insets is used to compute display frames of this virtual display, which will
384 * be then used to layout windows in the virtual display.
385 */
386 @NonNull private Insets mForwardedInsets = Insets.NONE;
387
Ady Abrahamf3e05312019-05-13 18:04:59 -0700388 private RefreshRatePolicy mRefreshRatePolicy;
389
Tiger Huang7c610aa2018-10-27 00:01:01 +0800390 // -------- PolicyHandler --------
391 private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
392 private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
393 private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
Arthur Hung20479922019-02-27 17:13:22 +0800394 private static final int MSG_ENABLE_POINTER_LOCATION = 4;
395 private static final int MSG_DISABLE_POINTER_LOCATION = 5;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800396
397 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
398 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
399
400 private class PolicyHandler extends Handler {
401
402 PolicyHandler(Looper looper) {
403 super(looper);
404 }
405
406 @Override
407 public void handleMessage(Message msg) {
408 switch (msg.what) {
409 case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
410 updateDreamingSleepToken(msg.arg1 != 0);
411 break;
412 case MSG_REQUEST_TRANSIENT_BARS:
413 WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
414 ? mStatusBar : mNavigationBar;
415 if (targetBar != null) {
416 requestTransientBars(targetBar);
417 }
418 break;
419 case MSG_DISPOSE_INPUT_CONSUMER:
420 disposeInputConsumer((InputConsumer) msg.obj);
421 break;
Arthur Hung20479922019-02-27 17:13:22 +0800422 case MSG_ENABLE_POINTER_LOCATION:
423 enablePointerLocation();
424 break;
425 case MSG_DISABLE_POINTER_LOCATION:
426 disablePointerLocation();
427 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800428 }
429 }
430 }
431
432 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800433 mService = service;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800434 mContext = displayContent.isDefaultDisplay ? service.mContext
435 : service.mContext.createDisplayContext(displayContent.getDisplay());
436 mDisplayContent = displayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800437 mLock = service.getWindowManagerLock();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800438
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800439 final int displayId = displayContent.getDisplayId();
440 mStatusBarController = new StatusBarController(displayId);
441 mNavigationBarController = new BarController("NavigationBar",
442 displayId,
443 View.NAVIGATION_BAR_TRANSIENT,
444 View.NAVIGATION_BAR_UNHIDE,
445 View.NAVIGATION_BAR_TRANSLUCENT,
446 StatusBarManager.WINDOW_NAVIGATION_BAR,
447 FLAG_TRANSLUCENT_NAVIGATION,
448 View.NAVIGATION_BAR_TRANSPARENT);
449
Tiger Huang7c610aa2018-10-27 00:01:01 +0800450 final Resources r = mContext.getResources();
451 mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
452 mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
Brad Stenninge0573692019-03-11 13:52:46 -0700453 mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800454
455 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
456 Context.ACCESSIBILITY_SERVICE);
457 if (!displayContent.isDefaultDisplay) {
458 mAwake = true;
459 mScreenOnEarly = true;
460 mScreenOnFully = true;
461 }
462
463 final Looper looper = UiThread.getHandler().getLooper();
464 mHandler = new PolicyHandler(looper);
465 mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
466 new SystemGesturesPointerEventListener.Callbacks() {
467 @Override
468 public void onSwipeFromTop() {
469 if (mStatusBar != null) {
470 requestTransientBars(mStatusBar);
471 }
472 }
473
474 @Override
475 public void onSwipeFromBottom() {
Winson Chung36941632019-04-19 15:21:38 -0700476 if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800477 requestTransientBars(mNavigationBar);
478 }
479 }
480
481 @Override
482 public void onSwipeFromRight() {
Jeff Chang3cf3e562019-06-18 11:51:25 +0800483 final Region excludedRegion;
484 synchronized (mLock) {
485 excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
486 }
Winson Chung36941632019-04-19 15:21:38 -0700487 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
488 || mNavigationBarPosition == NAV_BAR_RIGHT;
489 if (mNavigationBar != null && sideAllowed
490 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800491 requestTransientBars(mNavigationBar);
492 }
493 }
494
495 @Override
496 public void onSwipeFromLeft() {
Jeff Chang3cf3e562019-06-18 11:51:25 +0800497 final Region excludedRegion;
498 synchronized (mLock) {
499 excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
500 }
Winson Chung36941632019-04-19 15:21:38 -0700501 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
502 || mNavigationBarPosition == NAV_BAR_LEFT;
503 if (mNavigationBar != null && sideAllowed
504 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800505 requestTransientBars(mNavigationBar);
506 }
507 }
508
509 @Override
510 public void onFling(int duration) {
511 if (mService.mPowerManagerInternal != null) {
512 mService.mPowerManagerInternal.powerHint(
513 PowerHint.INTERACTION, duration);
514 }
515 }
516
517 @Override
518 public void onDebug() {
519 // no-op
520 }
521
522 private WindowOrientationListener getOrientationListener() {
523 final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
524 return rotation != null ? rotation.getOrientationListener() : null;
525 }
526
527 @Override
528 public void onDown() {
529 final WindowOrientationListener listener = getOrientationListener();
530 if (listener != null) {
531 listener.onTouchStart();
532 }
533 }
534
535 @Override
536 public void onUpOrCancel() {
537 final WindowOrientationListener listener = getOrientationListener();
538 if (listener != null) {
539 listener.onTouchEnd();
540 }
541 }
542
543 @Override
544 public void onMouseHoverAtTop() {
545 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
546 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
547 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
548 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
549 }
550
551 @Override
552 public void onMouseHoverAtBottom() {
553 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
554 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
555 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
556 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
557 }
558
559 @Override
560 public void onMouseLeaveFromEdge() {
561 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
562 }
563 });
564 displayContent.registerPointerEventListener(mSystemGestures);
565 displayContent.mAppTransition.registerListenerLocked(
566 mStatusBarController.getAppTransitionListener());
567 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
568 mService.mVrModeEnabled);
569 mAcquireSleepTokenRunnable = () -> {
570 if (mWindowSleepToken != null) {
571 return;
572 }
Tiger Huang7c610aa2018-10-27 00:01:01 +0800573 mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
574 "WindowSleepTokenOnDisplay" + displayId, displayId);
575 };
576 mReleaseSleepTokenRunnable = () -> {
577 if (mWindowSleepToken == null) {
578 return;
579 }
580 mWindowSleepToken.release();
581 mWindowSleepToken = null;
582 };
583
584 // TODO: Make it can take screenshot on external display
585 mScreenshotHelper = displayContent.isDefaultDisplay
586 ? new ScreenshotHelper(mContext) : null;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800587
Tiger Huang7c610aa2018-10-27 00:01:01 +0800588 if (mDisplayContent.isDefaultDisplay) {
Louis Changfc64c832018-12-04 11:38:26 +0800589 mHasStatusBar = true;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800590 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800591
Tiger Huang7c610aa2018-10-27 00:01:01 +0800592 // Allow a system property to override this. Used by the emulator.
593 // See also hasNavigationBar().
594 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
595 if ("1".equals(navBarOverride)) {
596 mHasNavigationBar = false;
597 } else if ("0".equals(navBarOverride)) {
598 mHasNavigationBar = true;
599 }
600 } else {
Louis Changfc64c832018-12-04 11:38:26 +0800601 mHasStatusBar = false;
Andrii Kuliandd989612019-02-21 12:13:28 -0800602 mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800603 }
Ady Abrahamf3e05312019-05-13 18:04:59 -0700604
605 mRefreshRatePolicy = new RefreshRatePolicy(mService,
606 mDisplayContent.getDisplayInfo(),
607 mService.mHighRefreshRateBlacklist);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800608 }
609
Charles Chen5bdd3e22018-12-18 17:51:56 +0800610 void systemReady() {
611 mSystemGestures.systemReady();
Arthur Hung20479922019-02-27 17:13:22 +0800612 if (mService.mPointerLocationEnabled) {
613 setPointerLocationEnabled(true);
614 }
Charles Chen5bdd3e22018-12-18 17:51:56 +0800615 }
616
617 private int getDisplayId() {
618 return mDisplayContent.getDisplayId();
619 }
620
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800621 public void setHdmiPlugged(boolean plugged) {
622 setHdmiPlugged(plugged, false /* force */);
623 }
624
625 public void setHdmiPlugged(boolean plugged, boolean force) {
626 if (force || mHdmiPlugged != plugged) {
627 mHdmiPlugged = plugged;
628 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
629 final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
630 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
631 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800632 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800633 }
634 }
635
636 boolean isHdmiPlugged() {
637 return mHdmiPlugged;
638 }
639
640 boolean isCarDockEnablesAccelerometer() {
641 return mCarDockEnablesAccelerometer;
642 }
643
644 boolean isDeskDockEnablesAccelerometer() {
645 return mDeskDockEnablesAccelerometer;
646 }
647
648 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
649 mPersistentVrModeEnabled = persistentVrModeEnabled;
650 }
651
652 public boolean isPersistentVrModeEnabled() {
653 return mPersistentVrModeEnabled;
654 }
655
656 public void setDockMode(int dockMode) {
657 mDockMode = dockMode;
658 }
659
660 public int getDockMode() {
661 return mDockMode;
662 }
663
Brad Stenninge0573692019-03-11 13:52:46 -0700664 /**
665 * @see WindowManagerService.setForceShowSystemBars
666 */
667 void setForceShowSystemBars(boolean forceShowSystemBars) {
668 mForceShowSystemBarsFromExternal = forceShowSystemBars;
669 }
670
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800671 public boolean hasNavigationBar() {
672 return mHasNavigationBar;
673 }
674
Louis Changfc64c832018-12-04 11:38:26 +0800675 public boolean hasStatusBar() {
676 return mHasStatusBar;
677 }
678
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800679 public boolean navigationBarCanMove() {
680 return mNavigationBarCanMove;
681 }
682
683 public void setLidState(int lidState) {
684 mLidState = lidState;
685 }
686
687 public int getLidState() {
688 return mLidState;
689 }
690
691 public void setAwake(boolean awake) {
692 mAwake = awake;
693 }
694
695 public boolean isAwake() {
696 return mAwake;
697 }
698
699 public boolean isScreenOnEarly() {
700 return mScreenOnEarly;
701 }
702
703 public boolean isScreenOnFully() {
704 return mScreenOnFully;
705 }
706
707 public boolean isKeyguardDrawComplete() {
708 return mKeyguardDrawComplete;
709 }
710
711 public boolean isWindowManagerDrawComplete() {
712 return mWindowManagerDrawComplete;
713 }
714
715 public ScreenOnListener getScreenOnListener() {
716 return mScreenOnListener;
717 }
718
719 public void screenTurnedOn(ScreenOnListener screenOnListener) {
720 synchronized (mLock) {
721 mScreenOnEarly = true;
722 mScreenOnFully = false;
723 mKeyguardDrawComplete = false;
724 mWindowManagerDrawComplete = false;
725 mScreenOnListener = screenOnListener;
726 }
727 }
728
729 public void screenTurnedOff() {
730 synchronized (mLock) {
731 mScreenOnEarly = false;
732 mScreenOnFully = false;
733 mKeyguardDrawComplete = false;
734 mWindowManagerDrawComplete = false;
735 mScreenOnListener = null;
736 }
737 }
738
739 /** Return false if we are not awake yet or we have already informed of this event. */
740 public boolean finishKeyguardDrawn() {
741 synchronized (mLock) {
742 if (!mScreenOnEarly || mKeyguardDrawComplete) {
743 return false;
744 }
745
746 mKeyguardDrawComplete = true;
747 mWindowManagerDrawComplete = false;
748 }
749 return true;
750 }
751
752 /** Return false if screen is not turned on or we did already handle this case earlier. */
753 public boolean finishWindowsDrawn() {
754 synchronized (mLock) {
755 if (!mScreenOnEarly || mWindowManagerDrawComplete) {
756 return false;
757 }
758
759 mWindowManagerDrawComplete = true;
760 }
761 return true;
762 }
763
764 /** Return false if it is not ready to turn on. */
765 public boolean finishScreenTurningOn() {
766 synchronized (mLock) {
767 if (DEBUG_SCREEN_ON) Slog.d(TAG,
768 "finishScreenTurningOn: mAwake=" + mAwake
769 + ", mScreenOnEarly=" + mScreenOnEarly
770 + ", mScreenOnFully=" + mScreenOnFully
771 + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
772 + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
773
774 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
775 || (mAwake && !mKeyguardDrawComplete)) {
776 return false;
777 }
778
779 if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on...");
780 mScreenOnListener = null;
781 mScreenOnFully = true;
782 }
783 return true;
784 }
785
Jorim Jaggi4981f152019-03-26 18:58:45 +0100786 private boolean hasStatusBarServicePermission(int pid, int uid) {
787 return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
788 == PackageManager.PERMISSION_GRANTED;
789 }
790
Tiger Huang7c610aa2018-10-27 00:01:01 +0800791 /**
792 * Sanitize the layout parameters coming from a client. Allows the policy
793 * to do things like ensure that windows of a specific type can't take
794 * input focus.
795 *
796 * @param attrs The window layout parameters to be modified. These values
797 * are modified in-place.
798 */
799 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
Jorim Jaggi4981f152019-03-26 18:58:45 +0100800 int callingPid, int callingUid) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800801
802 final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
803 if (mScreenDecorWindows.contains(win)) {
804 if (!isScreenDecor) {
805 // No longer has the flag set, so remove from the set.
806 mScreenDecorWindows.remove(win);
807 }
Jorim Jaggi4981f152019-03-26 18:58:45 +0100808 } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800809 mScreenDecorWindows.add(win);
810 }
811
812 switch (attrs.type) {
813 case TYPE_SYSTEM_OVERLAY:
814 case TYPE_SECURE_SYSTEM_OVERLAY:
815 // These types of windows can't receive input events.
816 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
817 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
818 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
819 break;
820 case TYPE_DREAM:
821 case TYPE_WALLPAPER:
822 // Dreams and wallpapers don't have an app window token and can thus not be
823 // letterboxed. Hence always let them extend under the cutout.
Arthur Hung20479922019-02-27 17:13:22 +0800824 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800825 break;
826 case TYPE_STATUS_BAR:
827
828 // If the Keyguard is in a hidden state (occluded by another window), we force to
829 // remove the wallpaper and keyguard flag so that any change in-flight after setting
830 // the keyguard as occluded wouldn't set these flags again.
831 // See {@link #processKeyguardSetHiddenResultLw}.
832 if (mService.mPolicy.isKeyguardOccluded()) {
833 attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
834 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
835 }
836 break;
837
838 case TYPE_SCREENSHOT:
839 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
840 break;
841
842 case TYPE_TOAST:
843 // While apps should use the dedicated toast APIs to add such windows
844 // it possible legacy apps to add the window directly. Therefore, we
845 // make windows added directly by the app behave as a toast as much
846 // as possible in terms of timeout and animation.
847 if (attrs.hideTimeoutMilliseconds < 0
848 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
849 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
850 }
Rhed Jao406d3a22018-11-30 19:28:58 +0800851 // Accessibility users may need longer timeout duration. This api compares
852 // original timeout with user's preference and return longer one. It returns
853 // original timeout if there's no preference.
854 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
855 (int) attrs.hideTimeoutMilliseconds,
856 AccessibilityManager.FLAG_CONTENT_TEXT);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800857 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
Jeff Changb10fac72019-04-09 17:28:30 +0800858 // Toast can show with below conditions when the screen is locked.
859 if (canToastShowWhenLocked(callingPid)) {
860 attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
861 }
Tiger Huang7c610aa2018-10-27 00:01:01 +0800862 break;
863 }
864
865 if (attrs.type != TYPE_STATUS_BAR) {
866 // The status bar is the only window allowed to exhibit keyguard behavior.
867 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
868 }
869 }
870
871 /**
Jeff Changb10fac72019-04-09 17:28:30 +0800872 * @return {@code true} if the calling activity initiate toast and is visible with
873 * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
874 */
875 boolean canToastShowWhenLocked(int callingPid) {
876 return mDisplayContent.forAllWindows(w -> {
877 return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
878 }, true /* traverseTopToBottom */);
879 }
880
881 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +0800882 * Preflight adding a window to the system.
883 *
884 * Currently enforces that three window types are singletons per display:
885 * <ul>
886 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
887 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
888 * </ul>
889 *
890 * @param win The window to be added
891 * @param attrs Information about the window to be added
892 *
893 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
894 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
895 */
896 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
897
898 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
899 mContext.enforceCallingOrSelfPermission(
900 android.Manifest.permission.STATUS_BAR_SERVICE,
901 "DisplayPolicy");
902 mScreenDecorWindows.add(win);
903 }
904
905 switch (attrs.type) {
906 case TYPE_STATUS_BAR:
907 mContext.enforceCallingOrSelfPermission(
908 android.Manifest.permission.STATUS_BAR_SERVICE,
909 "DisplayPolicy");
910 if (mStatusBar != null) {
911 if (mStatusBar.isAlive()) {
912 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
913 }
914 }
915 mStatusBar = win;
916 mStatusBarController.setWindow(win);
917 if (mDisplayContent.isDefaultDisplay) {
918 mService.mPolicy.setKeyguardCandidateLw(win);
919 }
Adrian Roos11dfd272019-03-25 19:21:26 +0100920 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200921 (displayFrames, windowState, rect) -> {
922 rect.top = 0;
923 rect.bottom = getStatusBarHeight(displayFrames);
Adrian Roos11dfd272019-03-25 19:21:26 +0100924 };
925 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, frameProvider);
926 mDisplayContent.setInsetProvider(TYPE_TOP_GESTURES, win, frameProvider);
927 mDisplayContent.setInsetProvider(TYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800928 break;
929 case TYPE_NAVIGATION_BAR:
930 mContext.enforceCallingOrSelfPermission(
931 android.Manifest.permission.STATUS_BAR_SERVICE,
932 "DisplayPolicy");
933 if (mNavigationBar != null) {
934 if (mNavigationBar.isAlive()) {
935 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
936 }
937 }
938 mNavigationBar = win;
939 mNavigationBarController.setWindow(win);
940 mNavigationBarController.setOnBarVisibilityChangedListener(
941 mNavBarVisibilityListener, true);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200942 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR,
943 win, null /* frameProvider */);
Adrian Roos11dfd272019-03-25 19:21:26 +0100944 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_GESTURES, win,
945 (displayFrames, windowState, inOutFrame) -> {
946 inOutFrame.top -= mBottomGestureAdditionalInset;
947 });
948 mDisplayContent.setInsetProvider(InsetsState.TYPE_LEFT_GESTURES, win,
949 (displayFrames, windowState, inOutFrame) -> {
950 inOutFrame.left = 0;
951 inOutFrame.top = 0;
952 inOutFrame.bottom = displayFrames.mDisplayHeight;
953 inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
954 });
955 mDisplayContent.setInsetProvider(InsetsState.TYPE_RIGHT_GESTURES, win,
956 (displayFrames, windowState, inOutFrame) -> {
957 inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
958 inOutFrame.top = 0;
959 inOutFrame.bottom = displayFrames.mDisplayHeight;
960 inOutFrame.right = displayFrames.mDisplayWidth;
961 });
962 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_TAPPABLE_ELEMENT, win,
963 (displayFrames, windowState, inOutFrame) -> {
964 if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
965 || mNavigationBarLetsThroughTaps) {
966 inOutFrame.setEmpty();
967 }
968 });
Tiger Huang7c610aa2018-10-27 00:01:01 +0800969 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
970 break;
971 case TYPE_NAVIGATION_BAR_PANEL:
972 case TYPE_STATUS_BAR_PANEL:
973 case TYPE_STATUS_BAR_SUB_PANEL:
974 case TYPE_VOICE_INTERACTION_STARTING:
975 mContext.enforceCallingOrSelfPermission(
976 android.Manifest.permission.STATUS_BAR_SERVICE,
977 "DisplayPolicy");
978 break;
979 }
980 return ADD_OKAY;
981 }
982
983 /**
984 * Called when a window is being removed from a window manager. Must not
985 * throw an exception -- clean up as much as possible.
986 *
987 * @param win The window being removed.
988 */
989 public void removeWindowLw(WindowState win) {
990 if (mStatusBar == win) {
991 mStatusBar = null;
992 mStatusBarController.setWindow(null);
993 if (mDisplayContent.isDefaultDisplay) {
994 mService.mPolicy.setKeyguardCandidateLw(null);
995 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200996 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800997 } else if (mNavigationBar == win) {
998 mNavigationBar = null;
999 mNavigationBarController.setWindow(null);
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001000 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001001 }
1002 if (mLastFocusedWindow == win) {
1003 mLastFocusedWindow = null;
1004 }
1005 mScreenDecorWindows.remove(win);
1006 }
1007
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001008 private int getStatusBarHeight(DisplayFrames displayFrames) {
1009 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1010 displayFrames.mDisplayCutoutSafe.top);
1011 }
1012
Tiger Huang7c610aa2018-10-27 00:01:01 +08001013 /**
1014 * Control the animation to run when a window's state changes. Return a
1015 * non-0 number to force the animation to a specific resource ID, or 0
1016 * to use the default animation.
1017 *
1018 * @param win The window that is changing.
1019 * @param transit What is happening to the window:
1020 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1021 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1022 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1023 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1024 *
1025 * @return Resource ID of the actual animation to use, or 0 for none.
1026 */
1027 public int selectAnimationLw(WindowState win, int transit) {
1028 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1029 + ": transit=" + transit);
1030 if (win == mStatusBar) {
1031 final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
1032 final boolean expanded = win.getAttrs().height == MATCH_PARENT
1033 && win.getAttrs().width == MATCH_PARENT;
1034 if (isKeyguard || expanded) {
1035 return -1;
1036 }
1037 if (transit == TRANSIT_EXIT
1038 || transit == TRANSIT_HIDE) {
1039 return R.anim.dock_top_exit;
1040 } else if (transit == TRANSIT_ENTER
1041 || transit == TRANSIT_SHOW) {
1042 return R.anim.dock_top_enter;
1043 }
1044 } else if (win == mNavigationBar) {
1045 if (win.getAttrs().windowAnimations != 0) {
1046 return 0;
1047 }
1048 // This can be on either the bottom or the right or the left.
1049 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1050 if (transit == TRANSIT_EXIT
1051 || transit == TRANSIT_HIDE) {
1052 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1053 return R.anim.dock_bottom_exit_keyguard;
1054 } else {
1055 return R.anim.dock_bottom_exit;
1056 }
1057 } else if (transit == TRANSIT_ENTER
1058 || transit == TRANSIT_SHOW) {
1059 return R.anim.dock_bottom_enter;
1060 }
1061 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1062 if (transit == TRANSIT_EXIT
1063 || transit == TRANSIT_HIDE) {
1064 return R.anim.dock_right_exit;
1065 } else if (transit == TRANSIT_ENTER
1066 || transit == TRANSIT_SHOW) {
1067 return R.anim.dock_right_enter;
1068 }
1069 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1070 if (transit == TRANSIT_EXIT
1071 || transit == TRANSIT_HIDE) {
1072 return R.anim.dock_left_exit;
1073 } else if (transit == TRANSIT_ENTER
1074 || transit == TRANSIT_SHOW) {
1075 return R.anim.dock_left_enter;
1076 }
1077 }
1078 } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
1079 return selectDockedDividerAnimationLw(win, transit);
1080 }
1081
1082 if (transit == TRANSIT_PREVIEW_DONE) {
1083 if (win.hasAppShownWindows()) {
1084 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1085 return R.anim.app_starting_exit;
1086 }
1087 } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
1088 && transit == TRANSIT_ENTER) {
1089 // Special case: we are animating in a dream, while the keyguard
1090 // is shown. We don't want an animation on the dream, because
1091 // we need it shown immediately with the keyguard animating away
1092 // to reveal it.
1093 return -1;
1094 }
1095
1096 return 0;
1097 }
1098
1099 private int selectDockedDividerAnimationLw(WindowState win, int transit) {
1100 int insets = mDisplayContent.getDockedDividerController().getContentInsets();
1101
1102 // If the divider is behind the navigation bar, don't animate.
1103 final Rect frame = win.getFrameLw();
1104 final boolean behindNavBar = mNavigationBar != null
1105 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
1106 && frame.top + insets >= mNavigationBar.getFrameLw().top)
1107 || (mNavigationBarPosition == NAV_BAR_RIGHT
1108 && frame.left + insets >= mNavigationBar.getFrameLw().left)
1109 || (mNavigationBarPosition == NAV_BAR_LEFT
1110 && frame.right - insets <= mNavigationBar.getFrameLw().right));
1111 final boolean landscape = frame.height() > frame.width();
1112 final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
1113 || frame.left + insets >= win.getDisplayFrameLw().right);
1114 final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
1115 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1116 final boolean offscreen = offscreenLandscape || offscreenPortrait;
1117 if (behindNavBar || offscreen) {
1118 return 0;
1119 }
1120 if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1121 return R.anim.fade_in;
1122 } else if (transit == TRANSIT_EXIT) {
1123 return R.anim.fade_out;
1124 } else {
1125 return 0;
1126 }
1127 }
1128
1129 /**
1130 * Determine the animation to run for a rotation transition based on the
1131 * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
1132 * and whether it is currently fullscreen and frontmost.
1133 *
1134 * @param anim The exiting animation resource id is stored in anim[0], the
1135 * entering animation resource id is stored in anim[1].
1136 */
1137 public void selectRotationAnimationLw(int anim[]) {
1138 // If the screen is off or non-interactive, force a jumpcut.
1139 final boolean forceJumpcut = !mScreenOnFully || !mService.mPolicy.okToAnimate();
1140 if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
1141 + mTopFullscreenOpaqueWindowState + " rotationAnimation="
1142 + (mTopFullscreenOpaqueWindowState == null
1143 ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)
1144 + " forceJumpcut=" + forceJumpcut);
1145 if (forceJumpcut) {
1146 anim[0] = R.anim.rotation_animation_jump_exit;
1147 anim[1] = R.anim.rotation_animation_enter;
1148 return;
1149 }
1150 if (mTopFullscreenOpaqueWindowState != null) {
1151 int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint();
1152 if (animationHint < 0 && mTopIsFullscreen) {
1153 animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation;
1154 }
1155 switch (animationHint) {
1156 case ROTATION_ANIMATION_CROSSFADE:
1157 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
1158 anim[0] = R.anim.rotation_animation_xfade_exit;
1159 anim[1] = R.anim.rotation_animation_enter;
1160 break;
1161 case ROTATION_ANIMATION_JUMPCUT:
1162 anim[0] = R.anim.rotation_animation_jump_exit;
1163 anim[1] = R.anim.rotation_animation_enter;
1164 break;
1165 case ROTATION_ANIMATION_ROTATE:
1166 default:
1167 anim[0] = anim[1] = 0;
1168 break;
1169 }
1170 } else {
1171 anim[0] = anim[1] = 0;
1172 }
1173 }
1174
1175 /**
1176 * Validate whether the current top fullscreen has specified the same
1177 * {@link WindowManager.LayoutParams#rotationAnimation} value as that
1178 * being passed in from the previous top fullscreen window.
1179 *
1180 * @param exitAnimId exiting resource id from the previous window.
1181 * @param enterAnimId entering resource id from the previous window.
1182 * @param forceDefault For rotation animations only, if true ignore the
1183 * animation values and just return false.
1184 * @return true if the previous values are still valid, false if they
1185 * should be replaced with the default.
1186 */
1187 public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
1188 boolean forceDefault) {
1189 switch (exitAnimId) {
1190 case R.anim.rotation_animation_xfade_exit:
1191 case R.anim.rotation_animation_jump_exit:
1192 // These are the only cases that matter.
1193 if (forceDefault) {
1194 return false;
1195 }
1196 int anim[] = new int[2];
1197 selectRotationAnimationLw(anim);
1198 return (exitAnimId == anim[0] && enterAnimId == anim[1]);
1199 default:
1200 return true;
1201 }
1202 }
1203
1204 /**
1205 * Called when a new system UI visibility is being reported, allowing
1206 * the policy to adjust what is actually reported.
1207 * @param visibility The raw visibility reported by the status bar.
1208 * @return The new desired visibility.
1209 */
1210 public int adjustSystemUiVisibilityLw(int visibility) {
1211 mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1212 mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1213
1214 // Reset any bits in mForceClearingStatusBarVisibility that
1215 // are now clear.
1216 mResettingSystemUiFlags &= visibility;
1217 // Clear any bits in the new visibility that are currently being
1218 // force cleared, before reporting it.
1219 return visibility & ~mResettingSystemUiFlags
1220 & ~mForceClearedSystemUiFlags;
1221 }
1222
1223 /**
Brad Stenninge0573692019-03-11 13:52:46 -07001224 * @return true if the system bars are forced to stay visible
Tiger Huang7c610aa2018-10-27 00:01:01 +08001225 */
Brad Stenninge0573692019-03-11 13:52:46 -07001226 public boolean areSystemBarsForcedShownLw(WindowState windowState) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001227 return mForceShowSystemBars;
1228 }
1229
1230 // TODO: Should probably be moved into DisplayFrames.
1231 /**
1232 * Return the layout hints for a newly added window. These values are computed on the
1233 * most recent layout, so they are not guaranteed to be correct.
1234 *
1235 * @param attrs The LayoutParams of the window.
1236 * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1237 * associated with the window.
1238 * @param displayFrames display frames.
1239 * @param floatingStack Whether the window's stack is floating.
1240 * @param outFrame The frame of the window.
1241 * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1242 * @param outStableInsets The areas covered by stable system windows irrespective of their
1243 * current visibility. Expressed as positive insets.
1244 * @param outOutsets The areas that are not real display, but we would like to treat as such.
1245 * @param outDisplayCutout The area that has been cut away from the display.
Brad Stenninge0573692019-03-11 13:52:46 -07001246 * @return Whether to always consume the system bars.
1247 * See {@link #areSystemBarsForcedShownLw(WindowState)}.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001248 */
1249 public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1250 DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1251 Rect outContentInsets, Rect outStableInsets,
1252 Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
1253 final int fl = PolicyControl.getWindowFlags(null, attrs);
1254 final int pfl = attrs.privateFlags;
1255 final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1256 final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
1257 final int displayRotation = displayFrames.mRotation;
1258
1259 final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
1260 if (useOutsets) {
Jorim Jaggi4981f152019-03-26 18:58:45 +01001261 int outset = mWindowOutsetBottom;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001262 if (outset > 0) {
1263 if (displayRotation == Surface.ROTATION_0) {
1264 outOutsets.bottom += outset;
1265 } else if (displayRotation == Surface.ROTATION_90) {
1266 outOutsets.right += outset;
1267 } else if (displayRotation == Surface.ROTATION_180) {
1268 outOutsets.top += outset;
1269 } else if (displayRotation == Surface.ROTATION_270) {
1270 outOutsets.left += outset;
1271 }
1272 }
1273 }
1274
1275 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1276 final boolean layoutInScreenAndInsetDecor = layoutInScreen
1277 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1278 final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1279
1280 if (layoutInScreenAndInsetDecor && !screenDecor) {
Jorim Jaggid6490572019-04-16 14:57:56 +02001281 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001282 outFrame.set(displayFrames.mUnrestricted);
1283 } else {
1284 outFrame.set(displayFrames.mRestricted);
1285 }
1286
1287 final Rect sf;
1288 if (floatingStack) {
1289 sf = null;
1290 } else {
1291 sf = displayFrames.mStable;
1292 }
1293
1294 final Rect cf;
1295 if (floatingStack) {
1296 cf = null;
1297 } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1298 if ((fl & FLAG_FULLSCREEN) != 0) {
1299 cf = displayFrames.mStableFullscreen;
1300 } else {
1301 cf = displayFrames.mStable;
1302 }
1303 } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
1304 cf = displayFrames.mOverscan;
1305 } else {
1306 cf = displayFrames.mCurrent;
1307 }
1308
1309 if (taskBounds != null) {
1310 outFrame.intersect(taskBounds);
1311 }
1312 InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1313 InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1314 outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1315 .getDisplayCutout());
1316 return mForceShowSystemBars;
1317 } else {
1318 if (layoutInScreen) {
1319 outFrame.set(displayFrames.mUnrestricted);
1320 } else {
1321 outFrame.set(displayFrames.mStable);
1322 }
1323 if (taskBounds != null) {
1324 outFrame.intersect(taskBounds);
1325 }
1326
1327 outContentInsets.setEmpty();
1328 outStableInsets.setEmpty();
1329 outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1330 return mForceShowSystemBars;
1331 }
1332 }
1333
1334 private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1335 int impliedFlags = 0;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001336 final boolean forceWindowDrawsBarBackgrounds =
1337 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1338 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001339 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001340 || forceWindowDrawsBarBackgrounds) {
Jorim Jaggid6490572019-04-16 14:57:56 +02001341 impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001342 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1343 }
1344 return impliedFlags;
1345 }
1346
1347 private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
1348 return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
1349 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
1350 }
1351
1352 private final Runnable mClearHideNavigationFlag = new Runnable() {
1353 @Override
1354 public void run() {
1355 synchronized (mLock) {
1356 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1357 mDisplayContent.reevaluateStatusBarVisibility();
1358 }
1359 }
1360 };
1361
1362 /**
1363 * Input handler used while nav bar is hidden. Captures any touch on the screen,
1364 * to determine when the nav bar should be shown and prevent applications from
1365 * receiving those touches.
1366 */
1367 private final class HideNavInputEventReceiver extends InputEventReceiver {
1368 HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1369 super(inputChannel, looper);
1370 }
1371
1372 @Override
1373 public void onInputEvent(InputEvent event) {
1374 try {
1375 if (event instanceof MotionEvent
1376 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1377 final MotionEvent motionEvent = (MotionEvent) event;
1378 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1379 // When the user taps down, we re-show the nav bar.
1380 boolean changed = false;
1381 synchronized (mLock) {
1382 if (mInputConsumer == null) {
1383 return;
1384 }
1385 // Any user activity always causes us to show the
1386 // navigation controls, if they had been hidden.
1387 // We also clear the low profile and only content
1388 // flags so that tapping on the screen will atomically
1389 // restore all currently hidden screen decorations.
1390 int newVal = mResettingSystemUiFlags
1391 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1392 | View.SYSTEM_UI_FLAG_LOW_PROFILE
1393 | View.SYSTEM_UI_FLAG_FULLSCREEN;
1394 if (mResettingSystemUiFlags != newVal) {
1395 mResettingSystemUiFlags = newVal;
1396 changed = true;
1397 }
1398 // We don't allow the system's nav bar to be hidden
1399 // again for 1 second, to prevent applications from
1400 // spamming us and keeping it from being shown.
1401 newVal = mForceClearedSystemUiFlags
1402 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1403 if (mForceClearedSystemUiFlags != newVal) {
1404 mForceClearedSystemUiFlags = newVal;
1405 changed = true;
1406 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1407 }
1408 if (changed) {
1409 mDisplayContent.reevaluateStatusBarVisibility();
1410 }
1411 }
1412 }
1413 }
1414 } finally {
1415 finishInputEvent(event, false /* handled */);
1416 }
1417 }
1418 }
1419
1420 /**
1421 * Called when layout of the windows is about to start.
1422 *
1423 * @param displayFrames frames of the display we are doing layout on.
1424 * @param uiMode The current uiMode in configuration.
1425 */
1426 public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1427 displayFrames.onBeginLayout();
1428 mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1429 mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1430
1431 // For purposes of putting out fake window up to steal focus, we will
1432 // drive nav being hidden only by whether it is requested.
1433 final int sysui = mLastSystemUiFlags;
1434 boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
1435 boolean navTranslucent = (sysui
1436 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
1437 boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
1438 boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
1439 boolean navAllowedHidden = immersive || immersiveSticky;
1440 navTranslucent &= !immersiveSticky; // transient trumps translucent
1441 boolean isKeyguardShowing = isStatusBarKeyguard()
1442 && !mService.mPolicy.isKeyguardOccluded();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001443 boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
1444 && (mStatusBar.getAttrs().privateFlags
1445 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1446
1447 // When the navigation bar isn't visible, we put up a fake input window to catch all
1448 // touch events. This way we can detect when the user presses anywhere to bring back the
1449 // nav bar and ensure the application doesn't see the event.
1450 if (navVisible || navAllowedHidden) {
1451 if (mInputConsumer != null) {
1452 mHandler.sendMessage(
1453 mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1454 mInputConsumer = null;
1455 }
1456 } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1457 mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1458 INPUT_CONSUMER_NAVIGATION,
1459 HideNavInputEventReceiver::new,
1460 displayFrames.mDisplayId);
1461 // As long as mInputConsumer is active, hover events are not dispatched to the app
1462 // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1463 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1464 }
1465
1466 // For purposes of positioning and showing the nav bar, if we have decided that it can't
1467 // be hidden (because of the screen aspect ratio), then take that into account.
1468 navVisible |= !canHideNavigationBar();
1469
1470 boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
1471 navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
1472 if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1473 updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1474 if (updateSysUiVisibility) {
1475 updateSystemUiVisibilityLw();
1476 }
1477 layoutScreenDecorWindows(displayFrames);
1478
1479 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1480 // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1481 // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1482 // bar.
1483 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1484 displayFrames.mStable.top);
1485 }
Issei Suzukia5dbf522019-02-01 17:58:15 +01001486
1487 // In case this is a virtual display, and the host display has insets that overlap this
1488 // virtual display, apply the insets of the overlapped area onto the current and content
1489 // frame of this virtual display. This let us layout windows in the virtual display as
1490 // expected when the window needs to avoid overlap with the system windows.
1491 // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1492 // IME.
1493 displayFrames.mCurrent.inset(mForwardedInsets);
1494 displayFrames.mContent.inset(mForwardedInsets);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001495 }
1496
1497 private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1498 if (mScreenDecorWindows.isEmpty()) {
1499 return;
1500 }
1501
1502 sTmpRect.setEmpty();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001503 final int displayId = displayFrames.mDisplayId;
1504 final Rect dockFrame = displayFrames.mDock;
1505 final int displayHeight = displayFrames.mDisplayHeight;
1506 final int displayWidth = displayFrames.mDisplayWidth;
1507
1508 for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1509 final WindowState w = mScreenDecorWindows.valueAt(i);
1510 if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1511 // Skip if not on the same display or not visible.
1512 continue;
1513 }
1514
chaviw0d833762019-06-20 17:09:53 -07001515 w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1516 displayFrames.mUnrestricted /* displayFrame */,
1517 displayFrames.mUnrestricted /* overscanFrame */,
1518 displayFrames.mUnrestricted /* contentFrame */,
1519 displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
1520 displayFrames.mUnrestricted /* stableFrame */,
1521 displayFrames.mUnrestricted /* outsetFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001522 w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1523 w.computeFrameLw();
1524 final Rect frame = w.getFrameLw();
1525
1526 if (frame.left <= 0 && frame.top <= 0) {
1527 // Docked at left or top.
1528 if (frame.bottom >= displayHeight) {
1529 // Docked left.
1530 dockFrame.left = Math.max(frame.right, dockFrame.left);
1531 } else if (frame.right >= displayWidth) {
1532 // Docked top.
1533 dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1534 } else {
1535 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1536 + " not docked on left or top of display. frame=" + frame
1537 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1538 }
1539 } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1540 // Docked at right or bottom.
1541 if (frame.top <= 0) {
1542 // Docked right.
1543 dockFrame.right = Math.min(frame.left, dockFrame.right);
1544 } else if (frame.left <= 0) {
1545 // Docked bottom.
1546 dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1547 } else {
1548 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1549 + " not docked on right or bottom" + " of display. frame=" + frame
1550 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1551 }
1552 } else {
1553 // Screen decor windows are required to be docked on one of the sides of the screen.
1554 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1555 + " not docked on one of the sides of the display. frame=" + frame
1556 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1557 }
1558 }
1559
1560 displayFrames.mRestricted.set(dockFrame);
1561 displayFrames.mCurrent.set(dockFrame);
1562 displayFrames.mVoiceContent.set(dockFrame);
1563 displayFrames.mSystem.set(dockFrame);
1564 displayFrames.mContent.set(dockFrame);
1565 displayFrames.mRestrictedOverscan.set(dockFrame);
1566 }
1567
1568 private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1569 boolean isKeyguardShowing) {
1570 // decide where the status bar goes ahead of time
1571 if (mStatusBar == null) {
1572 return false;
1573 }
1574 // apply any navigation bar insets
1575 sTmpRect.setEmpty();
Jorim Jaggi4981f152019-03-26 18:58:45 +01001576 final WindowFrames windowFrames = mStatusBar.getWindowFrames();
1577 windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001578 displayFrames.mUnrestricted /* displayFrame */,
1579 displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
1580 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
1581 displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
Jorim Jaggi4981f152019-03-26 18:58:45 +01001582 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001583
1584 // Let the status bar determine its size.
1585 mStatusBar.computeFrameLw();
1586
1587 // For layout, the status bar is always at the top with our fixed height.
1588 displayFrames.mStable.top = displayFrames.mUnrestricted.top
1589 + mStatusBarHeightForRotation[displayFrames.mRotation];
1590 // Make sure the status bar covers the entire cutout height
1591 displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1592 displayFrames.mDisplayCutoutSafe.top);
1593
1594 // Tell the bar controller where the collapsed status bar content is
1595 sTmpRect.set(mStatusBar.getContentFrameLw());
1596 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1597 sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
1598 sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
1599 mStatusBarController.setContentFrame(sTmpRect);
1600
1601 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
1602 boolean statusBarTranslucent = (sysui
1603 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001604
1605 // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1606 if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1607 // Status bar may go away, so the screen area it occupies is available to apps but just
1608 // covering them when the status bar is visible.
1609 final Rect dockFrame = displayFrames.mDock;
1610 dockFrame.top = displayFrames.mStable.top;
1611 displayFrames.mContent.set(dockFrame);
1612 displayFrames.mVoiceContent.set(dockFrame);
1613 displayFrames.mCurrent.set(dockFrame);
1614
1615 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1616 "dock=%s content=%s cur=%s", dockFrame.toString(),
1617 displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1618
Jorim Jaggi4981f152019-03-26 18:58:45 +01001619 if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
1620 && !mStatusBar.isAnimatingLw()) {
1621
Tiger Huang7c610aa2018-10-27 00:01:01 +08001622 // If the opaque status bar is currently requested to be visible, and not in the
1623 // process of animating on or off, then we can tell the app that it is covered by
1624 // it.
1625 displayFrames.mSystem.top = displayFrames.mStable.top;
1626 }
1627 }
1628 return mStatusBarController.checkHiddenLw();
1629 }
1630
1631 private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1632 boolean navTranslucent, boolean navAllowedHidden,
1633 boolean statusBarForcesShowingNavigation) {
1634 if (mNavigationBar == null) {
1635 return false;
1636 }
1637
1638 final Rect navigationFrame = sTmpNavFrame;
1639 boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1640 // Force the navigation bar to its appropriate place and size. We need to do this directly,
1641 // instead of relying on it to bubble up from the nav bar, because this needs to change
1642 // atomically with screen rotations.
1643 final int rotation = displayFrames.mRotation;
1644 final int displayHeight = displayFrames.mDisplayHeight;
1645 final int displayWidth = displayFrames.mDisplayWidth;
1646 final Rect dockFrame = displayFrames.mDock;
1647 mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1648
1649 final Rect cutoutSafeUnrestricted = sTmpRect;
1650 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1651 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1652
1653 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1654 // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1655 final int top = cutoutSafeUnrestricted.bottom
1656 - getNavigationBarHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001657 final int topNavBar = cutoutSafeUnrestricted.bottom
Matthew Nga7f24bc2019-04-09 17:06:41 -07001658 - getNavigationBarFrameHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001659 navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001660 displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1661 if (transientNavBarShowing) {
1662 mNavigationBarController.setBarShowingLw(true);
1663 } else if (navVisible) {
1664 mNavigationBarController.setBarShowingLw(true);
1665 dockFrame.bottom = displayFrames.mRestricted.bottom =
1666 displayFrames.mRestrictedOverscan.bottom = top;
1667 } else {
1668 // We currently want to hide the navigation UI - unless we expanded the status bar.
1669 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1670 }
1671 if (navVisible && !navTranslucent && !navAllowedHidden
1672 && !mNavigationBar.isAnimatingLw()
1673 && !mNavigationBarController.wasRecentlyTranslucent()) {
1674 // If the opaque nav bar is currently requested to be visible and not in the process
1675 // of animating on or off, then we can tell the app that it is covered by it.
1676 displayFrames.mSystem.bottom = top;
1677 }
1678 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1679 // Landscape screen; nav bar goes to the right.
1680 final int left = cutoutSafeUnrestricted.right
1681 - getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001682 navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001683 displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1684 if (transientNavBarShowing) {
1685 mNavigationBarController.setBarShowingLw(true);
1686 } else if (navVisible) {
1687 mNavigationBarController.setBarShowingLw(true);
1688 dockFrame.right = displayFrames.mRestricted.right =
1689 displayFrames.mRestrictedOverscan.right = left;
1690 } else {
1691 // We currently want to hide the navigation UI - unless we expanded the status bar.
1692 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1693 }
1694 if (navVisible && !navTranslucent && !navAllowedHidden
1695 && !mNavigationBar.isAnimatingLw()
1696 && !mNavigationBarController.wasRecentlyTranslucent()) {
1697 // If the nav bar is currently requested to be visible, and not in the process of
1698 // animating on or off, then we can tell the app that it is covered by it.
1699 displayFrames.mSystem.right = left;
1700 }
1701 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1702 // Seascape screen; nav bar goes to the left.
1703 final int right = cutoutSafeUnrestricted.left
1704 + getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001705 navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001706 displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1707 if (transientNavBarShowing) {
1708 mNavigationBarController.setBarShowingLw(true);
1709 } else if (navVisible) {
1710 mNavigationBarController.setBarShowingLw(true);
1711 dockFrame.left = displayFrames.mRestricted.left =
1712 displayFrames.mRestrictedOverscan.left = right;
1713 } else {
1714 // We currently want to hide the navigation UI - unless we expanded the status bar.
1715 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1716 }
1717 if (navVisible && !navTranslucent && !navAllowedHidden
1718 && !mNavigationBar.isAnimatingLw()
1719 && !mNavigationBarController.wasRecentlyTranslucent()) {
1720 // If the nav bar is currently requested to be visible, and not in the process of
1721 // animating on or off, then we can tell the app that it is covered by it.
1722 displayFrames.mSystem.left = right;
1723 }
1724 }
1725
1726 // Make sure the content and current rectangles are updated to account for the restrictions
1727 // from the navigation bar.
1728 displayFrames.mCurrent.set(dockFrame);
1729 displayFrames.mVoiceContent.set(dockFrame);
1730 displayFrames.mContent.set(dockFrame);
1731 // And compute the final frame.
1732 sTmpRect.setEmpty();
1733 mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
1734 navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
1735 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1736 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
1737 navigationFrame /* stableFrame */,
1738 displayFrames.mDisplayCutoutSafe /* outsetFrame */);
1739 mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1740 mNavigationBar.computeFrameLw();
1741 mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1742
1743 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1744 return mNavigationBarController.checkHiddenLw();
1745 }
1746
1747 private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
1748 boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
1749 DisplayFrames displayFrames) {
1750 if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1751 // Here's a special case: if the child window is not the 'dock window'
1752 // or input method target, and the window it is attached to is below
1753 // the dock window, then the frames we computed for the window it is
1754 // attached to can not be used because the dock is effectively part
1755 // of the underlying window and the attached window is floating on top
1756 // of the whole thing. So, we ignore the attached window and explicitly
1757 // compute the frames that would be appropriate without the dock.
1758 vf.set(displayFrames.mDock);
1759 cf.set(displayFrames.mDock);
1760 of.set(displayFrames.mDock);
1761 df.set(displayFrames.mDock);
1762 } else {
Jorim Jaggid6490572019-04-16 14:57:56 +02001763
1764 // In case we forced the window to draw behind the navigation bar, restrict df/of to
1765 // DF.RestrictedOverscan to simulate old compat behavior.
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001766 Rect parentDisplayFrame = attached.getDisplayFrameLw();
1767 Rect parentOverscan = attached.getOverscanFrameLw();
Jorim Jaggid6490572019-04-16 14:57:56 +02001768 final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
1769 if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1770 && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1771 && (attachedAttrs.systemUiVisibility
1772 & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001773 parentOverscan = new Rect(parentOverscan);
Jorim Jaggid6490572019-04-16 14:57:56 +02001774 parentOverscan.intersect(displayFrames.mRestrictedOverscan);
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001775 parentDisplayFrame = new Rect(parentDisplayFrame);
Jorim Jaggid6490572019-04-16 14:57:56 +02001776 parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan);
1777 }
1778
Tiger Huang7c610aa2018-10-27 00:01:01 +08001779 // The effective display frame of the attached window depends on whether it is taking
1780 // care of insetting its content. If not, we need to use the parent's content frame so
1781 // that the entire window is positioned within that content. Otherwise we can use the
1782 // overscan frame and let the attached window take care of positioning its content
1783 // appropriately.
1784 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1785 // Set the content frame of the attached window to the parent's decor frame
1786 // (same as content frame when IME isn't present) if specifically requested by
1787 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1788 // Otherwise, use the overscan frame.
1789 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
Jorim Jaggid6490572019-04-16 14:57:56 +02001790 ? attached.getContentFrameLw() : parentOverscan);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001791 } else {
1792 // If the window is resizing, then we want to base the content frame on our attached
1793 // content frame to resize...however, things can be tricky if the attached window is
1794 // NOT in resize mode, in which case its content frame will be larger.
1795 // Ungh. So to deal with that, make sure the content frame we end up using is not
1796 // covering the IM dock.
1797 cf.set(attached.getContentFrameLw());
1798 if (attached.isVoiceInteraction()) {
1799 cf.intersectUnchecked(displayFrames.mVoiceContent);
1800 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1801 cf.intersectUnchecked(displayFrames.mContent);
1802 }
1803 }
Jorim Jaggid6490572019-04-16 14:57:56 +02001804 df.set(insetDecors ? parentDisplayFrame : cf);
1805 of.set(insetDecors ? parentOverscan : cf);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001806 vf.set(attached.getVisibleFrameLw());
1807 }
1808 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1809 // positioned relative to its parent or the entire screen.
1810 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1811 }
1812
1813 private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1814 if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1815 return;
1816 }
1817 // If app is requesting a stable layout, don't let the content insets go below the stable
1818 // values.
1819 if ((fl & FLAG_FULLSCREEN) != 0) {
1820 r.intersectUnchecked(displayFrames.mStableFullscreen);
1821 } else {
1822 r.intersectUnchecked(displayFrames.mStable);
1823 }
1824 }
1825
1826 private boolean canReceiveInput(WindowState win) {
1827 boolean notFocusable =
1828 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1829 boolean altFocusableIm =
1830 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1831 boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1832 return !notFocusableForIm;
1833 }
1834
1835 /**
1836 * Called for each window attached to the window manager as layout is proceeding. The
1837 * implementation of this function must take care of setting the window's frame, either here or
1838 * in finishLayout().
1839 *
1840 * @param win The window being positioned.
1841 * @param attached For sub-windows, the window it is attached to; this
1842 * window will already have had layoutWindow() called on it
1843 * so you can use its Rect. Otherwise null.
1844 * @param displayFrames The display frames.
1845 */
1846 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1847 // We've already done the navigation bar, status bar, and all screen decor windows. If the
1848 // status bar can receive input, we need to layout it again to accommodate for the IME
1849 // window.
1850 if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1851 || mScreenDecorWindows.contains(win)) {
1852 return;
1853 }
1854 final WindowManager.LayoutParams attrs = win.getAttrs();
1855 final boolean isDefaultDisplay = win.isDefaultDisplay();
1856
1857 final int type = attrs.type;
1858 final int fl = PolicyControl.getWindowFlags(win, attrs);
1859 final int pfl = attrs.privateFlags;
1860 final int sim = attrs.softInputMode;
1861 final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1862 final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1863
1864 final WindowFrames windowFrames = win.getWindowFrames();
1865
1866 windowFrames.setHasOutsets(false);
1867 sTmpLastParentFrame.set(windowFrames.mParentFrame);
1868 final Rect pf = windowFrames.mParentFrame;
1869 final Rect df = windowFrames.mDisplayFrame;
1870 final Rect of = windowFrames.mOverscanFrame;
1871 final Rect cf = windowFrames.mContentFrame;
1872 final Rect vf = windowFrames.mVisibleFrame;
1873 final Rect dcf = windowFrames.mDecorFrame;
1874 final Rect sf = windowFrames.mStableFrame;
1875 dcf.setEmpty();
1876 windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1877 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1878
1879 final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1880 && mNavigationBar.isVisibleLw();
1881
1882 final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1883
1884 final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
1885 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
1886
1887 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1888 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1889
1890 sf.set(displayFrames.mStable);
1891
1892 if (type == TYPE_INPUT_METHOD) {
1893 vf.set(displayFrames.mDock);
1894 cf.set(displayFrames.mDock);
1895 of.set(displayFrames.mDock);
1896 df.set(displayFrames.mDock);
1897 windowFrames.mParentFrame.set(displayFrames.mDock);
1898 // IM dock windows layout below the nav bar...
1899 pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
1900 // ...with content insets above the nav bar
1901 cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1902 if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1903 // The status bar forces the navigation bar while it's visible. Make sure the IME
1904 // avoids the navigation bar in that case.
1905 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1906 pf.right = df.right = of.right = cf.right = vf.right =
1907 displayFrames.mStable.right;
1908 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1909 pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
1910 }
1911 }
1912
Matthew Nga7f24bc2019-04-09 17:06:41 -07001913 // In case the navigation bar is on the bottom, we use the frame height instead of the
1914 // regular height for the insets we send to the IME as we need some space to show
1915 // additional buttons in SystemUI when the IME is up.
1916 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1917 final int rotation = displayFrames.mRotation;
1918 final int uimode = mService.mPolicy.getUiMode();
1919 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
1920 - getNavigationBarHeight(rotation, uimode);
1921 if (navHeightOffset > 0) {
1922 cf.bottom -= navHeightOffset;
1923 sf.bottom -= navHeightOffset;
1924 vf.bottom -= navHeightOffset;
1925 dcf.bottom -= navHeightOffset;
1926 }
1927 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001928
1929 // IM dock windows always go to the bottom of the screen.
1930 attrs.gravity = Gravity.BOTTOM;
1931 } else if (type == TYPE_VOICE_INTERACTION) {
1932 of.set(displayFrames.mUnrestricted);
1933 df.set(displayFrames.mUnrestricted);
1934 pf.set(displayFrames.mUnrestricted);
1935 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1936 cf.set(displayFrames.mDock);
1937 } else {
1938 cf.set(displayFrames.mContent);
1939 }
1940 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1941 vf.set(displayFrames.mCurrent);
1942 } else {
1943 vf.set(cf);
1944 }
1945 } else if (type == TYPE_WALLPAPER) {
1946 layoutWallpaper(displayFrames, pf, df, of, cf);
1947 } else if (win == mStatusBar) {
1948 of.set(displayFrames.mUnrestricted);
1949 df.set(displayFrames.mUnrestricted);
1950 pf.set(displayFrames.mUnrestricted);
1951 cf.set(displayFrames.mStable);
1952 vf.set(displayFrames.mStable);
1953
1954 if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
1955 cf.bottom = displayFrames.mContent.bottom;
1956 } else {
1957 cf.bottom = displayFrames.mDock.bottom;
1958 vf.bottom = displayFrames.mContent.bottom;
1959 }
1960 } else {
1961 dcf.set(displayFrames.mSystem);
1962 final boolean inheritTranslucentDecor =
1963 (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
1964 final boolean isAppWindow =
1965 type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1966 final boolean topAtRest =
1967 win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
1968 if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
1969 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
1970 && (fl & FLAG_FULLSCREEN) == 0
1971 && (fl & FLAG_TRANSLUCENT_STATUS) == 0
1972 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001973 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001974 // Ensure policy decor includes status bar
1975 dcf.top = displayFrames.mStable.top;
1976 }
1977 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
1978 && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001979 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1980 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001981 // Ensure policy decor includes navigation bar
1982 dcf.bottom = displayFrames.mStable.bottom;
1983 dcf.right = displayFrames.mStable.right;
1984 }
1985 }
1986
1987 if (layoutInScreen && layoutInsetDecor) {
1988 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1989 + "): IN_SCREEN, INSET_DECOR");
1990 // This is the case for a normal activity window: we want it to cover all of the
1991 // screen space, and it can take care of moving its contents to account for screen
1992 // decorations that intrude into that space.
1993 if (attached != null) {
1994 // If this window is attached to another, our display
1995 // frame is the same as the one we are attached to.
1996 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
1997 displayFrames);
1998 } else {
1999 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2000 // Status bar panels are the only windows who can go on top of the status
2001 // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
2002 // have the same privileges as the status bar itself.
2003 //
2004 // However, they should still dodge the navigation bar if it exists.
2005
2006 pf.left = df.left = of.left = hasNavBar
2007 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
2008 pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
2009 pf.right = df.right = of.right = hasNavBar
2010 ? displayFrames.mRestricted.right
2011 : displayFrames.mUnrestricted.right;
2012 pf.bottom = df.bottom = of.bottom = hasNavBar
2013 ? displayFrames.mRestricted.bottom
2014 : displayFrames.mUnrestricted.bottom;
2015
2016 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
2017 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2018 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2019 // Asking to layout into the overscan region, so give it that pure
2020 // unrestricted area.
2021 of.set(displayFrames.mOverscan);
2022 df.set(displayFrames.mOverscan);
2023 pf.set(displayFrames.mOverscan);
Jorim Jaggid6490572019-04-16 14:57:56 +02002024 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08002025 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
Charles Chen64172bb2019-04-22 17:30:29 +08002026 || type == TYPE_VOLUME_OVERLAY
2027 || type == TYPE_KEYGUARD_DIALOG)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002028 // Asking for layout as if the nav bar is hidden, lets the application
2029 // extend into the unrestricted overscan screen area. We only do this for
2030 // application windows and certain system windows to ensure no window that
2031 // can be above the nav bar can do this.
2032 df.set(displayFrames.mOverscan);
2033 pf.set(displayFrames.mOverscan);
2034 // We need to tell the app about where the frame inside the overscan is, so
2035 // it can inset its content by that amount -- it didn't ask to actually
2036 // extend itself into the overscan region.
2037 of.set(displayFrames.mUnrestricted);
2038 } else {
2039 df.set(displayFrames.mRestrictedOverscan);
2040 pf.set(displayFrames.mRestrictedOverscan);
2041 // We need to tell the app about where the frame inside the overscan
2042 // is, so it can inset its content by that amount -- it didn't ask
2043 // to actually extend itself into the overscan region.
2044 of.set(displayFrames.mUnrestricted);
2045 }
2046
2047 if ((fl & FLAG_FULLSCREEN) == 0) {
2048 if (win.isVoiceInteraction()) {
2049 cf.set(displayFrames.mVoiceContent);
2050 } else {
Jorim Jaggi648e5882019-01-24 13:24:02 +01002051 // IME Insets are handled on the client for ADJUST_RESIZE in the new
2052 // insets world
2053 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2054 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002055 cf.set(displayFrames.mDock);
2056 } else {
2057 cf.set(displayFrames.mContent);
2058 }
2059 }
2060 } else {
2061 // Full screen windows are always given a layout that is as if the status
2062 // bar and other transient decors are gone. This is to avoid bad states when
2063 // moving from a window that is not hiding the status bar to one that is.
2064 cf.set(displayFrames.mRestricted);
2065 }
2066 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2067 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2068 vf.set(displayFrames.mCurrent);
2069 } else {
2070 vf.set(cf);
2071 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002072 }
2073 } else if (layoutInScreen || (sysUiFl
2074 & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Jorim Jaggid6490572019-04-16 14:57:56 +02002075 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002076 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2077 + "): IN_SCREEN");
2078 // A window that has requested to fill the entire screen just
2079 // gets everything, period.
2080 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2081 cf.set(displayFrames.mUnrestricted);
2082 of.set(displayFrames.mUnrestricted);
2083 df.set(displayFrames.mUnrestricted);
2084 pf.set(displayFrames.mUnrestricted);
2085 if (hasNavBar) {
2086 pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
2087 pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
2088 pf.bottom = df.bottom = of.bottom = cf.bottom =
2089 displayFrames.mRestricted.bottom;
2090 }
2091 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
2092 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
2093 // The navigation bar has Real Ultimate Power.
2094 of.set(displayFrames.mUnrestricted);
2095 df.set(displayFrames.mUnrestricted);
2096 pf.set(displayFrames.mUnrestricted);
2097 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
2098 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
2099 && ((fl & FLAG_FULLSCREEN) != 0)) {
2100 // Fullscreen secure system overlays get what they ask for. Screenshot region
2101 // selection overlay should also expand to full screen.
2102 cf.set(displayFrames.mOverscan);
2103 of.set(displayFrames.mOverscan);
2104 df.set(displayFrames.mOverscan);
2105 pf.set(displayFrames.mOverscan);
2106 } else if (type == TYPE_BOOT_PROGRESS) {
2107 // Boot progress screen always covers entire display.
2108 cf.set(displayFrames.mOverscan);
2109 of.set(displayFrames.mOverscan);
2110 df.set(displayFrames.mOverscan);
2111 pf.set(displayFrames.mOverscan);
2112 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2113 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2114 // Asking to layout into the overscan region, so give it that pure unrestricted
2115 // area.
2116 cf.set(displayFrames.mOverscan);
2117 of.set(displayFrames.mOverscan);
2118 df.set(displayFrames.mOverscan);
2119 pf.set(displayFrames.mOverscan);
Jorim Jaggid6490572019-04-16 14:57:56 +02002120 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08002121 && (type == TYPE_STATUS_BAR
2122 || type == TYPE_TOAST
2123 || type == TYPE_DOCK_DIVIDER
2124 || type == TYPE_VOICE_INTERACTION_STARTING
2125 || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
2126 // Asking for layout as if the nav bar is hidden, lets the
2127 // application extend into the unrestricted screen area. We
2128 // only do this for application windows (or toasts) to ensure no window that
2129 // can be above the nav bar can do this.
2130 // XXX This assumes that an app asking for this will also
2131 // ask for layout in only content. We can't currently figure out
2132 // what the screen would be if only laying out to hide the nav bar.
2133 cf.set(displayFrames.mUnrestricted);
2134 of.set(displayFrames.mUnrestricted);
2135 df.set(displayFrames.mUnrestricted);
2136 pf.set(displayFrames.mUnrestricted);
2137 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
2138 of.set(displayFrames.mRestricted);
2139 df.set(displayFrames.mRestricted);
2140 pf.set(displayFrames.mRestricted);
Jorim Jaggi648e5882019-01-24 13:24:02 +01002141
2142 // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2143 // world
2144 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2145 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002146 cf.set(displayFrames.mDock);
2147 } else {
2148 cf.set(displayFrames.mContent);
2149 }
2150 } else {
2151 cf.set(displayFrames.mRestricted);
2152 of.set(displayFrames.mRestricted);
2153 df.set(displayFrames.mRestricted);
2154 pf.set(displayFrames.mRestricted);
2155 }
2156
2157 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2158
2159 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2160 vf.set(displayFrames.mCurrent);
2161 } else {
2162 vf.set(cf);
2163 }
2164 } else if (attached != null) {
2165 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2166 + "): attached to " + attached);
2167 // A child window should be placed inside of the same visible
2168 // frame that its parent had.
2169 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
2170 displayFrames);
2171 } else {
2172 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2173 + "): normal window");
2174 // Otherwise, a normal window must be placed inside the content
2175 // of all screen decorations.
2176 if (type == TYPE_STATUS_BAR_PANEL) {
2177 // Status bar panels can go on
2178 // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2179 // permission, so they have the same privileges as the status bar itself.
2180 cf.set(displayFrames.mRestricted);
2181 of.set(displayFrames.mRestricted);
2182 df.set(displayFrames.mRestricted);
2183 pf.set(displayFrames.mRestricted);
Vishnu Nair9ccb1d22019-03-20 16:32:44 +00002184 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002185 // These dialogs are stable to interim decor changes.
2186 cf.set(displayFrames.mStable);
2187 of.set(displayFrames.mStable);
2188 df.set(displayFrames.mStable);
2189 pf.set(displayFrames.mStable);
2190 } else {
2191 pf.set(displayFrames.mContent);
2192 if (win.isVoiceInteraction()) {
2193 cf.set(displayFrames.mVoiceContent);
2194 of.set(displayFrames.mVoiceContent);
2195 df.set(displayFrames.mVoiceContent);
2196 } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2197 cf.set(displayFrames.mDock);
2198 of.set(displayFrames.mDock);
2199 df.set(displayFrames.mDock);
2200 } else {
2201 cf.set(displayFrames.mContent);
2202 of.set(displayFrames.mContent);
2203 df.set(displayFrames.mContent);
2204 }
2205 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2206 vf.set(displayFrames.mCurrent);
2207 } else {
2208 vf.set(cf);
2209 }
2210 }
2211 }
2212 }
2213
2214 final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2215 final boolean attachedInParent = attached != null && !layoutInScreen;
2216 final boolean requestedHideNavigation =
2217 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
2218
2219 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2220 // cropped / shifted to the displayFrame in WindowState.
2221 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2222 && type != TYPE_BASE_APPLICATION;
2223
2224 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2225 // the cutout safe zone.
Arthur Hung20479922019-02-27 17:13:22 +08002226 if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002227 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2228 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2229 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2230 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2231 // At the top we have the status bar, so apps that are
2232 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2233 // already expect that there's an inset there and we don't need to exclude
2234 // the window from that area.
2235 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2236 }
2237 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2238 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2239 // Same for the navigation bar.
2240 switch (mNavigationBarPosition) {
2241 case NAV_BAR_BOTTOM:
2242 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2243 break;
2244 case NAV_BAR_RIGHT:
2245 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2246 break;
2247 case NAV_BAR_LEFT:
2248 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2249 break;
2250 }
2251 }
2252 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2253 // The IME can always extend under the bottom cutout if the navbar is there.
2254 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2255 }
2256 // Windows that are attached to a parent and laid out in said parent already avoid
2257 // the cutout according to that parent and don't need to be further constrained.
2258 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2259 // They will later be cropped or shifted using the displayFrame in WindowState,
2260 // which prevents overlap with the DisplayCutout.
2261 if (!attachedInParent && !floatingInScreenWindow) {
2262 sTmpRect.set(pf);
2263 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2264 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2265 }
2266 // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2267 // cutout.
2268 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2269 }
2270
2271 // Content should never appear in the cutout.
2272 cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2273
2274 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2275 // Also, we don't allow windows in multi-window mode to extend out of the screen.
2276 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
Evan Rosky4fb1e912019-03-06 13:54:43 -08002277 && !win.inMultiWindowMode()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002278 df.left = df.top = -10000;
2279 df.right = df.bottom = 10000;
2280 if (type != TYPE_WALLPAPER) {
2281 of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
2282 of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
2283 }
2284 }
2285
2286 // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
2287 // need to provide information to the clients that want to pretend that you can draw there.
2288 // We only want to apply outsets to certain types of windows. For example, we never want to
2289 // apply the outsets to floating dialogs, because they wouldn't make sense there.
2290 final boolean useOutsets = shouldUseOutsets(attrs, fl);
2291 if (isDefaultDisplay && useOutsets) {
2292 final Rect osf = windowFrames.mOutsetFrame;
2293 osf.set(cf.left, cf.top, cf.right, cf.bottom);
2294 windowFrames.setHasOutsets(true);
Jorim Jaggi4981f152019-03-26 18:58:45 +01002295 int outset = mWindowOutsetBottom;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002296 if (outset > 0) {
2297 int rotation = displayFrames.mRotation;
2298 if (rotation == Surface.ROTATION_0) {
2299 osf.bottom += outset;
2300 } else if (rotation == Surface.ROTATION_90) {
2301 osf.right += outset;
2302 } else if (rotation == Surface.ROTATION_180) {
2303 osf.top -= outset;
2304 } else if (rotation == Surface.ROTATION_270) {
2305 osf.left -= outset;
2306 }
2307 if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
2308 + " with rotation " + rotation + ", result: " + osf);
2309 }
2310 }
2311
2312 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2313 + ": sim=#" + Integer.toHexString(sim)
2314 + " attach=" + attached + " type=" + type
2315 + String.format(" flags=0x%08x", fl)
2316 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
2317 + " of=" + of.toShortString()
2318 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2319 + " dcf=" + dcf.toShortString()
2320 + " sf=" + sf.toShortString()
2321 + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
2322
2323 if (!sTmpLastParentFrame.equals(pf)) {
2324 windowFrames.setContentChanged(true);
2325 }
2326
2327 win.computeFrameLw();
2328 // Dock windows carve out the bottom of the screen, so normal windows
2329 // can't appear underneath them.
2330 if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2331 && !win.getGivenInsetsPendingLw()) {
2332 offsetInputMethodWindowLw(win, displayFrames);
2333 }
2334 if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2335 && !win.getGivenInsetsPendingLw()) {
2336 offsetVoiceInputWindowLw(win, displayFrames);
2337 }
2338 }
2339
2340 private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
2341 // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
2342 df.set(displayFrames.mOverscan);
2343 pf.set(displayFrames.mOverscan);
2344 cf.set(displayFrames.mUnrestricted);
2345 of.set(displayFrames.mUnrestricted);
2346 }
2347
2348 private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
2349 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2350 top += win.getGivenContentInsetsLw().top;
2351 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
2352 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2353 top = win.getVisibleFrameLw().top;
2354 top += win.getGivenVisibleInsetsLw().top;
2355 displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2356 if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2357 + displayFrames.mDock.bottom + " mContentBottom="
2358 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2359 }
2360
2361 private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2362 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2363 top += win.getGivenContentInsetsLw().top;
2364 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2365 }
2366
2367 /**
2368 * Called following layout of all windows before each window has policy applied.
2369 */
2370 public void beginPostLayoutPolicyLw() {
2371 mTopFullscreenOpaqueWindowState = null;
2372 mTopFullscreenOpaqueOrDimmingWindowState = null;
2373 mTopDockedOpaqueWindowState = null;
2374 mTopDockedOpaqueOrDimmingWindowState = null;
2375 mForceStatusBar = false;
2376 mForceStatusBarFromKeyguard = false;
2377 mForceStatusBarTransparent = false;
2378 mForcingShowNavBar = false;
2379 mForcingShowNavBarLayer = -1;
2380
2381 mAllowLockscreenWhenOn = false;
2382 mShowingDream = false;
2383 mWindowSleepTokenNeeded = false;
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002384 mIsFreeformWindowOverlappingWithNavBar = false;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002385 }
2386
2387 /**
2388 * Called following layout of all window to apply policy to each window.
2389 *
2390 * @param win The window being positioned.
2391 * @param attrs The LayoutParams of the window.
2392 * @param attached For sub-windows, the window it is attached to. Otherwise null.
2393 */
2394 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2395 WindowState attached, WindowState imeTarget) {
2396 final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2397 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2398 mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2399 final int fl = PolicyControl.getWindowFlags(win, attrs);
2400 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2401 && attrs.type == TYPE_INPUT_METHOD) {
2402 mForcingShowNavBar = true;
2403 mForcingShowNavBarLayer = win.getSurfaceLayer();
2404 }
2405 if (attrs.type == TYPE_STATUS_BAR) {
2406 if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
2407 mForceStatusBarFromKeyguard = true;
2408 }
2409 if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
2410 mForceStatusBarTransparent = true;
2411 }
2412 }
2413
2414 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2415 && attrs.type < FIRST_SYSTEM_WINDOW;
2416 final int windowingMode = win.getWindowingMode();
2417 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2418 windowingMode == WINDOWING_MODE_FULLSCREEN
2419 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2420 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2421 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2422 mForceStatusBar = true;
2423 }
2424 if (attrs.type == TYPE_DREAM) {
2425 // If the lockscreen was showing when the dream started then wait
2426 // for the dream to draw before hiding the lockscreen.
2427 if (!mDreamingLockscreen
2428 || (win.isVisibleLw() && win.hasDrawnLw())) {
2429 mShowingDream = true;
2430 appWindow = true;
2431 }
2432 }
2433
2434 // For app windows that are not attached, we decide if all windows in the app they
2435 // represent should be hidden or if we should hide the lockscreen. For attached app
2436 // windows we defer the decision to the window it is attached to.
2437 if (appWindow && attached == null) {
2438 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2439 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2440 mTopFullscreenOpaqueWindowState = win;
2441 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2442 mTopFullscreenOpaqueOrDimmingWindowState = win;
2443 }
2444 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2445 mAllowLockscreenWhenOn = true;
2446 }
2447 }
2448 }
2449 }
2450
2451 // Voice interaction overrides both top fullscreen and top docked.
Jorim Jaggi50150152019-03-27 23:08:58 +01002452 if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002453 if (mTopFullscreenOpaqueWindowState == null) {
2454 mTopFullscreenOpaqueWindowState = win;
2455 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2456 mTopFullscreenOpaqueOrDimmingWindowState = win;
2457 }
2458 }
2459 if (mTopDockedOpaqueWindowState == null) {
2460 mTopDockedOpaqueWindowState = win;
2461 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2462 mTopDockedOpaqueOrDimmingWindowState = win;
2463 }
2464 }
2465 }
2466
2467 // Keep track of the window if it's dimming but not necessarily fullscreen.
2468 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2469 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2470 mTopFullscreenOpaqueOrDimmingWindowState = win;
2471 }
2472
2473 // We need to keep track of the top "fullscreen" opaque window for the docked stack
2474 // separately, because both the "real fullscreen" opaque window and the one for the docked
2475 // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2476 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2477 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2478 mTopDockedOpaqueWindowState = win;
2479 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2480 mTopDockedOpaqueOrDimmingWindowState = win;
2481 }
2482 }
2483
HEO SEUNG22d3ec22019-05-30 20:28:53 +09002484 // Check if the freeform window overlaps with the navigation bar area.
2485 final WindowState navBarWin = hasNavigationBar() ? mNavigationBar : null;
2486 if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode()
2487 && isOverlappingWithNavBar(win, navBarWin)) {
2488 mIsFreeformWindowOverlappingWithNavBar = true;
2489 }
2490
Tiger Huang7c610aa2018-10-27 00:01:01 +08002491 // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2492 // docked stack.
2493 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2494 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2495 mTopDockedOpaqueOrDimmingWindowState = win;
2496 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002497 }
2498
2499 /**
2500 * Called following layout of all windows and after policy has been applied
2501 * to each window. If in this function you do
2502 * something that may have modified the animation state of another window,
2503 * be sure to return non-zero in order to perform another pass through layout.
2504 *
2505 * @return Return any bit set of
2506 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2507 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2508 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2509 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2510 */
2511 public int finishPostLayoutPolicyLw() {
2512 int changes = 0;
2513 boolean topIsFullscreen = false;
2514
2515 // If we are not currently showing a dream then remember the current
2516 // lockscreen state. We will use this to determine whether the dream
2517 // started while the lockscreen was showing and remember this state
2518 // while the dream is showing.
2519 if (!mShowingDream) {
2520 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2521 if (mDreamingSleepTokenNeeded) {
2522 mDreamingSleepTokenNeeded = false;
2523 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2524 }
2525 } else {
2526 if (!mDreamingSleepTokenNeeded) {
2527 mDreamingSleepTokenNeeded = true;
2528 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2529 }
2530 }
2531
2532 if (mStatusBar != null) {
2533 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
2534 + " forcefkg=" + mForceStatusBarFromKeyguard
2535 + " top=" + mTopFullscreenOpaqueWindowState);
2536 boolean shouldBeTransparent = mForceStatusBarTransparent
2537 && !mForceStatusBar
2538 && !mForceStatusBarFromKeyguard;
2539 if (!shouldBeTransparent) {
2540 mStatusBarController.setShowTransparent(false /* transparent */);
2541 } else if (!mStatusBar.isVisibleLw()) {
2542 mStatusBarController.setShowTransparent(true /* transparent */);
2543 }
2544
2545 boolean statusBarForcesShowingNavigation =
2546 (mStatusBar.getAttrs().privateFlags
2547 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
2548 boolean topAppHidesStatusBar = topAppHidesStatusBar();
2549 if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
2550 || statusBarForcesShowingNavigation) {
2551 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2552 if (mStatusBarController.setBarShowingLw(true)) {
2553 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2554 }
2555 // Maintain fullscreen layout until incoming animation is complete.
2556 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
2557 // Transient status bar is not allowed if status bar is on lockscreen or status bar
2558 // is expecting the navigation keys from the user.
2559 if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
2560 && mStatusBarController.isTransientShowing()) {
2561 mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2562 mLastSystemUiFlags, mLastSystemUiFlags);
2563 }
2564 } else if (mTopFullscreenOpaqueWindowState != null) {
2565 topIsFullscreen = topAppHidesStatusBar;
2566 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2567 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2568 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
2569 // case though.
2570 if (mStatusBarController.isTransientShowing()) {
2571 if (mStatusBarController.setBarShowingLw(true)) {
2572 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2573 }
2574 } else if (topIsFullscreen
2575 && !mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM)
2576 && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2577 if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2578 if (mStatusBarController.setBarShowingLw(false)) {
2579 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2580 } else {
2581 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2582 }
2583 } else {
2584 if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2585 if (mStatusBarController.setBarShowingLw(true)) {
2586 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2587 }
2588 topAppHidesStatusBar = false;
2589 }
2590 }
2591 mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2592 }
2593
2594 if (mTopIsFullscreen != topIsFullscreen) {
2595 if (!topIsFullscreen) {
2596 // Force another layout when status bar becomes fully shown.
2597 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2598 }
2599 mTopIsFullscreen = topIsFullscreen;
2600 }
2601
2602 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2603 // If the navigation bar has been hidden or shown, we need to do another
2604 // layout pass to update that window.
2605 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2606 }
2607
2608 if (mShowingDream != mLastShowingDream) {
2609 mLastShowingDream = mShowingDream;
2610 mService.notifyShowingDreamChanged();
2611 }
2612
2613 updateWindowSleepToken();
2614
2615 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2616 return changes;
2617 }
2618
2619 private void updateWindowSleepToken() {
2620 if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2621 mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2622 mHandler.post(mAcquireSleepTokenRunnable);
2623 } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2624 mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2625 mHandler.post(mReleaseSleepTokenRunnable);
2626 }
2627 mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2628 }
2629
2630 /**
2631 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2632 * window.
2633 */
2634 private boolean topAppHidesStatusBar() {
2635 if (mTopFullscreenOpaqueWindowState == null) {
2636 return false;
2637 }
2638 final int fl = PolicyControl.getWindowFlags(null,
2639 mTopFullscreenOpaqueWindowState.getAttrs());
2640 if (localLOGV) {
2641 Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2642 Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2643 + " lp.flags=0x" + Integer.toHexString(fl));
2644 }
2645 return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2646 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2647 }
2648
2649 /**
Winson Chungda20fec2019-04-10 12:19:59 -07002650 * Called when the user is switched.
2651 */
2652 public void switchUser() {
2653 updateCurrentUserResources();
2654 }
2655
2656 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002657 * Called when the resource overlays change.
2658 */
2659 public void onOverlayChangedLw() {
Winson Chungda20fec2019-04-10 12:19:59 -07002660 updateCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002661 onConfigurationChanged();
Jeff Changb0a061e2019-03-11 11:39:54 +08002662 mSystemGestures.onConfigurationChanged();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002663 }
2664
2665 /**
2666 * Called when the configuration has changed, and it's safe to load new values from resources.
2667 */
2668 public void onConfigurationChanged() {
2669 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2670
Winson Chungda20fec2019-04-10 12:19:59 -07002671 final Resources res = getCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002672 final int portraitRotation = displayRotation.getPortraitRotation();
2673 final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2674 final int landscapeRotation = displayRotation.getLandscapeRotation();
2675 final int seascapeRotation = displayRotation.getSeascapeRotation();
Matthew Nga7f24bc2019-04-09 17:06:41 -07002676 final int uiMode = mService.mPolicy.getUiMode();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002677
Louis Changfc64c832018-12-04 11:38:26 +08002678 if (hasStatusBar()) {
2679 mStatusBarHeightForRotation[portraitRotation] =
2680 mStatusBarHeightForRotation[upsideDownRotation] =
2681 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2682 mStatusBarHeightForRotation[landscapeRotation] =
2683 mStatusBarHeightForRotation[seascapeRotation] =
2684 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2685 } else {
2686 mStatusBarHeightForRotation[portraitRotation] =
2687 mStatusBarHeightForRotation[upsideDownRotation] =
2688 mStatusBarHeightForRotation[landscapeRotation] =
2689 mStatusBarHeightForRotation[seascapeRotation] = 0;
2690 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002691
2692 // Height of the navigation bar when presented horizontally at bottom
2693 mNavigationBarHeightForRotationDefault[portraitRotation] =
2694 mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2695 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2696 mNavigationBarHeightForRotationDefault[landscapeRotation] =
2697 mNavigationBarHeightForRotationDefault[seascapeRotation] =
2698 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2699
Matthew Nga7f24bc2019-04-09 17:06:41 -07002700 // Height of the navigation bar frame when presented horizontally at bottom
2701 mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2702 mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2703 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2704 mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2705 mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2706 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2707
Tiger Huang7c610aa2018-10-27 00:01:01 +08002708 // Width of the navigation bar when presented vertically along one side
2709 mNavigationBarWidthForRotationDefault[portraitRotation] =
2710 mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2711 mNavigationBarWidthForRotationDefault[landscapeRotation] =
2712 mNavigationBarWidthForRotationDefault[seascapeRotation] =
2713 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2714
2715 if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2716 // Height of the navigation bar when presented horizontally at bottom
2717 mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2718 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2719 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2720 mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2721 mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2722 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2723
2724 // Width of the navigation bar when presented vertically along one side
2725 mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2726 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2727 mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2728 mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2729 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2730 }
2731
Winson Chung4723b4e2019-03-25 16:49:36 -07002732 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002733 mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
2734 mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
Winson Chung36941632019-04-19 15:21:38 -07002735 mNavigationBarAlwaysShowOnSideGesture =
2736 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
Winson Chung4723b4e2019-03-25 16:49:36 -07002737
Matthew Nga7f24bc2019-04-09 17:06:41 -07002738 // This should calculate how much above the frame we accept gestures.
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002739 mBottomGestureAdditionalInset =
Matthew Nga7f24bc2019-04-09 17:06:41 -07002740 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002741 - getNavigationBarFrameHeight(portraitRotation, uiMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002742
Winson Chung4723b4e2019-03-25 16:49:36 -07002743 updateConfigurationAndScreenSizeDependentBehaviors();
Jorim Jaggi4981f152019-03-26 18:58:45 +01002744 mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
Winson Chung4723b4e2019-03-25 16:49:36 -07002745 }
2746
2747 void updateConfigurationAndScreenSizeDependentBehaviors() {
Winson Chungda20fec2019-04-10 12:19:59 -07002748 final Resources res = getCurrentUserResources();
Winson Chung4723b4e2019-03-25 16:49:36 -07002749 mNavigationBarCanMove =
2750 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2751 && res.getBoolean(R.bool.config_navBarCanMove);
Adrian Roosd3b40862019-04-16 15:39:23 +02002752 mAllowSeamlessRotationDespiteNavBarMoving =
2753 res.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002754 }
2755
Winson Chungda20fec2019-04-10 12:19:59 -07002756 /**
2757 * Updates the current user's resources to pick up any changes for the current user (including
2758 * overlay paths)
2759 */
2760 private void updateCurrentUserResources() {
2761 final int userId = mService.mAmInternal.getCurrentUserId();
2762 final Context uiContext = getSystemUiContext();
Winson Chung203e1522019-05-02 15:42:22 -07002763
2764 if (userId == UserHandle.USER_SYSTEM) {
2765 // Skip the (expensive) recreation of resources for the system user below and just
2766 // use the resources from the system ui context
2767 mCurrentUserResources = uiContext.getResources();
2768 return;
2769 }
2770
2771 // For non-system users, ensure that the resources are loaded from the current
2772 // user's package info (see ContextImpl.createDisplayContext)
Winson Chungda20fec2019-04-10 12:19:59 -07002773 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2774 uiContext.getPackageName(), null, 0, userId);
Winson Chungda20fec2019-04-10 12:19:59 -07002775 mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2776 pi.getResDir(),
2777 null /* splitResDirs */,
2778 pi.getOverlayDirs(),
2779 pi.getApplicationInfo().sharedLibraryFiles,
2780 mDisplayContent.getDisplayId(),
2781 null /* overrideConfig */,
2782 uiContext.getResources().getCompatibilityInfo(),
2783 null /* classLoader */);
2784 }
2785
Tiger Huang7c610aa2018-10-27 00:01:01 +08002786 @VisibleForTesting
Winson Chungda20fec2019-04-10 12:19:59 -07002787 Resources getCurrentUserResources() {
2788 if (mCurrentUserResources == null) {
2789 updateCurrentUserResources();
2790 }
2791 return mCurrentUserResources;
2792 }
2793
2794 @VisibleForTesting
2795 Context getContext() {
2796 return mContext;
2797 }
2798
2799 private Context getSystemUiContext() {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002800 final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
2801 return mDisplayContent.isDefaultDisplay
2802 ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay());
2803 }
2804
2805 private int getNavigationBarWidth(int rotation, int uiMode) {
2806 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2807 return mNavigationBarWidthForRotationInCarMode[rotation];
2808 } else {
2809 return mNavigationBarWidthForRotationDefault[rotation];
2810 }
2811 }
2812
Charles Chen3dedec32019-01-24 22:19:37 +08002813 void notifyDisplayReady() {
wilsonshih643bf132019-02-27 12:49:19 +08002814 mHandler.post(() -> {
2815 final int displayId = getDisplayId();
2816 getStatusBarManagerInternal().onDisplayReady(displayId);
2817 LocalServices.getService(WallpaperManagerInternal.class).onDisplayReady(displayId);
2818 });
Charles Chen3dedec32019-01-24 22:19:37 +08002819 }
2820
Tiger Huang7c610aa2018-10-27 00:01:01 +08002821 /**
2822 * Return the display width available after excluding any screen
2823 * decorations that could never be removed in Honeycomb. That is, system bar or
2824 * button bar.
2825 */
2826 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2827 DisplayCutout displayCutout) {
2828 int width = fullWidth;
2829 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002830 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2831 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002832 width -= getNavigationBarWidth(rotation, uiMode);
2833 }
2834 }
2835 if (displayCutout != null) {
2836 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2837 }
2838 return width;
2839 }
2840
2841 private int getNavigationBarHeight(int rotation, int uiMode) {
2842 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2843 return mNavigationBarHeightForRotationInCarMode[rotation];
2844 } else {
2845 return mNavigationBarHeightForRotationDefault[rotation];
2846 }
2847 }
2848
2849 /**
Matthew Nga7f24bc2019-04-09 17:06:41 -07002850 * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2851 * is used for spacing to show additional buttons on the navigation bar (such as the ime
2852 * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2853 * height that we send to the app as content insets that can be smaller.
2854 * <p>
2855 * In car mode it will return the same height as {@link #getNavigationBarHeight}
2856 *
2857 * @param rotation specifies rotation to return dimension from
2858 * @param uiMode to determine if in car mode
2859 * @return navigation bar frame height
2860 */
2861 private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2862 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2863 return mNavigationBarHeightForRotationInCarMode[rotation];
2864 } else {
2865 return mNavigationBarFrameHeightForRotationDefault[rotation];
2866 }
2867 }
2868
2869 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002870 * Return the display height available after excluding any screen
2871 * decorations that could never be removed in Honeycomb. That is, system bar or
2872 * button bar.
2873 */
2874 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2875 DisplayCutout displayCutout) {
2876 int height = fullHeight;
2877 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002878 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2879 if (navBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002880 height -= getNavigationBarHeight(rotation, uiMode);
2881 }
2882 }
2883 if (displayCutout != null) {
2884 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2885 }
2886 return height;
2887 }
2888
2889 /**
2890 * Return the available screen width that we should report for the
2891 * configuration. This must be no larger than
2892 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2893 * than that to account for more transient decoration like a status bar.
2894 */
2895 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2896 DisplayCutout displayCutout) {
2897 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2898 }
2899
2900 /**
2901 * Return the available screen height that we should report for the
2902 * configuration. This must be no larger than
2903 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2904 * than that to account for more transient decoration like a status bar.
2905 */
2906 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2907 DisplayCutout displayCutout) {
2908 // There is a separate status bar at the top of the display. We don't count that as part
2909 // of the fixed decor, since it can hide; however, for purposes of configurations,
2910 // we do want to exclude it since applications can't generally use that part
2911 // of the screen.
2912 int statusBarHeight = mStatusBarHeightForRotation[rotation];
2913 if (displayCutout != null) {
2914 // If there is a cutout, it may already have accounted for some part of the status
2915 // bar height.
2916 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2917 }
2918 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2919 - statusBarHeight;
2920 }
2921
Tiger Huang43b8fc22019-04-26 11:49:29 +08002922 /**
2923 * Return corner radius in pixels that should be used on windows in order to cover the display.
2924 * The radius is only valid for built-in displays since the one who configures window corner
2925 * radius cannot know the corner radius of non-built-in display.
2926 */
2927 float getWindowCornerRadius() {
2928 return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN
2929 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2930 }
2931
Tiger Huang7c610aa2018-10-27 00:01:01 +08002932 boolean isShowingDreamLw() {
2933 return mShowingDream;
2934 }
2935
2936 /**
Riddle Hsu61987bc2019-04-03 13:08:47 +08002937 * Calculates the stable insets if we already have the non-decor insets.
2938 *
2939 * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2940 * @param rotation The current display rotation.
2941 */
2942 void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2943 inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2944 }
2945
2946 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002947 * Calculates the stable insets without running a layout.
2948 *
2949 * @param displayRotation the current display rotation
2950 * @param displayWidth the current display width
2951 * @param displayHeight the current display height
2952 * @param displayCutout the current display cutout
2953 * @param outInsets the insets to return
2954 */
2955 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2956 DisplayCutout displayCutout, Rect outInsets) {
2957 outInsets.setEmpty();
2958
2959 // Navigation bar and status bar.
2960 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
Riddle Hsu61987bc2019-04-03 13:08:47 +08002961 convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002962 }
2963
2964 /**
2965 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2966 * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2967 *
2968 * @param displayRotation the current display rotation
2969 * @param displayWidth the current display width
2970 * @param displayHeight the current display height
2971 * @param displayCutout the current display cutout
2972 * @param outInsets the insets to return
2973 */
2974 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2975 DisplayCutout displayCutout, Rect outInsets) {
2976 outInsets.setEmpty();
2977
2978 // Only navigation bar
2979 if (hasNavigationBar()) {
2980 final int uiMode = mService.mPolicy.getUiMode();
2981 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2982 if (position == NAV_BAR_BOTTOM) {
2983 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2984 } else if (position == NAV_BAR_RIGHT) {
2985 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2986 } else if (position == NAV_BAR_LEFT) {
2987 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2988 }
2989 }
2990
2991 if (displayCutout != null) {
2992 outInsets.left += displayCutout.getSafeInsetLeft();
2993 outInsets.top += displayCutout.getSafeInsetTop();
2994 outInsets.right += displayCutout.getSafeInsetRight();
2995 outInsets.bottom += displayCutout.getSafeInsetBottom();
2996 }
2997 }
2998
Issei Suzukia5dbf522019-02-01 17:58:15 +01002999 /**
3000 * @see IWindowManager#setForwardedInsets
3001 */
3002 public void setForwardedInsets(@NonNull Insets forwardedInsets) {
3003 mForwardedInsets = forwardedInsets;
3004 }
3005
3006 @NonNull
3007 public Insets getForwardedInsets() {
3008 return mForwardedInsets;
3009 }
3010
Tiger Huang7c610aa2018-10-27 00:01:01 +08003011 @NavigationBarPosition
3012 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
3013 if (navigationBarCanMove() && displayWidth > displayHeight) {
3014 if (displayRotation == Surface.ROTATION_270) {
3015 return NAV_BAR_LEFT;
3016 } else if (displayRotation == Surface.ROTATION_90) {
3017 return NAV_BAR_RIGHT;
3018 }
3019 }
3020 return NAV_BAR_BOTTOM;
3021 }
3022
3023 /**
3024 * @return The side of the screen where navigation bar is positioned.
3025 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
3026 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
3027 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
3028 */
3029 @NavigationBarPosition
3030 public int getNavBarPosition() {
3031 return mNavigationBarPosition;
3032 }
3033
3034 /**
3035 * A new window has been focused.
3036 */
3037 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
3038 mFocusedWindow = newFocus;
3039 mLastFocusedWindow = lastFocus;
Issei Suzuki9f840c72018-12-07 15:09:30 -08003040 if (mDisplayContent.isDefaultDisplay) {
3041 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
3042 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003043 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
3044 // If the navigation bar has been hidden or shown, we need to do another
3045 // layout pass to update that window.
3046 return FINISH_LAYOUT_REDO_LAYOUT;
3047 }
3048 return 0;
3049 }
3050
3051 /**
3052 * Return true if it is okay to perform animations for an app transition
3053 * that is about to occur. You may return false for this if, for example,
3054 * the dream window is currently displayed so the switch should happen
3055 * immediately.
3056 */
3057 public boolean allowAppAnimationsLw() {
3058 return !mShowingDream;
3059 }
3060
3061 private void updateDreamingSleepToken(boolean acquire) {
3062 if (acquire) {
3063 final int displayId = getDisplayId();
3064 if (mDreamingSleepToken == null) {
3065 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
3066 "DreamOnDisplay" + displayId, displayId);
3067 }
3068 } else {
3069 if (mDreamingSleepToken != null) {
3070 mDreamingSleepToken.release();
3071 mDreamingSleepToken = null;
3072 }
3073 }
3074 }
3075
3076 private void requestTransientBars(WindowState swipeTarget) {
3077 synchronized (mLock) {
3078 if (!mService.mPolicy.isUserSetupComplete()) {
3079 // Swipe-up for navigation bar is disabled during setup
3080 return;
3081 }
3082 boolean sb = mStatusBarController.checkShowTransientBarLw();
3083 boolean nb = mNavigationBarController.checkShowTransientBarLw()
3084 && !isNavBarEmpty(mLastSystemUiFlags);
3085 if (sb || nb) {
3086 // Don't show status bar when swiping on already visible navigation bar
3087 if (!nb && swipeTarget == mNavigationBar) {
3088 if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
3089 return;
3090 }
3091 if (sb) mStatusBarController.showTransient();
3092 if (nb) mNavigationBarController.showTransient();
3093 mImmersiveModeConfirmation.confirmCurrentPrompt();
3094 updateSystemUiVisibilityLw();
3095 }
3096 }
3097 }
3098
3099 private void disposeInputConsumer(InputConsumer inputConsumer) {
3100 if (inputConsumer != null) {
3101 inputConsumer.dismiss();
3102 }
3103 }
3104
3105 private boolean isStatusBarKeyguard() {
3106 return mStatusBar != null
3107 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
3108 }
3109
3110 private boolean isKeyguardOccluded() {
3111 // TODO (b/113840485): Handle per display keyguard.
3112 return mService.mPolicy.isKeyguardOccluded();
3113 }
3114
3115 void resetSystemUiVisibilityLw() {
3116 mLastSystemUiFlags = 0;
3117 updateSystemUiVisibilityLw();
3118 }
3119
3120 private int updateSystemUiVisibilityLw() {
3121 // If there is no window focused, there will be nobody to handle the events
3122 // anyway, so just hang on in whatever state we're in until things settle down.
3123 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
3124 : mTopFullscreenOpaqueWindowState;
3125 if (winCandidate == null) {
3126 return 0;
3127 }
3128
3129 // The immersive mode confirmation should never affect the system bar visibility, otherwise
3130 // it will unhide the navigation bar and hide itself.
3131 if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
3132
3133 // The immersive mode confirmation took the focus from mLastFocusedWindow which was
3134 // controlling the system ui visibility. So if mLastFocusedWindow can still receive
3135 // keys, we let it keep controlling the visibility.
3136 final boolean lastFocusCanReceiveKeys =
3137 (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
3138 winCandidate = isStatusBarKeyguard() ? mStatusBar
3139 : lastFocusCanReceiveKeys ? mLastFocusedWindow
3140 : mTopFullscreenOpaqueWindowState;
3141 if (winCandidate == null) {
3142 return 0;
3143 }
3144 }
3145 final WindowState win = winCandidate;
3146 if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) {
3147 // We are updating at a point where the keyguard has gotten
3148 // focus, but we were last in a state where the top window is
3149 // hiding it. This is probably because the keyguard as been
3150 // shown while the top window was displayed, so we want to ignore
3151 // it here because this is just a very transient change and it
3152 // will quickly lose focus once it correctly gets hidden.
3153 return 0;
3154 }
3155
Jorim Jaggib6030952018-10-23 18:31:52 +02003156 mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(
3157 mTopFullscreenOpaqueWindowState);
3158
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
3167 final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
3168 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
3169 final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
3170 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
3171 mService.getStackBounds(
3172 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
3173 mService.getStackBounds(
3174 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003175 final Pair<Integer, Boolean> result =
3176 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
3177 final int visibility = result.first;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003178 final int diff = visibility ^ mLastSystemUiFlags;
3179 final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
3180 final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
3181 final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
3182 if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
3183 && mFocusedApp == win.getAppToken()
3184 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
3185 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
3186 return 0;
3187 }
3188 mLastSystemUiFlags = visibility;
3189 mLastFullscreenStackSysUiFlags = fullscreenVisibility;
3190 mLastDockedStackSysUiFlags = dockedVisibility;
3191 mLastFocusNeedsMenu = needsMenu;
3192 mFocusedApp = win.getAppToken();
Riddle Hsu4d6a63f2019-03-29 19:14:43 +08003193 mLastNonDockedStackBounds.set(mNonDockedStackBounds);
3194 mLastDockedStackBounds.set(mDockedStackBounds);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003195 final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
3196 final Rect dockedStackBounds = new Rect(mDockedStackBounds);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003197 final boolean isNavbarColorManagedByIme = result.second;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003198 mHandler.post(() -> {
3199 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
3200 if (statusBar != null) {
3201 final int displayId = getDisplayId();
3202 statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility,
3203 dockedVisibility, 0xffffffff, fullscreenStackBounds,
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003204 dockedStackBounds, isNavbarColorManagedByIme, win.toString());
Tiger Huang7c610aa2018-10-27 00:01:01 +08003205 statusBar.topAppWindowChanged(displayId, needsMenu);
3206 }
3207 });
3208 return diff;
3209 }
3210
3211 private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
3212 final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded();
3213 final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
3214 if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
3215 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
3216 // its light flag.
3217 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3218 vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
3219 & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3220 } else if (statusColorWin != null && statusColorWin.isDimming()) {
3221 // Otherwise if it's dimming, clear the light flag.
3222 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3223 }
3224 return vis;
3225 }
3226
3227 @VisibleForTesting
3228 @Nullable
3229 static WindowState chooseNavigationColorWindowLw(WindowState opaque,
3230 WindowState opaqueOrDimming, WindowState imeWindow,
3231 @NavigationBarPosition int navBarPosition) {
3232 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
3233 // window can be navigation color window.
3234 final boolean imeWindowCanNavColorWindow = imeWindow != null
3235 && imeWindow.isVisibleLw()
3236 && navBarPosition == NAV_BAR_BOTTOM
3237 && (PolicyControl.getWindowFlags(imeWindow, null)
3238 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3239
3240 if (opaque != null && opaqueOrDimming == opaque) {
3241 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
3242 // unless IME window is also eligible, since currently the IME window is always show
3243 // above the opaque fullscreen app window, regardless of the IME target window.
3244 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
3245 return imeWindowCanNavColorWindow ? imeWindow : opaque;
3246 }
3247
3248 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
3249 // No dimming window is involved. Determine the result only with the IME window.
3250 return imeWindowCanNavColorWindow ? imeWindow : null;
3251 }
3252
3253 if (!imeWindowCanNavColorWindow) {
3254 // No IME window is involved. Determine the result only with opaqueOrDimming.
3255 return opaqueOrDimming;
3256 }
3257
3258 // The IME window and the dimming window are competing. Check if the dimming window can be
3259 // IME target or not.
3260 if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3261 // The IME window is above the dimming window.
3262 return imeWindow;
3263 } else {
3264 // The dimming window is above the IME window.
3265 return opaqueOrDimming;
3266 }
3267 }
3268
3269 @VisibleForTesting
3270 static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3271 WindowState imeWindow, WindowState navColorWin) {
3272
3273 if (navColorWin != null) {
3274 if (navColorWin == imeWindow || navColorWin == opaque) {
3275 // Respect the light flag.
3276 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3277 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3278 & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3279 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3280 // Clear the light flag for dimming window.
3281 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3282 }
3283 }
3284 return vis;
3285 }
3286
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003287 private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003288 final boolean dockedStackVisible =
3289 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3290 final boolean freeformStackVisible =
3291 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3292 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3293
3294 // We need to force system bars when the docked stack is visible, when the freeform stack
3295 // is visible but also when we are resizing for the transitions when docked stack
3296 // visibility changes.
Brad Stenninge0573692019-03-11 13:52:46 -07003297 mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing
3298 || mForceShowSystemBarsFromExternal;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003299 final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
3300
3301 // apply translucent bar vis flags
3302 WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded()
3303 ? mStatusBar
3304 : mTopFullscreenOpaqueWindowState;
3305 vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3306 vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
Adrian Roosfaba4062019-05-14 15:27:17 +02003307 int dockedVis = mStatusBarController.applyTranslucentFlagLw(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003308 mTopDockedOpaqueWindowState, 0, 0);
Adrian Roosfaba4062019-05-14 15:27:17 +02003309 dockedVis = mNavigationBarController.applyTranslucentFlagLw(
3310 mTopDockedOpaqueWindowState, dockedVis, 0);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003311
3312 final boolean fullscreenDrawsStatusBarBackground =
3313 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3314 final boolean dockedDrawsStatusBarBackground =
3315 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003316 final boolean fullscreenDrawsNavBarBackground =
3317 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
Adrian Roosfaba4062019-05-14 15:27:17 +02003318 final boolean dockedDrawsNavigationBarBackground =
3319 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003320
3321 // prevent status bar interaction from clearing certain flags
3322 int type = win.getAttrs().type;
3323 boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
3324 if (statusBarHasFocus && !isStatusBarKeyguard()) {
3325 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3326 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3327 | View.SYSTEM_UI_FLAG_IMMERSIVE
3328 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3329 | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3330 if (isKeyguardOccluded()) {
3331 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3332 }
3333 vis = (vis & ~flags) | (oldVis & flags);
3334 }
3335
3336 if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3337 vis |= View.STATUS_BAR_TRANSPARENT;
3338 vis &= ~View.STATUS_BAR_TRANSLUCENT;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003339 } else if (forceOpaqueStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003340 vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3341 }
3342
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003343 vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003344 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003345
3346 // update status bar
3347 boolean immersiveSticky =
3348 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3349 final boolean hideStatusBarWM =
3350 mTopFullscreenOpaqueWindowState != null
3351 && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3352 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3353 final boolean hideStatusBarSysui =
3354 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3355 final boolean hideNavBarSysui =
3356 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3357
3358 final boolean transientStatusBarAllowed = mStatusBar != null
3359 && (statusBarHasFocus || (!mForceShowSystemBars
3360 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3361
3362 final boolean transientNavBarAllowed = mNavigationBar != null
3363 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3364
3365 final long now = SystemClock.uptimeMillis();
3366 final boolean pendingPanic = mPendingPanicGestureUptime != 0
3367 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3368 final DisplayPolicy defaultDisplayPolicy =
3369 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
3370 if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
3371 // TODO (b/111955725): Show keyguard presentation on all external displays
3372 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3373 // The user performed the panic gesture recently, we're about to hide the bars,
3374 // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3375 mPendingPanicGestureUptime = 0;
3376 mStatusBarController.showTransient();
3377 if (!isNavBarEmpty(vis)) {
3378 mNavigationBarController.showTransient();
3379 }
3380 }
3381
3382 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3383 && !transientStatusBarAllowed && hideStatusBarSysui;
3384 final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3385 && !transientNavBarAllowed;
3386 if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3387 // clear the clearable flags instead
3388 clearClearableFlagsLw();
3389 vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3390 }
3391
3392 final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3393 immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3394 final boolean navAllowedHidden = immersive || immersiveSticky;
3395
3396 if (hideNavBarSysui && !navAllowedHidden
3397 && mService.mPolicy.getWindowLayerLw(win)
3398 > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3399 // We can't hide the navbar from this window otherwise the input consumer would not get
3400 // the input events.
3401 vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3402 }
3403
3404 vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3405
3406 // update navigation bar
3407 boolean oldImmersiveMode = isImmersiveMode(oldVis);
3408 boolean newImmersiveMode = isImmersiveMode(vis);
3409 if (oldImmersiveMode != newImmersiveMode) {
3410 final String pkg = win.getOwningPackage();
3411 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3412 mService.mPolicy.isUserSetupComplete(),
3413 isNavBarEmpty(win.getSystemUiVisibility()));
3414 }
3415
3416 vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3417
3418 final WindowState navColorWin = chooseNavigationColorWindowLw(
3419 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3420 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3421 vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3422 mTopFullscreenOpaqueOrDimmingWindowState,
3423 mDisplayContent.mInputMethodWindow, navColorWin);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003424 // Navbar color is controlled by the IME.
3425 final boolean isManagedByIme =
3426 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003427
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003428 return Pair.create(vis, isManagedByIme);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003429 }
3430
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003431 private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
3432 int translucentFlag) {
3433 if (!controller.isTransparentAllowed(win)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003434 return false;
3435 }
3436 if (win == null) {
3437 return true;
3438 }
3439
3440 final boolean drawsSystemBars =
3441 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3442 final boolean forceDrawsSystemBars =
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003443 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003444
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003445 return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
3446 }
3447
3448 private boolean drawsStatusBarBackground(int vis, WindowState win) {
3449 return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
3450 }
3451
3452 private boolean drawsNavigationBarBackground(int vis, WindowState win) {
3453 return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003454 }
3455
3456 /**
3457 * @return the current visibility flags with the nav-bar opacity related flags toggled based
3458 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3459 */
3460 private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003461 boolean freeformStackVisible, boolean isDockedDividerResizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003462 boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
3463 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
3464 if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
3465 visibility = setNavBarTransparentFlag(visibility);
3466 } else if (dockedStackVisible) {
3467 visibility = setNavBarOpaqueFlag(visibility);
3468 }
3469 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003470 if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003471 if (mIsFreeformWindowOverlappingWithNavBar) {
3472 visibility = setNavBarTranslucentFlag(visibility);
3473 } else {
3474 visibility = setNavBarOpaqueFlag(visibility);
3475 }
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003476 } else if (fullscreenDrawsBackground) {
3477 visibility = setNavBarTransparentFlag(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003478 }
3479 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3480 if (isDockedDividerResizing) {
3481 visibility = setNavBarOpaqueFlag(visibility);
3482 } else if (freeformStackVisible) {
3483 visibility = setNavBarTranslucentFlag(visibility);
3484 } else {
3485 visibility = setNavBarOpaqueFlag(visibility);
3486 }
3487 }
3488
Tiger Huang7c610aa2018-10-27 00:01:01 +08003489 return visibility;
3490 }
3491
3492 private int setNavBarOpaqueFlag(int visibility) {
3493 return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3494 }
3495
3496 private int setNavBarTranslucentFlag(int visibility) {
3497 visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3498 return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3499 }
3500
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003501 private int setNavBarTransparentFlag(int visibility) {
3502 visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3503 return visibility | View.NAVIGATION_BAR_TRANSPARENT;
3504 }
3505
Tiger Huang7c610aa2018-10-27 00:01:01 +08003506 private void clearClearableFlagsLw() {
3507 int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3508 if (newVal != mResettingSystemUiFlags) {
3509 mResettingSystemUiFlags = newVal;
3510 mDisplayContent.reevaluateStatusBarVisibility();
3511 }
3512 }
3513
3514 private boolean isImmersiveMode(int vis) {
3515 final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3516 return mNavigationBar != null
3517 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3518 && (vis & flags) != 0
3519 && canHideNavigationBar();
3520 }
3521
3522 /**
3523 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3524 */
3525 private boolean canHideNavigationBar() {
3526 return hasNavigationBar();
3527 }
3528
3529 private static boolean isNavBarEmpty(int systemUiFlags) {
3530 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3531 | View.STATUS_BAR_DISABLE_BACK
3532 | View.STATUS_BAR_DISABLE_RECENT);
3533
3534 return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3535 }
3536
Tiger Huang7c610aa2018-10-27 00:01:01 +08003537 boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
3538 int newRotation) {
3539 // For the upside down rotation we don't rotate seamlessly as the navigation
3540 // bar moves position.
3541 // Note most apps (using orientation:sensor or user as opposed to fullSensor)
3542 // will not enter the reverse portrait orientation, so actually the
3543 // orientation won't change at all.
3544 if (oldRotation == displayRotation.getUpsideDownRotation()
3545 || newRotation == displayRotation.getUpsideDownRotation()) {
3546 return false;
3547 }
3548 // If the navigation bar can't change sides, then it will
3549 // jump when we change orientations and we don't rotate
Adrian Roosd3b40862019-04-16 15:39:23 +02003550 // seamlessly - unless that is allowed, eg. with gesture
3551 // navigation where the navbar is low-profile enough that this isn't very noticeable.
3552 if (!navigationBarCanMove() && !mAllowSeamlessRotationDespiteNavBarMoving) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003553 return false;
3554 }
3555
3556 final WindowState w = mTopFullscreenOpaqueWindowState;
Riddle Hsuc90c4a52019-02-25 13:35:53 +08003557 if (w == null || w != mFocusedWindow) {
3558 return false;
3559 }
3560 // If the bounds of activity window is different from its parent, then reject to be seamless
3561 // because the window position may change after rotation that will look like a sudden jump.
3562 if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003563 return false;
3564 }
3565
3566 // We only enable seamless rotation if the top window has requested
3567 // it and is in the fullscreen opaque state. Seamless rotation
3568 // requires freezing various Surface states and won't work well
3569 // with animations, so we disable it in the animation case for now.
Riddle Hsuc90c4a52019-02-25 13:35:53 +08003570 if (!w.isAnimatingLw() && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003571 return true;
3572 }
3573 return false;
3574 }
3575
3576 private final Runnable mHiddenNavPanic = new Runnable() {
3577 @Override
3578 public void run() {
3579 synchronized (mLock) {
3580 if (!mService.mPolicy.isUserSetupComplete()) {
3581 // Swipe-up for navigation bar is disabled during setup
3582 return;
3583 }
3584 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3585 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3586 mNavigationBarController.showTransient();
3587 }
3588 }
3589 }
3590 };
3591
3592 void onPowerKeyDown(boolean isScreenOn) {
3593 // Detect user pressing the power button in panic when an application has
3594 // taken over the whole screen.
3595 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3596 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3597 isNavBarEmpty(mLastSystemUiFlags));
3598 if (panic) {
3599 mHandler.post(mHiddenNavPanic);
3600 }
3601 }
3602
3603 void onVrStateChangedLw(boolean enabled) {
3604 mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3605 }
3606
3607 /**
3608 * Called when the state of lock task mode changes. This should be used to disable immersive
3609 * mode confirmation.
3610 *
3611 * @param lockTaskState the new lock task mode state. One of
3612 * {@link ActivityManager#LOCK_TASK_MODE_NONE},
3613 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3614 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3615 */
3616 public void onLockTaskStateChangedLw(int lockTaskState) {
3617 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3618 }
3619
3620 /**
3621 * Request a screenshot be taken.
3622 *
3623 * @param screenshotType The type of screenshot, for example either
3624 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3625 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3626 */
3627 public void takeScreenshot(int screenshotType) {
3628 if (mScreenshotHelper != null) {
3629 mScreenshotHelper.takeScreenshot(screenshotType,
3630 mStatusBar != null && mStatusBar.isVisibleLw(),
3631 mNavigationBar != null && mNavigationBar.isVisibleLw(), mHandler);
3632 }
3633 }
3634
Ady Abrahamf3e05312019-05-13 18:04:59 -07003635 RefreshRatePolicy getRefreshRatePolicy() {
3636 return mRefreshRatePolicy;
3637 }
3638
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003639 void dump(String prefix, PrintWriter pw) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003640 pw.print(prefix); pw.print("DisplayPolicy");
3641 prefix += " ";
3642 pw.print(prefix);
3643 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3644 pw.print(" mDeskDockEnablesAccelerometer=");
3645 pw.println(mDeskDockEnablesAccelerometer);
3646 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3647 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3648 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3649 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3650 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3651 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3652 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3653 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3654 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3655 || mForceClearedSystemUiFlags != 0) {
3656 pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3657 pw.print(Integer.toHexString(mLastSystemUiFlags));
3658 pw.print(" mResettingSystemUiFlags=0x");
3659 pw.print(Integer.toHexString(mResettingSystemUiFlags));
3660 pw.print(" mForceClearedSystemUiFlags=0x");
3661 pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3662 }
3663 if (mLastFocusNeedsMenu) {
3664 pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu);
3665 }
3666 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3667 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3668 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3669 if (mStatusBar != null) {
3670 pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
3671 pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard());
3672 }
3673 if (mNavigationBar != null) {
3674 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
Winson Chung4723b4e2019-03-25 16:49:36 -07003675 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
3676 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
3677 pw.print(prefix); pw.print("mNavigationBarPosition=");
3678 pw.println(mNavigationBarPosition);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003679 }
3680 if (mFocusedWindow != null) {
3681 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3682 }
3683 if (mFocusedApp != null) {
3684 pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3685 }
3686 if (mTopFullscreenOpaqueWindowState != null) {
3687 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3688 pw.println(mTopFullscreenOpaqueWindowState);
3689 }
3690 if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3691 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3692 pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3693 }
3694 if (mForcingShowNavBar) {
3695 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3696 pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3697 pw.println(mForcingShowNavBarLayer);
3698 }
3699 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
3700 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
3701 pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
Brad Stenninge0573692019-03-11 13:52:46 -07003702 pw.print(" mForceShowSystemBarsFromExternal=");
3703 pw.println(mForceShowSystemBarsFromExternal);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003704 pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
3705 mStatusBarController.dump(pw, prefix);
3706 mNavigationBarController.dump(pw, prefix);
3707
3708 pw.print(prefix); pw.println("Looper state:");
3709 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003710 }
Arthur Hung20479922019-02-27 17:13:22 +08003711
3712 private boolean supportsPointerLocation() {
3713 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
3714 }
3715
3716 void setPointerLocationEnabled(boolean pointerLocationEnabled) {
3717 if (!supportsPointerLocation()) {
3718 return;
3719 }
3720
3721 mHandler.sendEmptyMessage(pointerLocationEnabled
3722 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
3723 }
3724
3725 private void enablePointerLocation() {
3726 if (mPointerLocationView != null) {
3727 return;
3728 }
3729
3730 mPointerLocationView = new PointerLocationView(mContext);
3731 mPointerLocationView.setPrintCoords(false);
3732 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
3733 WindowManager.LayoutParams.MATCH_PARENT,
3734 WindowManager.LayoutParams.MATCH_PARENT);
3735 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3736 lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
3737 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3738 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3739 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3740 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3741 if (ActivityManager.isHighEndGfx()) {
3742 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3743 lp.privateFlags |=
3744 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3745 }
3746 lp.format = PixelFormat.TRANSLUCENT;
3747 lp.setTitle("PointerLocation - display " + getDisplayId());
3748 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3749 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3750 wm.addView(mPointerLocationView, lp);
3751 mDisplayContent.registerPointerEventListener(mPointerLocationView);
3752 }
3753
3754 private void disablePointerLocation() {
3755 if (mPointerLocationView == null) {
3756 return;
3757 }
3758
3759 mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3760 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3761 wm.removeView(mPointerLocationView);
3762 mPointerLocationView = null;
3763 }
HEO SEUNG22d3ec22019-05-30 20:28:53 +09003764
3765 @VisibleForTesting
3766 static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
3767 if (navBarWindow == null || !navBarWindow.isVisibleLw()
3768 || targetWindow.mAppToken == null || !targetWindow.isVisibleLw()) {
3769 return false;
3770 }
3771
3772 return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw());
3773 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003774}