blob: 99a9db316c63acc831b7cf53d3f7013e77566fc9 [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
Jorim Jaggi4981f152019-03-26 18:58:45 +0100287 /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
288 @Px private int mWindowOutsetBottom;
289
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800290 private final StatusBarController mStatusBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800291
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800292 private final BarController mNavigationBarController;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800293
294 private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
295 new BarController.OnBarVisibilityChangedListener() {
296 @Override
297 public void onBarVisibilityChanged(boolean visible) {
298 if (mAccessibilityManager == null) {
299 return;
300 }
301 mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
302 }
303 };
304
Tiger Huang7c610aa2018-10-27 00:01:01 +0800305 @GuardedBy("mHandler")
306 private SleepToken mDreamingSleepToken;
307
308 @GuardedBy("mHandler")
309 private SleepToken mWindowSleepToken;
310
311 private final Runnable mAcquireSleepTokenRunnable;
312 private final Runnable mReleaseSleepTokenRunnable;
313
314 // The windows we were told about in focusChanged.
315 private WindowState mFocusedWindow;
316 private WindowState mLastFocusedWindow;
317
318 IApplicationToken mFocusedApp;
319
320 int mLastSystemUiFlags;
321 // Bits that we are in the process of clearing, so we want to prevent
322 // them from being set by applications until everything has been updated
323 // to have them clear.
324 private int mResettingSystemUiFlags = 0;
325 // Bits that we are currently always keeping cleared.
326 private int mForceClearedSystemUiFlags = 0;
327 private int mLastFullscreenStackSysUiFlags;
328 private int mLastDockedStackSysUiFlags;
329 private final Rect mNonDockedStackBounds = new Rect();
330 private final Rect mDockedStackBounds = new Rect();
331 private final Rect mLastNonDockedStackBounds = new Rect();
332 private final Rect mLastDockedStackBounds = new Rect();
333
334 // What we last reported to system UI about whether the compatibility
335 // menu needs to be displayed.
336 private boolean mLastFocusNeedsMenu = false;
337 // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
338 private long mPendingPanicGestureUptime;
339
340 private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
341 private static final Rect sTmpRect = new Rect();
342 private static final Rect sTmpDockedFrame = new Rect();
343 private static final Rect sTmpNavFrame = new Rect();
344 private static final Rect sTmpLastParentFrame = new Rect();
345
346 private WindowState mTopFullscreenOpaqueWindowState;
347 private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
348 private WindowState mTopDockedOpaqueWindowState;
349 private WindowState mTopDockedOpaqueOrDimmingWindowState;
350 private boolean mTopIsFullscreen;
351 private boolean mForceStatusBar;
352 private boolean mForceStatusBarFromKeyguard;
353 private boolean mForceStatusBarTransparent;
354 private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
355 private boolean mForcingShowNavBar;
356 private int mForcingShowNavBarLayer;
357 private boolean mForceShowSystemBars;
358
Brad Stenninge0573692019-03-11 13:52:46 -0700359 /**
360 * Force the display of system bars regardless of other settings.
361 */
362 private boolean mForceShowSystemBarsFromExternal;
363
Tiger Huang7c610aa2018-10-27 00:01:01 +0800364 private boolean mShowingDream;
365 private boolean mLastShowingDream;
366 private boolean mDreamingLockscreen;
367 private boolean mDreamingSleepTokenNeeded;
368 private boolean mWindowSleepTokenNeeded;
369 private boolean mLastWindowSleepTokenNeeded;
370 private boolean mAllowLockscreenWhenOn;
371
372 private InputConsumer mInputConsumer = null;
373
Arthur Hung20479922019-02-27 17:13:22 +0800374 private PointerLocationView mPointerLocationView;
375
Issei Suzukia5dbf522019-02-01 17:58:15 +0100376 /**
377 * The area covered by system windows which belong to another display. Forwarded insets is set
378 * in case this is a virtual display, this is displayed on another display that has insets, and
379 * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
380 * displayed on the host display, and it covers a part of this virtual display.)
381 * The forwarded insets is used to compute display frames of this virtual display, which will
382 * be then used to layout windows in the virtual display.
383 */
384 @NonNull private Insets mForwardedInsets = Insets.NONE;
385
Ady Abrahamf3e05312019-05-13 18:04:59 -0700386 private RefreshRatePolicy mRefreshRatePolicy;
387
Tiger Huang7c610aa2018-10-27 00:01:01 +0800388 // -------- PolicyHandler --------
389 private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
390 private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
391 private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
Arthur Hung20479922019-02-27 17:13:22 +0800392 private static final int MSG_ENABLE_POINTER_LOCATION = 4;
393 private static final int MSG_DISABLE_POINTER_LOCATION = 5;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800394
395 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
396 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
397
398 private class PolicyHandler extends Handler {
399
400 PolicyHandler(Looper looper) {
401 super(looper);
402 }
403
404 @Override
405 public void handleMessage(Message msg) {
406 switch (msg.what) {
407 case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
408 updateDreamingSleepToken(msg.arg1 != 0);
409 break;
410 case MSG_REQUEST_TRANSIENT_BARS:
411 WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
412 ? mStatusBar : mNavigationBar;
413 if (targetBar != null) {
414 requestTransientBars(targetBar);
415 }
416 break;
417 case MSG_DISPOSE_INPUT_CONSUMER:
418 disposeInputConsumer((InputConsumer) msg.obj);
419 break;
Arthur Hung20479922019-02-27 17:13:22 +0800420 case MSG_ENABLE_POINTER_LOCATION:
421 enablePointerLocation();
422 break;
423 case MSG_DISABLE_POINTER_LOCATION:
424 disablePointerLocation();
425 break;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800426 }
427 }
428 }
429
430 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800431 mService = service;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800432 mContext = displayContent.isDefaultDisplay ? service.mContext
433 : service.mContext.createDisplayContext(displayContent.getDisplay());
434 mDisplayContent = displayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800435 mLock = service.getWindowManagerLock();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800436
Riddle Hsud80ae9b2019-03-26 00:40:35 +0800437 final int displayId = displayContent.getDisplayId();
438 mStatusBarController = new StatusBarController(displayId);
439 mNavigationBarController = new BarController("NavigationBar",
440 displayId,
441 View.NAVIGATION_BAR_TRANSIENT,
442 View.NAVIGATION_BAR_UNHIDE,
443 View.NAVIGATION_BAR_TRANSLUCENT,
444 StatusBarManager.WINDOW_NAVIGATION_BAR,
445 FLAG_TRANSLUCENT_NAVIGATION,
446 View.NAVIGATION_BAR_TRANSPARENT);
447
Tiger Huang7c610aa2018-10-27 00:01:01 +0800448 final Resources r = mContext.getResources();
449 mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
450 mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
Brad Stenninge0573692019-03-11 13:52:46 -0700451 mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800452
453 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
454 Context.ACCESSIBILITY_SERVICE);
455 if (!displayContent.isDefaultDisplay) {
456 mAwake = true;
457 mScreenOnEarly = true;
458 mScreenOnFully = true;
459 }
460
461 final Looper looper = UiThread.getHandler().getLooper();
462 mHandler = new PolicyHandler(looper);
463 mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
464 new SystemGesturesPointerEventListener.Callbacks() {
465 @Override
466 public void onSwipeFromTop() {
467 if (mStatusBar != null) {
468 requestTransientBars(mStatusBar);
469 }
470 }
471
472 @Override
473 public void onSwipeFromBottom() {
Winson Chung36941632019-04-19 15:21:38 -0700474 if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800475 requestTransientBars(mNavigationBar);
476 }
477 }
478
479 @Override
480 public void onSwipeFromRight() {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200481 final Region excludedRegion = Region.obtain();
Jeff Chang1c459ef2019-06-18 11:51:25 +0800482 synchronized (mLock) {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200483 mDisplayContent.calculateSystemGestureExclusion(
484 excludedRegion, null /* outUnrestricted */);
Jeff Chang1c459ef2019-06-18 11:51:25 +0800485 }
Winson Chung36941632019-04-19 15:21:38 -0700486 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
487 || mNavigationBarPosition == NAV_BAR_RIGHT;
488 if (mNavigationBar != null && sideAllowed
489 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800490 requestTransientBars(mNavigationBar);
491 }
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200492 excludedRegion.recycle();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800493 }
494
495 @Override
496 public void onSwipeFromLeft() {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200497 final Region excludedRegion = Region.obtain();
Jeff Chang1c459ef2019-06-18 11:51:25 +0800498 synchronized (mLock) {
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200499 mDisplayContent.calculateSystemGestureExclusion(
500 excludedRegion, null /* outUnrestricted */);
Jeff Chang1c459ef2019-06-18 11:51:25 +0800501 }
Winson Chung36941632019-04-19 15:21:38 -0700502 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
503 || mNavigationBarPosition == NAV_BAR_LEFT;
504 if (mNavigationBar != null && sideAllowed
505 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800506 requestTransientBars(mNavigationBar);
507 }
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200508 excludedRegion.recycle();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800509 }
510
511 @Override
512 public void onFling(int duration) {
513 if (mService.mPowerManagerInternal != null) {
514 mService.mPowerManagerInternal.powerHint(
515 PowerHint.INTERACTION, duration);
516 }
517 }
518
519 @Override
520 public void onDebug() {
521 // no-op
522 }
523
524 private WindowOrientationListener getOrientationListener() {
525 final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
526 return rotation != null ? rotation.getOrientationListener() : null;
527 }
528
529 @Override
530 public void onDown() {
531 final WindowOrientationListener listener = getOrientationListener();
532 if (listener != null) {
533 listener.onTouchStart();
534 }
535 }
536
537 @Override
538 public void onUpOrCancel() {
539 final WindowOrientationListener listener = getOrientationListener();
540 if (listener != null) {
541 listener.onTouchEnd();
542 }
543 }
544
545 @Override
546 public void onMouseHoverAtTop() {
547 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
548 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
549 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
550 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
551 }
552
553 @Override
554 public void onMouseHoverAtBottom() {
555 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
556 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
557 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
558 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
559 }
560
561 @Override
562 public void onMouseLeaveFromEdge() {
563 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
564 }
565 });
566 displayContent.registerPointerEventListener(mSystemGestures);
567 displayContent.mAppTransition.registerListenerLocked(
568 mStatusBarController.getAppTransitionListener());
569 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
570 mService.mVrModeEnabled);
571 mAcquireSleepTokenRunnable = () -> {
572 if (mWindowSleepToken != null) {
573 return;
574 }
Tiger Huang7c610aa2018-10-27 00:01:01 +0800575 mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
576 "WindowSleepTokenOnDisplay" + displayId, displayId);
577 };
578 mReleaseSleepTokenRunnable = () -> {
579 if (mWindowSleepToken == null) {
580 return;
581 }
582 mWindowSleepToken.release();
583 mWindowSleepToken = null;
584 };
585
586 // TODO: Make it can take screenshot on external display
587 mScreenshotHelper = displayContent.isDefaultDisplay
588 ? new ScreenshotHelper(mContext) : null;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800589
Tiger Huang7c610aa2018-10-27 00:01:01 +0800590 if (mDisplayContent.isDefaultDisplay) {
Louis Changfc64c832018-12-04 11:38:26 +0800591 mHasStatusBar = true;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800592 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800593
Tiger Huang7c610aa2018-10-27 00:01:01 +0800594 // Allow a system property to override this. Used by the emulator.
595 // See also hasNavigationBar().
596 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
597 if ("1".equals(navBarOverride)) {
598 mHasNavigationBar = false;
599 } else if ("0".equals(navBarOverride)) {
600 mHasNavigationBar = true;
601 }
602 } else {
Louis Changfc64c832018-12-04 11:38:26 +0800603 mHasStatusBar = false;
Andrii Kuliandd989612019-02-21 12:13:28 -0800604 mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800605 }
Ady Abrahamf3e05312019-05-13 18:04:59 -0700606
607 mRefreshRatePolicy = new RefreshRatePolicy(mService,
608 mDisplayContent.getDisplayInfo(),
609 mService.mHighRefreshRateBlacklist);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800610 }
611
Charles Chen5bdd3e22018-12-18 17:51:56 +0800612 void systemReady() {
613 mSystemGestures.systemReady();
Arthur Hung20479922019-02-27 17:13:22 +0800614 if (mService.mPointerLocationEnabled) {
615 setPointerLocationEnabled(true);
616 }
Charles Chen5bdd3e22018-12-18 17:51:56 +0800617 }
618
619 private int getDisplayId() {
620 return mDisplayContent.getDisplayId();
621 }
622
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800623 public void setHdmiPlugged(boolean plugged) {
624 setHdmiPlugged(plugged, false /* force */);
625 }
626
627 public void setHdmiPlugged(boolean plugged, boolean force) {
628 if (force || mHdmiPlugged != plugged) {
629 mHdmiPlugged = plugged;
630 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
631 final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
632 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
633 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800634 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800635 }
636 }
637
638 boolean isHdmiPlugged() {
639 return mHdmiPlugged;
640 }
641
642 boolean isCarDockEnablesAccelerometer() {
643 return mCarDockEnablesAccelerometer;
644 }
645
646 boolean isDeskDockEnablesAccelerometer() {
647 return mDeskDockEnablesAccelerometer;
648 }
649
650 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
651 mPersistentVrModeEnabled = persistentVrModeEnabled;
652 }
653
654 public boolean isPersistentVrModeEnabled() {
655 return mPersistentVrModeEnabled;
656 }
657
658 public void setDockMode(int dockMode) {
659 mDockMode = dockMode;
660 }
661
662 public int getDockMode() {
663 return mDockMode;
664 }
665
Brad Stenninge0573692019-03-11 13:52:46 -0700666 /**
667 * @see WindowManagerService.setForceShowSystemBars
668 */
669 void setForceShowSystemBars(boolean forceShowSystemBars) {
670 mForceShowSystemBarsFromExternal = forceShowSystemBars;
671 }
672
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800673 public boolean hasNavigationBar() {
674 return mHasNavigationBar;
675 }
676
Louis Changfc64c832018-12-04 11:38:26 +0800677 public boolean hasStatusBar() {
678 return mHasStatusBar;
679 }
680
Adrian Roos5f2c9a12019-07-03 18:31:46 +0200681 boolean hasSideGestures() {
682 return mHasNavigationBar && mSideGestureInset > 0;
683 }
684
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800685 public boolean navigationBarCanMove() {
686 return mNavigationBarCanMove;
687 }
688
689 public void setLidState(int lidState) {
690 mLidState = lidState;
691 }
692
693 public int getLidState() {
694 return mLidState;
695 }
696
697 public void setAwake(boolean awake) {
698 mAwake = awake;
699 }
700
701 public boolean isAwake() {
702 return mAwake;
703 }
704
705 public boolean isScreenOnEarly() {
706 return mScreenOnEarly;
707 }
708
709 public boolean isScreenOnFully() {
710 return mScreenOnFully;
711 }
712
713 public boolean isKeyguardDrawComplete() {
714 return mKeyguardDrawComplete;
715 }
716
717 public boolean isWindowManagerDrawComplete() {
718 return mWindowManagerDrawComplete;
719 }
720
721 public ScreenOnListener getScreenOnListener() {
722 return mScreenOnListener;
723 }
724
725 public void screenTurnedOn(ScreenOnListener screenOnListener) {
726 synchronized (mLock) {
727 mScreenOnEarly = true;
728 mScreenOnFully = false;
729 mKeyguardDrawComplete = false;
730 mWindowManagerDrawComplete = false;
731 mScreenOnListener = screenOnListener;
732 }
733 }
734
735 public void screenTurnedOff() {
736 synchronized (mLock) {
737 mScreenOnEarly = false;
738 mScreenOnFully = false;
739 mKeyguardDrawComplete = false;
740 mWindowManagerDrawComplete = false;
741 mScreenOnListener = null;
742 }
743 }
744
745 /** Return false if we are not awake yet or we have already informed of this event. */
746 public boolean finishKeyguardDrawn() {
747 synchronized (mLock) {
748 if (!mScreenOnEarly || mKeyguardDrawComplete) {
749 return false;
750 }
751
752 mKeyguardDrawComplete = true;
753 mWindowManagerDrawComplete = false;
754 }
755 return true;
756 }
757
758 /** Return false if screen is not turned on or we did already handle this case earlier. */
759 public boolean finishWindowsDrawn() {
760 synchronized (mLock) {
761 if (!mScreenOnEarly || mWindowManagerDrawComplete) {
762 return false;
763 }
764
765 mWindowManagerDrawComplete = true;
766 }
767 return true;
768 }
769
770 /** Return false if it is not ready to turn on. */
771 public boolean finishScreenTurningOn() {
772 synchronized (mLock) {
773 if (DEBUG_SCREEN_ON) Slog.d(TAG,
774 "finishScreenTurningOn: mAwake=" + mAwake
775 + ", mScreenOnEarly=" + mScreenOnEarly
776 + ", mScreenOnFully=" + mScreenOnFully
777 + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
778 + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
779
780 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
781 || (mAwake && !mKeyguardDrawComplete)) {
782 return false;
783 }
784
785 if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on...");
786 mScreenOnListener = null;
787 mScreenOnFully = true;
788 }
789 return true;
790 }
791
Jorim Jaggi4981f152019-03-26 18:58:45 +0100792 private boolean hasStatusBarServicePermission(int pid, int uid) {
793 return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
794 == PackageManager.PERMISSION_GRANTED;
795 }
796
Tiger Huang7c610aa2018-10-27 00:01:01 +0800797 /**
798 * Sanitize the layout parameters coming from a client. Allows the policy
799 * to do things like ensure that windows of a specific type can't take
800 * input focus.
801 *
802 * @param attrs The window layout parameters to be modified. These values
803 * are modified in-place.
804 */
805 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
Jorim Jaggi4981f152019-03-26 18:58:45 +0100806 int callingPid, int callingUid) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800807
808 final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
809 if (mScreenDecorWindows.contains(win)) {
810 if (!isScreenDecor) {
811 // No longer has the flag set, so remove from the set.
812 mScreenDecorWindows.remove(win);
813 }
Jorim Jaggi4981f152019-03-26 18:58:45 +0100814 } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800815 mScreenDecorWindows.add(win);
816 }
817
818 switch (attrs.type) {
819 case TYPE_SYSTEM_OVERLAY:
820 case TYPE_SECURE_SYSTEM_OVERLAY:
821 // These types of windows can't receive input events.
822 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
823 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
824 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
825 break;
826 case TYPE_DREAM:
827 case TYPE_WALLPAPER:
828 // Dreams and wallpapers don't have an app window token and can thus not be
829 // letterboxed. Hence always let them extend under the cutout.
Arthur Hung20479922019-02-27 17:13:22 +0800830 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800831 break;
832 case TYPE_STATUS_BAR:
833
834 // If the Keyguard is in a hidden state (occluded by another window), we force to
835 // remove the wallpaper and keyguard flag so that any change in-flight after setting
836 // the keyguard as occluded wouldn't set these flags again.
837 // See {@link #processKeyguardSetHiddenResultLw}.
838 if (mService.mPolicy.isKeyguardOccluded()) {
839 attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
840 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
841 }
842 break;
843
844 case TYPE_SCREENSHOT:
845 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
846 break;
847
848 case TYPE_TOAST:
849 // While apps should use the dedicated toast APIs to add such windows
850 // it possible legacy apps to add the window directly. Therefore, we
851 // make windows added directly by the app behave as a toast as much
852 // as possible in terms of timeout and animation.
853 if (attrs.hideTimeoutMilliseconds < 0
854 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
855 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
856 }
Rhed Jao406d3a22018-11-30 19:28:58 +0800857 // Accessibility users may need longer timeout duration. This api compares
858 // original timeout with user's preference and return longer one. It returns
859 // original timeout if there's no preference.
860 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
861 (int) attrs.hideTimeoutMilliseconds,
862 AccessibilityManager.FLAG_CONTENT_TEXT);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800863 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
Jeff Changb10fac72019-04-09 17:28:30 +0800864 // Toast can show with below conditions when the screen is locked.
865 if (canToastShowWhenLocked(callingPid)) {
866 attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
867 }
Tiger Huang7c610aa2018-10-27 00:01:01 +0800868 break;
869 }
870
871 if (attrs.type != TYPE_STATUS_BAR) {
872 // The status bar is the only window allowed to exhibit keyguard behavior.
873 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
874 }
875 }
876
877 /**
Jeff Changb10fac72019-04-09 17:28:30 +0800878 * @return {@code true} if the calling activity initiate toast and is visible with
879 * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
880 */
881 boolean canToastShowWhenLocked(int callingPid) {
882 return mDisplayContent.forAllWindows(w -> {
883 return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
884 }, true /* traverseTopToBottom */);
885 }
886
887 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +0800888 * Preflight adding a window to the system.
889 *
890 * Currently enforces that three window types are singletons per display:
891 * <ul>
892 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
893 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
894 * </ul>
895 *
896 * @param win The window to be added
897 * @param attrs Information about the window to be added
898 *
899 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
900 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
901 */
902 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
903
904 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
905 mContext.enforceCallingOrSelfPermission(
906 android.Manifest.permission.STATUS_BAR_SERVICE,
907 "DisplayPolicy");
908 mScreenDecorWindows.add(win);
909 }
910
911 switch (attrs.type) {
912 case TYPE_STATUS_BAR:
913 mContext.enforceCallingOrSelfPermission(
914 android.Manifest.permission.STATUS_BAR_SERVICE,
915 "DisplayPolicy");
916 if (mStatusBar != null) {
917 if (mStatusBar.isAlive()) {
918 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
919 }
920 }
921 mStatusBar = win;
922 mStatusBarController.setWindow(win);
923 if (mDisplayContent.isDefaultDisplay) {
924 mService.mPolicy.setKeyguardCandidateLw(win);
925 }
Adrian Roos11dfd272019-03-25 19:21:26 +0100926 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200927 (displayFrames, windowState, rect) -> {
928 rect.top = 0;
929 rect.bottom = getStatusBarHeight(displayFrames);
Adrian Roos11dfd272019-03-25 19:21:26 +0100930 };
931 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, frameProvider);
932 mDisplayContent.setInsetProvider(TYPE_TOP_GESTURES, win, frameProvider);
933 mDisplayContent.setInsetProvider(TYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800934 break;
935 case TYPE_NAVIGATION_BAR:
936 mContext.enforceCallingOrSelfPermission(
937 android.Manifest.permission.STATUS_BAR_SERVICE,
938 "DisplayPolicy");
939 if (mNavigationBar != null) {
940 if (mNavigationBar.isAlive()) {
941 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
942 }
943 }
944 mNavigationBar = win;
945 mNavigationBarController.setWindow(win);
946 mNavigationBarController.setOnBarVisibilityChangedListener(
947 mNavBarVisibilityListener, true);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200948 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR,
949 win, null /* frameProvider */);
Adrian Roos11dfd272019-03-25 19:21:26 +0100950 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_GESTURES, win,
951 (displayFrames, windowState, inOutFrame) -> {
952 inOutFrame.top -= mBottomGestureAdditionalInset;
953 });
954 mDisplayContent.setInsetProvider(InsetsState.TYPE_LEFT_GESTURES, win,
955 (displayFrames, windowState, inOutFrame) -> {
956 inOutFrame.left = 0;
957 inOutFrame.top = 0;
958 inOutFrame.bottom = displayFrames.mDisplayHeight;
959 inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
960 });
961 mDisplayContent.setInsetProvider(InsetsState.TYPE_RIGHT_GESTURES, win,
962 (displayFrames, windowState, inOutFrame) -> {
963 inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
964 inOutFrame.top = 0;
965 inOutFrame.bottom = displayFrames.mDisplayHeight;
966 inOutFrame.right = displayFrames.mDisplayWidth;
967 });
968 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_TAPPABLE_ELEMENT, win,
969 (displayFrames, windowState, inOutFrame) -> {
970 if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
971 || mNavigationBarLetsThroughTaps) {
972 inOutFrame.setEmpty();
973 }
974 });
Tiger Huang7c610aa2018-10-27 00:01:01 +0800975 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
976 break;
977 case TYPE_NAVIGATION_BAR_PANEL:
978 case TYPE_STATUS_BAR_PANEL:
979 case TYPE_STATUS_BAR_SUB_PANEL:
980 case TYPE_VOICE_INTERACTION_STARTING:
981 mContext.enforceCallingOrSelfPermission(
982 android.Manifest.permission.STATUS_BAR_SERVICE,
983 "DisplayPolicy");
984 break;
985 }
986 return ADD_OKAY;
987 }
988
989 /**
990 * Called when a window is being removed from a window manager. Must not
991 * throw an exception -- clean up as much as possible.
992 *
993 * @param win The window being removed.
994 */
995 public void removeWindowLw(WindowState win) {
996 if (mStatusBar == win) {
997 mStatusBar = null;
998 mStatusBarController.setWindow(null);
999 if (mDisplayContent.isDefaultDisplay) {
1000 mService.mPolicy.setKeyguardCandidateLw(null);
1001 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001002 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001003 } else if (mNavigationBar == win) {
1004 mNavigationBar = null;
1005 mNavigationBarController.setWindow(null);
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001006 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001007 }
1008 if (mLastFocusedWindow == win) {
1009 mLastFocusedWindow = null;
1010 }
1011 mScreenDecorWindows.remove(win);
1012 }
1013
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001014 private int getStatusBarHeight(DisplayFrames displayFrames) {
1015 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1016 displayFrames.mDisplayCutoutSafe.top);
1017 }
1018
Tiger Huang7c610aa2018-10-27 00:01:01 +08001019 /**
1020 * Control the animation to run when a window's state changes. Return a
1021 * non-0 number to force the animation to a specific resource ID, or 0
1022 * to use the default animation.
1023 *
1024 * @param win The window that is changing.
1025 * @param transit What is happening to the window:
1026 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1027 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1028 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1029 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1030 *
1031 * @return Resource ID of the actual animation to use, or 0 for none.
1032 */
1033 public int selectAnimationLw(WindowState win, int transit) {
1034 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1035 + ": transit=" + transit);
1036 if (win == mStatusBar) {
1037 final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
1038 final boolean expanded = win.getAttrs().height == MATCH_PARENT
1039 && win.getAttrs().width == MATCH_PARENT;
1040 if (isKeyguard || expanded) {
1041 return -1;
1042 }
1043 if (transit == TRANSIT_EXIT
1044 || transit == TRANSIT_HIDE) {
1045 return R.anim.dock_top_exit;
1046 } else if (transit == TRANSIT_ENTER
1047 || transit == TRANSIT_SHOW) {
1048 return R.anim.dock_top_enter;
1049 }
1050 } else if (win == mNavigationBar) {
1051 if (win.getAttrs().windowAnimations != 0) {
1052 return 0;
1053 }
1054 // This can be on either the bottom or the right or the left.
1055 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1056 if (transit == TRANSIT_EXIT
1057 || transit == TRANSIT_HIDE) {
1058 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1059 return R.anim.dock_bottom_exit_keyguard;
1060 } else {
1061 return R.anim.dock_bottom_exit;
1062 }
1063 } else if (transit == TRANSIT_ENTER
1064 || transit == TRANSIT_SHOW) {
1065 return R.anim.dock_bottom_enter;
1066 }
1067 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1068 if (transit == TRANSIT_EXIT
1069 || transit == TRANSIT_HIDE) {
1070 return R.anim.dock_right_exit;
1071 } else if (transit == TRANSIT_ENTER
1072 || transit == TRANSIT_SHOW) {
1073 return R.anim.dock_right_enter;
1074 }
1075 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1076 if (transit == TRANSIT_EXIT
1077 || transit == TRANSIT_HIDE) {
1078 return R.anim.dock_left_exit;
1079 } else if (transit == TRANSIT_ENTER
1080 || transit == TRANSIT_SHOW) {
1081 return R.anim.dock_left_enter;
1082 }
1083 }
1084 } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
1085 return selectDockedDividerAnimationLw(win, transit);
1086 }
1087
1088 if (transit == TRANSIT_PREVIEW_DONE) {
1089 if (win.hasAppShownWindows()) {
1090 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1091 return R.anim.app_starting_exit;
1092 }
1093 } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
1094 && transit == TRANSIT_ENTER) {
1095 // Special case: we are animating in a dream, while the keyguard
1096 // is shown. We don't want an animation on the dream, because
1097 // we need it shown immediately with the keyguard animating away
1098 // to reveal it.
1099 return -1;
1100 }
1101
1102 return 0;
1103 }
1104
1105 private int selectDockedDividerAnimationLw(WindowState win, int transit) {
1106 int insets = mDisplayContent.getDockedDividerController().getContentInsets();
1107
1108 // If the divider is behind the navigation bar, don't animate.
1109 final Rect frame = win.getFrameLw();
1110 final boolean behindNavBar = mNavigationBar != null
1111 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
1112 && frame.top + insets >= mNavigationBar.getFrameLw().top)
1113 || (mNavigationBarPosition == NAV_BAR_RIGHT
1114 && frame.left + insets >= mNavigationBar.getFrameLw().left)
1115 || (mNavigationBarPosition == NAV_BAR_LEFT
1116 && frame.right - insets <= mNavigationBar.getFrameLw().right));
1117 final boolean landscape = frame.height() > frame.width();
1118 final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
1119 || frame.left + insets >= win.getDisplayFrameLw().right);
1120 final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
1121 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1122 final boolean offscreen = offscreenLandscape || offscreenPortrait;
1123 if (behindNavBar || offscreen) {
1124 return 0;
1125 }
1126 if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1127 return R.anim.fade_in;
1128 } else if (transit == TRANSIT_EXIT) {
1129 return R.anim.fade_out;
1130 } else {
1131 return 0;
1132 }
1133 }
1134
1135 /**
1136 * Determine the animation to run for a rotation transition based on the
1137 * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
1138 * and whether it is currently fullscreen and frontmost.
1139 *
1140 * @param anim The exiting animation resource id is stored in anim[0], the
1141 * entering animation resource id is stored in anim[1].
1142 */
1143 public void selectRotationAnimationLw(int anim[]) {
1144 // If the screen is off or non-interactive, force a jumpcut.
1145 final boolean forceJumpcut = !mScreenOnFully || !mService.mPolicy.okToAnimate();
1146 if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
1147 + mTopFullscreenOpaqueWindowState + " rotationAnimation="
1148 + (mTopFullscreenOpaqueWindowState == null
1149 ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)
1150 + " forceJumpcut=" + forceJumpcut);
1151 if (forceJumpcut) {
1152 anim[0] = R.anim.rotation_animation_jump_exit;
1153 anim[1] = R.anim.rotation_animation_enter;
1154 return;
1155 }
1156 if (mTopFullscreenOpaqueWindowState != null) {
1157 int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint();
1158 if (animationHint < 0 && mTopIsFullscreen) {
1159 animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation;
1160 }
1161 switch (animationHint) {
1162 case ROTATION_ANIMATION_CROSSFADE:
1163 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
1164 anim[0] = R.anim.rotation_animation_xfade_exit;
1165 anim[1] = R.anim.rotation_animation_enter;
1166 break;
1167 case ROTATION_ANIMATION_JUMPCUT:
1168 anim[0] = R.anim.rotation_animation_jump_exit;
1169 anim[1] = R.anim.rotation_animation_enter;
1170 break;
1171 case ROTATION_ANIMATION_ROTATE:
1172 default:
1173 anim[0] = anim[1] = 0;
1174 break;
1175 }
1176 } else {
1177 anim[0] = anim[1] = 0;
1178 }
1179 }
1180
1181 /**
1182 * Validate whether the current top fullscreen has specified the same
1183 * {@link WindowManager.LayoutParams#rotationAnimation} value as that
1184 * being passed in from the previous top fullscreen window.
1185 *
1186 * @param exitAnimId exiting resource id from the previous window.
1187 * @param enterAnimId entering resource id from the previous window.
1188 * @param forceDefault For rotation animations only, if true ignore the
1189 * animation values and just return false.
1190 * @return true if the previous values are still valid, false if they
1191 * should be replaced with the default.
1192 */
1193 public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
1194 boolean forceDefault) {
1195 switch (exitAnimId) {
1196 case R.anim.rotation_animation_xfade_exit:
1197 case R.anim.rotation_animation_jump_exit:
1198 // These are the only cases that matter.
1199 if (forceDefault) {
1200 return false;
1201 }
1202 int anim[] = new int[2];
1203 selectRotationAnimationLw(anim);
1204 return (exitAnimId == anim[0] && enterAnimId == anim[1]);
1205 default:
1206 return true;
1207 }
1208 }
1209
1210 /**
1211 * Called when a new system UI visibility is being reported, allowing
1212 * the policy to adjust what is actually reported.
1213 * @param visibility The raw visibility reported by the status bar.
1214 * @return The new desired visibility.
1215 */
1216 public int adjustSystemUiVisibilityLw(int visibility) {
1217 mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1218 mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1219
1220 // Reset any bits in mForceClearingStatusBarVisibility that
1221 // are now clear.
1222 mResettingSystemUiFlags &= visibility;
1223 // Clear any bits in the new visibility that are currently being
1224 // force cleared, before reporting it.
1225 return visibility & ~mResettingSystemUiFlags
1226 & ~mForceClearedSystemUiFlags;
1227 }
1228
1229 /**
Brad Stenninge0573692019-03-11 13:52:46 -07001230 * @return true if the system bars are forced to stay visible
Tiger Huang7c610aa2018-10-27 00:01:01 +08001231 */
Brad Stenninge0573692019-03-11 13:52:46 -07001232 public boolean areSystemBarsForcedShownLw(WindowState windowState) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001233 return mForceShowSystemBars;
1234 }
1235
1236 // TODO: Should probably be moved into DisplayFrames.
1237 /**
1238 * Return the layout hints for a newly added window. These values are computed on the
1239 * most recent layout, so they are not guaranteed to be correct.
1240 *
1241 * @param attrs The LayoutParams of the window.
1242 * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1243 * associated with the window.
1244 * @param displayFrames display frames.
1245 * @param floatingStack Whether the window's stack is floating.
1246 * @param outFrame The frame of the window.
1247 * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1248 * @param outStableInsets The areas covered by stable system windows irrespective of their
1249 * current visibility. Expressed as positive insets.
1250 * @param outOutsets The areas that are not real display, but we would like to treat as such.
1251 * @param outDisplayCutout The area that has been cut away from the display.
Brad Stenninge0573692019-03-11 13:52:46 -07001252 * @return Whether to always consume the system bars.
1253 * See {@link #areSystemBarsForcedShownLw(WindowState)}.
Tiger Huang7c610aa2018-10-27 00:01:01 +08001254 */
1255 public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1256 DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1257 Rect outContentInsets, Rect outStableInsets,
1258 Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
1259 final int fl = PolicyControl.getWindowFlags(null, attrs);
1260 final int pfl = attrs.privateFlags;
1261 final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1262 final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
1263 final int displayRotation = displayFrames.mRotation;
1264
1265 final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
1266 if (useOutsets) {
Jorim Jaggi4981f152019-03-26 18:58:45 +01001267 int outset = mWindowOutsetBottom;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001268 if (outset > 0) {
1269 if (displayRotation == Surface.ROTATION_0) {
1270 outOutsets.bottom += outset;
1271 } else if (displayRotation == Surface.ROTATION_90) {
1272 outOutsets.right += outset;
1273 } else if (displayRotation == Surface.ROTATION_180) {
1274 outOutsets.top += outset;
1275 } else if (displayRotation == Surface.ROTATION_270) {
1276 outOutsets.left += outset;
1277 }
1278 }
1279 }
1280
1281 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1282 final boolean layoutInScreenAndInsetDecor = layoutInScreen
1283 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1284 final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1285
1286 if (layoutInScreenAndInsetDecor && !screenDecor) {
Jorim Jaggid6490572019-04-16 14:57:56 +02001287 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001288 outFrame.set(displayFrames.mUnrestricted);
1289 } else {
1290 outFrame.set(displayFrames.mRestricted);
1291 }
1292
1293 final Rect sf;
1294 if (floatingStack) {
1295 sf = null;
1296 } else {
1297 sf = displayFrames.mStable;
1298 }
1299
1300 final Rect cf;
1301 if (floatingStack) {
1302 cf = null;
1303 } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1304 if ((fl & FLAG_FULLSCREEN) != 0) {
1305 cf = displayFrames.mStableFullscreen;
1306 } else {
1307 cf = displayFrames.mStable;
1308 }
1309 } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
1310 cf = displayFrames.mOverscan;
1311 } else {
1312 cf = displayFrames.mCurrent;
1313 }
1314
1315 if (taskBounds != null) {
1316 outFrame.intersect(taskBounds);
1317 }
1318 InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1319 InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1320 outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1321 .getDisplayCutout());
1322 return mForceShowSystemBars;
1323 } else {
1324 if (layoutInScreen) {
1325 outFrame.set(displayFrames.mUnrestricted);
1326 } else {
1327 outFrame.set(displayFrames.mStable);
1328 }
1329 if (taskBounds != null) {
1330 outFrame.intersect(taskBounds);
1331 }
1332
1333 outContentInsets.setEmpty();
1334 outStableInsets.setEmpty();
1335 outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1336 return mForceShowSystemBars;
1337 }
1338 }
1339
1340 private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1341 int impliedFlags = 0;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001342 final boolean forceWindowDrawsBarBackgrounds =
1343 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1344 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001345 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001346 || forceWindowDrawsBarBackgrounds) {
Jorim Jaggid6490572019-04-16 14:57:56 +02001347 impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001348 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1349 }
1350 return impliedFlags;
1351 }
1352
1353 private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
1354 return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
1355 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
1356 }
1357
1358 private final Runnable mClearHideNavigationFlag = new Runnable() {
1359 @Override
1360 public void run() {
1361 synchronized (mLock) {
1362 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1363 mDisplayContent.reevaluateStatusBarVisibility();
1364 }
1365 }
1366 };
1367
1368 /**
1369 * Input handler used while nav bar is hidden. Captures any touch on the screen,
1370 * to determine when the nav bar should be shown and prevent applications from
1371 * receiving those touches.
1372 */
1373 private final class HideNavInputEventReceiver extends InputEventReceiver {
1374 HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1375 super(inputChannel, looper);
1376 }
1377
1378 @Override
1379 public void onInputEvent(InputEvent event) {
1380 try {
1381 if (event instanceof MotionEvent
1382 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1383 final MotionEvent motionEvent = (MotionEvent) event;
1384 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1385 // When the user taps down, we re-show the nav bar.
1386 boolean changed = false;
1387 synchronized (mLock) {
1388 if (mInputConsumer == null) {
1389 return;
1390 }
1391 // Any user activity always causes us to show the
1392 // navigation controls, if they had been hidden.
1393 // We also clear the low profile and only content
1394 // flags so that tapping on the screen will atomically
1395 // restore all currently hidden screen decorations.
1396 int newVal = mResettingSystemUiFlags
1397 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1398 | View.SYSTEM_UI_FLAG_LOW_PROFILE
1399 | View.SYSTEM_UI_FLAG_FULLSCREEN;
1400 if (mResettingSystemUiFlags != newVal) {
1401 mResettingSystemUiFlags = newVal;
1402 changed = true;
1403 }
1404 // We don't allow the system's nav bar to be hidden
1405 // again for 1 second, to prevent applications from
1406 // spamming us and keeping it from being shown.
1407 newVal = mForceClearedSystemUiFlags
1408 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1409 if (mForceClearedSystemUiFlags != newVal) {
1410 mForceClearedSystemUiFlags = newVal;
1411 changed = true;
1412 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1413 }
1414 if (changed) {
1415 mDisplayContent.reevaluateStatusBarVisibility();
1416 }
1417 }
1418 }
1419 }
1420 } finally {
1421 finishInputEvent(event, false /* handled */);
1422 }
1423 }
1424 }
1425
1426 /**
1427 * Called when layout of the windows is about to start.
1428 *
1429 * @param displayFrames frames of the display we are doing layout on.
1430 * @param uiMode The current uiMode in configuration.
1431 */
1432 public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1433 displayFrames.onBeginLayout();
1434 mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1435 mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1436
1437 // For purposes of putting out fake window up to steal focus, we will
1438 // drive nav being hidden only by whether it is requested.
1439 final int sysui = mLastSystemUiFlags;
1440 boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
1441 boolean navTranslucent = (sysui
1442 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
1443 boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
1444 boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
1445 boolean navAllowedHidden = immersive || immersiveSticky;
1446 navTranslucent &= !immersiveSticky; // transient trumps translucent
1447 boolean isKeyguardShowing = isStatusBarKeyguard()
1448 && !mService.mPolicy.isKeyguardOccluded();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001449 boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
1450 && (mStatusBar.getAttrs().privateFlags
1451 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1452
1453 // When the navigation bar isn't visible, we put up a fake input window to catch all
1454 // touch events. This way we can detect when the user presses anywhere to bring back the
1455 // nav bar and ensure the application doesn't see the event.
1456 if (navVisible || navAllowedHidden) {
1457 if (mInputConsumer != null) {
1458 mHandler.sendMessage(
1459 mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1460 mInputConsumer = null;
1461 }
1462 } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1463 mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1464 INPUT_CONSUMER_NAVIGATION,
1465 HideNavInputEventReceiver::new,
1466 displayFrames.mDisplayId);
1467 // As long as mInputConsumer is active, hover events are not dispatched to the app
1468 // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1469 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1470 }
1471
1472 // For purposes of positioning and showing the nav bar, if we have decided that it can't
1473 // be hidden (because of the screen aspect ratio), then take that into account.
1474 navVisible |= !canHideNavigationBar();
1475
1476 boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
1477 navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
1478 if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1479 updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1480 if (updateSysUiVisibility) {
1481 updateSystemUiVisibilityLw();
1482 }
1483 layoutScreenDecorWindows(displayFrames);
1484
1485 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1486 // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1487 // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1488 // bar.
1489 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1490 displayFrames.mStable.top);
1491 }
Issei Suzukia5dbf522019-02-01 17:58:15 +01001492
1493 // In case this is a virtual display, and the host display has insets that overlap this
1494 // virtual display, apply the insets of the overlapped area onto the current and content
1495 // frame of this virtual display. This let us layout windows in the virtual display as
1496 // expected when the window needs to avoid overlap with the system windows.
1497 // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1498 // IME.
1499 displayFrames.mCurrent.inset(mForwardedInsets);
1500 displayFrames.mContent.inset(mForwardedInsets);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001501 }
1502
1503 private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1504 if (mScreenDecorWindows.isEmpty()) {
1505 return;
1506 }
1507
1508 sTmpRect.setEmpty();
Tiger Huang7c610aa2018-10-27 00:01:01 +08001509 final int displayId = displayFrames.mDisplayId;
1510 final Rect dockFrame = displayFrames.mDock;
1511 final int displayHeight = displayFrames.mDisplayHeight;
1512 final int displayWidth = displayFrames.mDisplayWidth;
1513
1514 for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1515 final WindowState w = mScreenDecorWindows.valueAt(i);
1516 if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1517 // Skip if not on the same display or not visible.
1518 continue;
1519 }
1520
chaviw0d833762019-06-20 17:09:53 -07001521 w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1522 displayFrames.mUnrestricted /* displayFrame */,
1523 displayFrames.mUnrestricted /* overscanFrame */,
1524 displayFrames.mUnrestricted /* contentFrame */,
1525 displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
1526 displayFrames.mUnrestricted /* stableFrame */,
1527 displayFrames.mUnrestricted /* outsetFrame */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001528 w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1529 w.computeFrameLw();
1530 final Rect frame = w.getFrameLw();
1531
1532 if (frame.left <= 0 && frame.top <= 0) {
1533 // Docked at left or top.
1534 if (frame.bottom >= displayHeight) {
1535 // Docked left.
1536 dockFrame.left = Math.max(frame.right, dockFrame.left);
1537 } else if (frame.right >= displayWidth) {
1538 // Docked top.
1539 dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1540 } else {
1541 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1542 + " not docked on left or top of display. frame=" + frame
1543 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1544 }
1545 } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1546 // Docked at right or bottom.
1547 if (frame.top <= 0) {
1548 // Docked right.
1549 dockFrame.right = Math.min(frame.left, dockFrame.right);
1550 } else if (frame.left <= 0) {
1551 // Docked bottom.
1552 dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1553 } else {
1554 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1555 + " not docked on right or bottom" + " of display. frame=" + frame
1556 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1557 }
1558 } else {
1559 // Screen decor windows are required to be docked on one of the sides of the screen.
1560 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1561 + " not docked on one of the sides of the display. frame=" + frame
1562 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1563 }
1564 }
1565
1566 displayFrames.mRestricted.set(dockFrame);
1567 displayFrames.mCurrent.set(dockFrame);
1568 displayFrames.mVoiceContent.set(dockFrame);
1569 displayFrames.mSystem.set(dockFrame);
1570 displayFrames.mContent.set(dockFrame);
1571 displayFrames.mRestrictedOverscan.set(dockFrame);
1572 }
1573
1574 private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1575 boolean isKeyguardShowing) {
1576 // decide where the status bar goes ahead of time
1577 if (mStatusBar == null) {
1578 return false;
1579 }
1580 // apply any navigation bar insets
1581 sTmpRect.setEmpty();
Jorim Jaggi4981f152019-03-26 18:58:45 +01001582 final WindowFrames windowFrames = mStatusBar.getWindowFrames();
1583 windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
Tiger Huang7c610aa2018-10-27 00:01:01 +08001584 displayFrames.mUnrestricted /* displayFrame */,
1585 displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
1586 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
1587 displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
Jorim Jaggi4981f152019-03-26 18:58:45 +01001588 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001589
1590 // Let the status bar determine its size.
1591 mStatusBar.computeFrameLw();
1592
1593 // For layout, the status bar is always at the top with our fixed height.
1594 displayFrames.mStable.top = displayFrames.mUnrestricted.top
1595 + mStatusBarHeightForRotation[displayFrames.mRotation];
1596 // Make sure the status bar covers the entire cutout height
1597 displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1598 displayFrames.mDisplayCutoutSafe.top);
1599
1600 // Tell the bar controller where the collapsed status bar content is
1601 sTmpRect.set(mStatusBar.getContentFrameLw());
1602 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1603 sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
1604 sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
1605 mStatusBarController.setContentFrame(sTmpRect);
1606
1607 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
1608 boolean statusBarTranslucent = (sysui
1609 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08001610
1611 // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1612 if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1613 // Status bar may go away, so the screen area it occupies is available to apps but just
1614 // covering them when the status bar is visible.
1615 final Rect dockFrame = displayFrames.mDock;
1616 dockFrame.top = displayFrames.mStable.top;
1617 displayFrames.mContent.set(dockFrame);
1618 displayFrames.mVoiceContent.set(dockFrame);
1619 displayFrames.mCurrent.set(dockFrame);
1620
1621 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1622 "dock=%s content=%s cur=%s", dockFrame.toString(),
1623 displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1624
Jorim Jaggi4981f152019-03-26 18:58:45 +01001625 if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
1626 && !mStatusBar.isAnimatingLw()) {
1627
Tiger Huang7c610aa2018-10-27 00:01:01 +08001628 // If the opaque status bar is currently requested to be visible, and not in the
1629 // process of animating on or off, then we can tell the app that it is covered by
1630 // it.
1631 displayFrames.mSystem.top = displayFrames.mStable.top;
1632 }
1633 }
1634 return mStatusBarController.checkHiddenLw();
1635 }
1636
1637 private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1638 boolean navTranslucent, boolean navAllowedHidden,
1639 boolean statusBarForcesShowingNavigation) {
1640 if (mNavigationBar == null) {
1641 return false;
1642 }
1643
1644 final Rect navigationFrame = sTmpNavFrame;
1645 boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1646 // Force the navigation bar to its appropriate place and size. We need to do this directly,
1647 // instead of relying on it to bubble up from the nav bar, because this needs to change
1648 // atomically with screen rotations.
1649 final int rotation = displayFrames.mRotation;
1650 final int displayHeight = displayFrames.mDisplayHeight;
1651 final int displayWidth = displayFrames.mDisplayWidth;
1652 final Rect dockFrame = displayFrames.mDock;
1653 mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1654
1655 final Rect cutoutSafeUnrestricted = sTmpRect;
1656 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1657 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1658
1659 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1660 // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1661 final int top = cutoutSafeUnrestricted.bottom
1662 - getNavigationBarHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001663 final int topNavBar = cutoutSafeUnrestricted.bottom
Matthew Nga7f24bc2019-04-09 17:06:41 -07001664 - getNavigationBarFrameHeight(rotation, uiMode);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001665 navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001666 displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1667 if (transientNavBarShowing) {
1668 mNavigationBarController.setBarShowingLw(true);
1669 } else if (navVisible) {
1670 mNavigationBarController.setBarShowingLw(true);
1671 dockFrame.bottom = displayFrames.mRestricted.bottom =
1672 displayFrames.mRestrictedOverscan.bottom = top;
1673 } else {
1674 // We currently want to hide the navigation UI - unless we expanded the status bar.
1675 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1676 }
1677 if (navVisible && !navTranslucent && !navAllowedHidden
1678 && !mNavigationBar.isAnimatingLw()
1679 && !mNavigationBarController.wasRecentlyTranslucent()) {
1680 // If the opaque nav bar is currently requested to be visible and not in the process
1681 // of animating on or off, then we can tell the app that it is covered by it.
1682 displayFrames.mSystem.bottom = top;
1683 }
1684 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1685 // Landscape screen; nav bar goes to the right.
1686 final int left = cutoutSafeUnrestricted.right
1687 - getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001688 navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001689 displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1690 if (transientNavBarShowing) {
1691 mNavigationBarController.setBarShowingLw(true);
1692 } else if (navVisible) {
1693 mNavigationBarController.setBarShowingLw(true);
1694 dockFrame.right = displayFrames.mRestricted.right =
1695 displayFrames.mRestrictedOverscan.right = left;
1696 } else {
1697 // We currently want to hide the navigation UI - unless we expanded the status bar.
1698 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1699 }
1700 if (navVisible && !navTranslucent && !navAllowedHidden
1701 && !mNavigationBar.isAnimatingLw()
1702 && !mNavigationBarController.wasRecentlyTranslucent()) {
1703 // If the nav bar is currently requested to be visible, and not in the process of
1704 // animating on or off, then we can tell the app that it is covered by it.
1705 displayFrames.mSystem.right = left;
1706 }
1707 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1708 // Seascape screen; nav bar goes to the left.
1709 final int right = cutoutSafeUnrestricted.left
1710 + getNavigationBarWidth(rotation, uiMode);
Matthew Nga7f24bc2019-04-09 17:06:41 -07001711 navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001712 displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1713 if (transientNavBarShowing) {
1714 mNavigationBarController.setBarShowingLw(true);
1715 } else if (navVisible) {
1716 mNavigationBarController.setBarShowingLw(true);
1717 dockFrame.left = displayFrames.mRestricted.left =
1718 displayFrames.mRestrictedOverscan.left = right;
1719 } else {
1720 // We currently want to hide the navigation UI - unless we expanded the status bar.
1721 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1722 }
1723 if (navVisible && !navTranslucent && !navAllowedHidden
1724 && !mNavigationBar.isAnimatingLw()
1725 && !mNavigationBarController.wasRecentlyTranslucent()) {
1726 // If the nav bar is currently requested to be visible, and not in the process of
1727 // animating on or off, then we can tell the app that it is covered by it.
1728 displayFrames.mSystem.left = right;
1729 }
1730 }
1731
1732 // Make sure the content and current rectangles are updated to account for the restrictions
1733 // from the navigation bar.
1734 displayFrames.mCurrent.set(dockFrame);
1735 displayFrames.mVoiceContent.set(dockFrame);
1736 displayFrames.mContent.set(dockFrame);
1737 // And compute the final frame.
1738 sTmpRect.setEmpty();
1739 mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
1740 navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
1741 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1742 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
1743 navigationFrame /* stableFrame */,
1744 displayFrames.mDisplayCutoutSafe /* outsetFrame */);
1745 mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1746 mNavigationBar.computeFrameLw();
1747 mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1748
1749 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1750 return mNavigationBarController.checkHiddenLw();
1751 }
1752
1753 private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
1754 boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
1755 DisplayFrames displayFrames) {
1756 if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1757 // Here's a special case: if the child window is not the 'dock window'
1758 // or input method target, and the window it is attached to is below
1759 // the dock window, then the frames we computed for the window it is
1760 // attached to can not be used because the dock is effectively part
1761 // of the underlying window and the attached window is floating on top
1762 // of the whole thing. So, we ignore the attached window and explicitly
1763 // compute the frames that would be appropriate without the dock.
1764 vf.set(displayFrames.mDock);
1765 cf.set(displayFrames.mDock);
1766 of.set(displayFrames.mDock);
1767 df.set(displayFrames.mDock);
1768 } else {
Jorim Jaggid6490572019-04-16 14:57:56 +02001769
1770 // In case we forced the window to draw behind the navigation bar, restrict df/of to
1771 // DF.RestrictedOverscan to simulate old compat behavior.
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001772 Rect parentDisplayFrame = attached.getDisplayFrameLw();
1773 Rect parentOverscan = attached.getOverscanFrameLw();
Jorim Jaggid6490572019-04-16 14:57:56 +02001774 final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
1775 if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1776 && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1777 && (attachedAttrs.systemUiVisibility
1778 & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001779 parentOverscan = new Rect(parentOverscan);
Jorim Jaggid6490572019-04-16 14:57:56 +02001780 parentOverscan.intersect(displayFrames.mRestrictedOverscan);
Jorim Jaggia72b4cc2019-04-16 15:38:49 +02001781 parentDisplayFrame = new Rect(parentDisplayFrame);
Jorim Jaggid6490572019-04-16 14:57:56 +02001782 parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan);
1783 }
1784
Tiger Huang7c610aa2018-10-27 00:01:01 +08001785 // The effective display frame of the attached window depends on whether it is taking
1786 // care of insetting its content. If not, we need to use the parent's content frame so
1787 // that the entire window is positioned within that content. Otherwise we can use the
1788 // overscan frame and let the attached window take care of positioning its content
1789 // appropriately.
1790 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1791 // Set the content frame of the attached window to the parent's decor frame
1792 // (same as content frame when IME isn't present) if specifically requested by
1793 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1794 // Otherwise, use the overscan frame.
1795 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
Jorim Jaggid6490572019-04-16 14:57:56 +02001796 ? attached.getContentFrameLw() : parentOverscan);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001797 } else {
1798 // If the window is resizing, then we want to base the content frame on our attached
1799 // content frame to resize...however, things can be tricky if the attached window is
1800 // NOT in resize mode, in which case its content frame will be larger.
1801 // Ungh. So to deal with that, make sure the content frame we end up using is not
1802 // covering the IM dock.
1803 cf.set(attached.getContentFrameLw());
1804 if (attached.isVoiceInteraction()) {
1805 cf.intersectUnchecked(displayFrames.mVoiceContent);
1806 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1807 cf.intersectUnchecked(displayFrames.mContent);
1808 }
1809 }
Jorim Jaggid6490572019-04-16 14:57:56 +02001810 df.set(insetDecors ? parentDisplayFrame : cf);
1811 of.set(insetDecors ? parentOverscan : cf);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001812 vf.set(attached.getVisibleFrameLw());
1813 }
1814 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1815 // positioned relative to its parent or the entire screen.
1816 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1817 }
1818
1819 private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1820 if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1821 return;
1822 }
1823 // If app is requesting a stable layout, don't let the content insets go below the stable
1824 // values.
1825 if ((fl & FLAG_FULLSCREEN) != 0) {
1826 r.intersectUnchecked(displayFrames.mStableFullscreen);
1827 } else {
1828 r.intersectUnchecked(displayFrames.mStable);
1829 }
1830 }
1831
1832 private boolean canReceiveInput(WindowState win) {
1833 boolean notFocusable =
1834 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1835 boolean altFocusableIm =
1836 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1837 boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1838 return !notFocusableForIm;
1839 }
1840
1841 /**
1842 * Called for each window attached to the window manager as layout is proceeding. The
1843 * implementation of this function must take care of setting the window's frame, either here or
1844 * in finishLayout().
1845 *
1846 * @param win The window being positioned.
1847 * @param attached For sub-windows, the window it is attached to; this
1848 * window will already have had layoutWindow() called on it
1849 * so you can use its Rect. Otherwise null.
1850 * @param displayFrames The display frames.
1851 */
1852 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1853 // We've already done the navigation bar, status bar, and all screen decor windows. If the
1854 // status bar can receive input, we need to layout it again to accommodate for the IME
1855 // window.
1856 if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1857 || mScreenDecorWindows.contains(win)) {
1858 return;
1859 }
1860 final WindowManager.LayoutParams attrs = win.getAttrs();
1861 final boolean isDefaultDisplay = win.isDefaultDisplay();
1862
1863 final int type = attrs.type;
1864 final int fl = PolicyControl.getWindowFlags(win, attrs);
1865 final int pfl = attrs.privateFlags;
1866 final int sim = attrs.softInputMode;
1867 final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1868 final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1869
1870 final WindowFrames windowFrames = win.getWindowFrames();
1871
1872 windowFrames.setHasOutsets(false);
1873 sTmpLastParentFrame.set(windowFrames.mParentFrame);
1874 final Rect pf = windowFrames.mParentFrame;
1875 final Rect df = windowFrames.mDisplayFrame;
1876 final Rect of = windowFrames.mOverscanFrame;
1877 final Rect cf = windowFrames.mContentFrame;
1878 final Rect vf = windowFrames.mVisibleFrame;
1879 final Rect dcf = windowFrames.mDecorFrame;
1880 final Rect sf = windowFrames.mStableFrame;
1881 dcf.setEmpty();
1882 windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1883 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1884
1885 final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1886 && mNavigationBar.isVisibleLw();
1887
1888 final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1889
1890 final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
1891 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
1892
1893 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1894 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1895
1896 sf.set(displayFrames.mStable);
1897
1898 if (type == TYPE_INPUT_METHOD) {
1899 vf.set(displayFrames.mDock);
1900 cf.set(displayFrames.mDock);
1901 of.set(displayFrames.mDock);
1902 df.set(displayFrames.mDock);
1903 windowFrames.mParentFrame.set(displayFrames.mDock);
1904 // IM dock windows layout below the nav bar...
1905 pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
1906 // ...with content insets above the nav bar
1907 cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1908 if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1909 // The status bar forces the navigation bar while it's visible. Make sure the IME
1910 // avoids the navigation bar in that case.
1911 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1912 pf.right = df.right = of.right = cf.right = vf.right =
1913 displayFrames.mStable.right;
1914 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1915 pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
1916 }
1917 }
1918
Matthew Nga7f24bc2019-04-09 17:06:41 -07001919 // In case the navigation bar is on the bottom, we use the frame height instead of the
1920 // regular height for the insets we send to the IME as we need some space to show
1921 // additional buttons in SystemUI when the IME is up.
1922 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1923 final int rotation = displayFrames.mRotation;
1924 final int uimode = mService.mPolicy.getUiMode();
1925 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
1926 - getNavigationBarHeight(rotation, uimode);
1927 if (navHeightOffset > 0) {
1928 cf.bottom -= navHeightOffset;
1929 sf.bottom -= navHeightOffset;
1930 vf.bottom -= navHeightOffset;
1931 dcf.bottom -= navHeightOffset;
1932 }
1933 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001934
1935 // IM dock windows always go to the bottom of the screen.
1936 attrs.gravity = Gravity.BOTTOM;
1937 } else if (type == TYPE_VOICE_INTERACTION) {
1938 of.set(displayFrames.mUnrestricted);
1939 df.set(displayFrames.mUnrestricted);
1940 pf.set(displayFrames.mUnrestricted);
1941 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1942 cf.set(displayFrames.mDock);
1943 } else {
1944 cf.set(displayFrames.mContent);
1945 }
1946 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1947 vf.set(displayFrames.mCurrent);
1948 } else {
1949 vf.set(cf);
1950 }
1951 } else if (type == TYPE_WALLPAPER) {
1952 layoutWallpaper(displayFrames, pf, df, of, cf);
1953 } else if (win == mStatusBar) {
1954 of.set(displayFrames.mUnrestricted);
1955 df.set(displayFrames.mUnrestricted);
1956 pf.set(displayFrames.mUnrestricted);
1957 cf.set(displayFrames.mStable);
1958 vf.set(displayFrames.mStable);
1959
1960 if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
1961 cf.bottom = displayFrames.mContent.bottom;
1962 } else {
1963 cf.bottom = displayFrames.mDock.bottom;
1964 vf.bottom = displayFrames.mContent.bottom;
1965 }
1966 } else {
1967 dcf.set(displayFrames.mSystem);
1968 final boolean inheritTranslucentDecor =
1969 (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
1970 final boolean isAppWindow =
1971 type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1972 final boolean topAtRest =
1973 win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
1974 if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
1975 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
1976 && (fl & FLAG_FULLSCREEN) == 0
1977 && (fl & FLAG_TRANSLUCENT_STATUS) == 0
1978 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001979 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001980 // Ensure policy decor includes status bar
1981 dcf.top = displayFrames.mStable.top;
1982 }
1983 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
1984 && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
Jorim Jaggia6aabac2019-03-11 14:23:16 -07001985 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1986 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001987 // Ensure policy decor includes navigation bar
1988 dcf.bottom = displayFrames.mStable.bottom;
1989 dcf.right = displayFrames.mStable.right;
1990 }
1991 }
1992
1993 if (layoutInScreen && layoutInsetDecor) {
1994 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1995 + "): IN_SCREEN, INSET_DECOR");
1996 // This is the case for a normal activity window: we want it to cover all of the
1997 // screen space, and it can take care of moving its contents to account for screen
1998 // decorations that intrude into that space.
1999 if (attached != null) {
2000 // If this window is attached to another, our display
2001 // frame is the same as the one we are attached to.
2002 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
2003 displayFrames);
2004 } else {
2005 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2006 // Status bar panels are the only windows who can go on top of the status
2007 // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
2008 // have the same privileges as the status bar itself.
2009 //
2010 // However, they should still dodge the navigation bar if it exists.
2011
2012 pf.left = df.left = of.left = hasNavBar
2013 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
2014 pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
2015 pf.right = df.right = of.right = hasNavBar
2016 ? displayFrames.mRestricted.right
2017 : displayFrames.mUnrestricted.right;
2018 pf.bottom = df.bottom = of.bottom = hasNavBar
2019 ? displayFrames.mRestricted.bottom
2020 : displayFrames.mUnrestricted.bottom;
2021
2022 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
2023 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2024 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2025 // Asking to layout into the overscan region, so give it that pure
2026 // unrestricted area.
2027 of.set(displayFrames.mOverscan);
2028 df.set(displayFrames.mOverscan);
2029 pf.set(displayFrames.mOverscan);
Jorim Jaggid6490572019-04-16 14:57:56 +02002030 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08002031 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
Charles Chen64172bb2019-04-22 17:30:29 +08002032 || type == TYPE_VOLUME_OVERLAY
2033 || type == TYPE_KEYGUARD_DIALOG)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002034 // Asking for layout as if the nav bar is hidden, lets the application
2035 // extend into the unrestricted overscan screen area. We only do this for
2036 // application windows and certain system windows to ensure no window that
2037 // can be above the nav bar can do this.
2038 df.set(displayFrames.mOverscan);
2039 pf.set(displayFrames.mOverscan);
2040 // We need to tell the app about where the frame inside the overscan is, so
2041 // it can inset its content by that amount -- it didn't ask to actually
2042 // extend itself into the overscan region.
2043 of.set(displayFrames.mUnrestricted);
2044 } else {
2045 df.set(displayFrames.mRestrictedOverscan);
2046 pf.set(displayFrames.mRestrictedOverscan);
2047 // We need to tell the app about where the frame inside the overscan
2048 // is, so it can inset its content by that amount -- it didn't ask
2049 // to actually extend itself into the overscan region.
2050 of.set(displayFrames.mUnrestricted);
2051 }
2052
2053 if ((fl & FLAG_FULLSCREEN) == 0) {
2054 if (win.isVoiceInteraction()) {
2055 cf.set(displayFrames.mVoiceContent);
2056 } else {
Jorim Jaggi648e5882019-01-24 13:24:02 +01002057 // IME Insets are handled on the client for ADJUST_RESIZE in the new
2058 // insets world
2059 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2060 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002061 cf.set(displayFrames.mDock);
2062 } else {
2063 cf.set(displayFrames.mContent);
2064 }
2065 }
2066 } else {
2067 // Full screen windows are always given a layout that is as if the status
2068 // bar and other transient decors are gone. This is to avoid bad states when
2069 // moving from a window that is not hiding the status bar to one that is.
2070 cf.set(displayFrames.mRestricted);
2071 }
2072 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2073 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2074 vf.set(displayFrames.mCurrent);
2075 } else {
2076 vf.set(cf);
2077 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002078 }
2079 } else if (layoutInScreen || (sysUiFl
2080 & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Jorim Jaggid6490572019-04-16 14:57:56 +02002081 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002082 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2083 + "): IN_SCREEN");
2084 // A window that has requested to fill the entire screen just
2085 // gets everything, period.
2086 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2087 cf.set(displayFrames.mUnrestricted);
2088 of.set(displayFrames.mUnrestricted);
2089 df.set(displayFrames.mUnrestricted);
2090 pf.set(displayFrames.mUnrestricted);
2091 if (hasNavBar) {
2092 pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
2093 pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
2094 pf.bottom = df.bottom = of.bottom = cf.bottom =
2095 displayFrames.mRestricted.bottom;
2096 }
2097 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
2098 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
2099 // The navigation bar has Real Ultimate Power.
2100 of.set(displayFrames.mUnrestricted);
2101 df.set(displayFrames.mUnrestricted);
2102 pf.set(displayFrames.mUnrestricted);
2103 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
2104 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
2105 && ((fl & FLAG_FULLSCREEN) != 0)) {
2106 // Fullscreen secure system overlays get what they ask for. Screenshot region
2107 // selection overlay should also expand to full screen.
2108 cf.set(displayFrames.mOverscan);
2109 of.set(displayFrames.mOverscan);
2110 df.set(displayFrames.mOverscan);
2111 pf.set(displayFrames.mOverscan);
2112 } else if (type == TYPE_BOOT_PROGRESS) {
2113 // Boot progress screen always covers entire display.
2114 cf.set(displayFrames.mOverscan);
2115 of.set(displayFrames.mOverscan);
2116 df.set(displayFrames.mOverscan);
2117 pf.set(displayFrames.mOverscan);
2118 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2119 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2120 // Asking to layout into the overscan region, so give it that pure unrestricted
2121 // area.
2122 cf.set(displayFrames.mOverscan);
2123 of.set(displayFrames.mOverscan);
2124 df.set(displayFrames.mOverscan);
2125 pf.set(displayFrames.mOverscan);
Jorim Jaggid6490572019-04-16 14:57:56 +02002126 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
Tiger Huang7c610aa2018-10-27 00:01:01 +08002127 && (type == TYPE_STATUS_BAR
2128 || type == TYPE_TOAST
2129 || type == TYPE_DOCK_DIVIDER
2130 || type == TYPE_VOICE_INTERACTION_STARTING
2131 || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
2132 // Asking for layout as if the nav bar is hidden, lets the
2133 // application extend into the unrestricted screen area. We
2134 // only do this for application windows (or toasts) to ensure no window that
2135 // can be above the nav bar can do this.
2136 // XXX This assumes that an app asking for this will also
2137 // ask for layout in only content. We can't currently figure out
2138 // what the screen would be if only laying out to hide the nav bar.
2139 cf.set(displayFrames.mUnrestricted);
2140 of.set(displayFrames.mUnrestricted);
2141 df.set(displayFrames.mUnrestricted);
2142 pf.set(displayFrames.mUnrestricted);
2143 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
2144 of.set(displayFrames.mRestricted);
2145 df.set(displayFrames.mRestricted);
2146 pf.set(displayFrames.mRestricted);
Jorim Jaggi648e5882019-01-24 13:24:02 +01002147
2148 // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2149 // world
2150 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2151 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002152 cf.set(displayFrames.mDock);
2153 } else {
2154 cf.set(displayFrames.mContent);
2155 }
2156 } else {
2157 cf.set(displayFrames.mRestricted);
2158 of.set(displayFrames.mRestricted);
2159 df.set(displayFrames.mRestricted);
2160 pf.set(displayFrames.mRestricted);
2161 }
2162
2163 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2164
2165 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2166 vf.set(displayFrames.mCurrent);
2167 } else {
2168 vf.set(cf);
2169 }
2170 } else if (attached != null) {
2171 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2172 + "): attached to " + attached);
2173 // A child window should be placed inside of the same visible
2174 // frame that its parent had.
2175 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
2176 displayFrames);
2177 } else {
2178 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2179 + "): normal window");
2180 // Otherwise, a normal window must be placed inside the content
2181 // of all screen decorations.
2182 if (type == TYPE_STATUS_BAR_PANEL) {
2183 // Status bar panels can go on
2184 // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2185 // permission, so they have the same privileges as the status bar itself.
2186 cf.set(displayFrames.mRestricted);
2187 of.set(displayFrames.mRestricted);
2188 df.set(displayFrames.mRestricted);
2189 pf.set(displayFrames.mRestricted);
Vishnu Nair9ccb1d22019-03-20 16:32:44 +00002190 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002191 // These dialogs are stable to interim decor changes.
2192 cf.set(displayFrames.mStable);
2193 of.set(displayFrames.mStable);
2194 df.set(displayFrames.mStable);
2195 pf.set(displayFrames.mStable);
2196 } else {
2197 pf.set(displayFrames.mContent);
2198 if (win.isVoiceInteraction()) {
2199 cf.set(displayFrames.mVoiceContent);
2200 of.set(displayFrames.mVoiceContent);
2201 df.set(displayFrames.mVoiceContent);
2202 } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2203 cf.set(displayFrames.mDock);
2204 of.set(displayFrames.mDock);
2205 df.set(displayFrames.mDock);
2206 } else {
2207 cf.set(displayFrames.mContent);
2208 of.set(displayFrames.mContent);
2209 df.set(displayFrames.mContent);
2210 }
2211 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2212 vf.set(displayFrames.mCurrent);
2213 } else {
2214 vf.set(cf);
2215 }
2216 }
2217 }
2218 }
2219
2220 final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2221 final boolean attachedInParent = attached != null && !layoutInScreen;
2222 final boolean requestedHideNavigation =
2223 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
2224
2225 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2226 // cropped / shifted to the displayFrame in WindowState.
2227 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2228 && type != TYPE_BASE_APPLICATION;
2229
2230 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2231 // the cutout safe zone.
Arthur Hung20479922019-02-27 17:13:22 +08002232 if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002233 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2234 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2235 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2236 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2237 // At the top we have the status bar, so apps that are
2238 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2239 // already expect that there's an inset there and we don't need to exclude
2240 // the window from that area.
2241 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2242 }
2243 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2244 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2245 // Same for the navigation bar.
2246 switch (mNavigationBarPosition) {
2247 case NAV_BAR_BOTTOM:
2248 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2249 break;
2250 case NAV_BAR_RIGHT:
2251 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2252 break;
2253 case NAV_BAR_LEFT:
2254 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2255 break;
2256 }
2257 }
2258 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2259 // The IME can always extend under the bottom cutout if the navbar is there.
2260 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2261 }
2262 // Windows that are attached to a parent and laid out in said parent already avoid
2263 // the cutout according to that parent and don't need to be further constrained.
2264 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2265 // They will later be cropped or shifted using the displayFrame in WindowState,
2266 // which prevents overlap with the DisplayCutout.
2267 if (!attachedInParent && !floatingInScreenWindow) {
2268 sTmpRect.set(pf);
2269 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2270 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2271 }
2272 // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2273 // cutout.
2274 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2275 }
2276
2277 // Content should never appear in the cutout.
2278 cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2279
2280 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2281 // Also, we don't allow windows in multi-window mode to extend out of the screen.
2282 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
Evan Rosky4fb1e912019-03-06 13:54:43 -08002283 && !win.inMultiWindowMode()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002284 df.left = df.top = -10000;
2285 df.right = df.bottom = 10000;
2286 if (type != TYPE_WALLPAPER) {
2287 of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
2288 of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
2289 }
2290 }
2291
2292 // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
2293 // need to provide information to the clients that want to pretend that you can draw there.
2294 // We only want to apply outsets to certain types of windows. For example, we never want to
2295 // apply the outsets to floating dialogs, because they wouldn't make sense there.
2296 final boolean useOutsets = shouldUseOutsets(attrs, fl);
2297 if (isDefaultDisplay && useOutsets) {
2298 final Rect osf = windowFrames.mOutsetFrame;
2299 osf.set(cf.left, cf.top, cf.right, cf.bottom);
2300 windowFrames.setHasOutsets(true);
Jorim Jaggi4981f152019-03-26 18:58:45 +01002301 int outset = mWindowOutsetBottom;
Tiger Huang7c610aa2018-10-27 00:01:01 +08002302 if (outset > 0) {
2303 int rotation = displayFrames.mRotation;
2304 if (rotation == Surface.ROTATION_0) {
2305 osf.bottom += outset;
2306 } else if (rotation == Surface.ROTATION_90) {
2307 osf.right += outset;
2308 } else if (rotation == Surface.ROTATION_180) {
2309 osf.top -= outset;
2310 } else if (rotation == Surface.ROTATION_270) {
2311 osf.left -= outset;
2312 }
2313 if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
2314 + " with rotation " + rotation + ", result: " + osf);
2315 }
2316 }
2317
2318 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2319 + ": sim=#" + Integer.toHexString(sim)
2320 + " attach=" + attached + " type=" + type
2321 + String.format(" flags=0x%08x", fl)
2322 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
2323 + " of=" + of.toShortString()
2324 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2325 + " dcf=" + dcf.toShortString()
2326 + " sf=" + sf.toShortString()
2327 + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
2328
2329 if (!sTmpLastParentFrame.equals(pf)) {
2330 windowFrames.setContentChanged(true);
2331 }
2332
2333 win.computeFrameLw();
2334 // Dock windows carve out the bottom of the screen, so normal windows
2335 // can't appear underneath them.
2336 if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2337 && !win.getGivenInsetsPendingLw()) {
2338 offsetInputMethodWindowLw(win, displayFrames);
2339 }
2340 if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2341 && !win.getGivenInsetsPendingLw()) {
2342 offsetVoiceInputWindowLw(win, displayFrames);
2343 }
2344 }
2345
2346 private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
2347 // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
2348 df.set(displayFrames.mOverscan);
2349 pf.set(displayFrames.mOverscan);
2350 cf.set(displayFrames.mUnrestricted);
2351 of.set(displayFrames.mUnrestricted);
2352 }
2353
2354 private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
2355 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2356 top += win.getGivenContentInsetsLw().top;
2357 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
2358 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2359 top = win.getVisibleFrameLw().top;
2360 top += win.getGivenVisibleInsetsLw().top;
2361 displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2362 if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2363 + displayFrames.mDock.bottom + " mContentBottom="
2364 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2365 }
2366
2367 private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2368 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2369 top += win.getGivenContentInsetsLw().top;
2370 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2371 }
2372
2373 /**
2374 * Called following layout of all windows before each window has policy applied.
2375 */
2376 public void beginPostLayoutPolicyLw() {
2377 mTopFullscreenOpaqueWindowState = null;
2378 mTopFullscreenOpaqueOrDimmingWindowState = null;
2379 mTopDockedOpaqueWindowState = null;
2380 mTopDockedOpaqueOrDimmingWindowState = null;
2381 mForceStatusBar = false;
2382 mForceStatusBarFromKeyguard = false;
2383 mForceStatusBarTransparent = false;
2384 mForcingShowNavBar = false;
2385 mForcingShowNavBarLayer = -1;
2386
2387 mAllowLockscreenWhenOn = false;
2388 mShowingDream = false;
2389 mWindowSleepTokenNeeded = false;
2390 }
2391
2392 /**
2393 * Called following layout of all window to apply policy to each window.
2394 *
2395 * @param win The window being positioned.
2396 * @param attrs The LayoutParams of the window.
2397 * @param attached For sub-windows, the window it is attached to. Otherwise null.
2398 */
2399 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2400 WindowState attached, WindowState imeTarget) {
2401 final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2402 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2403 mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2404 final int fl = PolicyControl.getWindowFlags(win, attrs);
2405 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2406 && attrs.type == TYPE_INPUT_METHOD) {
2407 mForcingShowNavBar = true;
2408 mForcingShowNavBarLayer = win.getSurfaceLayer();
2409 }
2410 if (attrs.type == TYPE_STATUS_BAR) {
2411 if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
2412 mForceStatusBarFromKeyguard = true;
2413 }
2414 if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
2415 mForceStatusBarTransparent = true;
2416 }
2417 }
2418
2419 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2420 && attrs.type < FIRST_SYSTEM_WINDOW;
2421 final int windowingMode = win.getWindowingMode();
2422 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2423 windowingMode == WINDOWING_MODE_FULLSCREEN
2424 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2425 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2426 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2427 mForceStatusBar = true;
2428 }
2429 if (attrs.type == TYPE_DREAM) {
2430 // If the lockscreen was showing when the dream started then wait
2431 // for the dream to draw before hiding the lockscreen.
2432 if (!mDreamingLockscreen
2433 || (win.isVisibleLw() && win.hasDrawnLw())) {
2434 mShowingDream = true;
2435 appWindow = true;
2436 }
2437 }
2438
2439 // For app windows that are not attached, we decide if all windows in the app they
2440 // represent should be hidden or if we should hide the lockscreen. For attached app
2441 // windows we defer the decision to the window it is attached to.
2442 if (appWindow && attached == null) {
2443 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2444 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2445 mTopFullscreenOpaqueWindowState = win;
2446 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2447 mTopFullscreenOpaqueOrDimmingWindowState = win;
2448 }
2449 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2450 mAllowLockscreenWhenOn = true;
2451 }
2452 }
2453 }
2454 }
2455
2456 // Voice interaction overrides both top fullscreen and top docked.
Jorim Jaggi50150152019-03-27 23:08:58 +01002457 if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002458 if (mTopFullscreenOpaqueWindowState == null) {
2459 mTopFullscreenOpaqueWindowState = win;
2460 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2461 mTopFullscreenOpaqueOrDimmingWindowState = win;
2462 }
2463 }
2464 if (mTopDockedOpaqueWindowState == null) {
2465 mTopDockedOpaqueWindowState = win;
2466 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2467 mTopDockedOpaqueOrDimmingWindowState = win;
2468 }
2469 }
2470 }
2471
2472 // Keep track of the window if it's dimming but not necessarily fullscreen.
2473 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2474 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2475 mTopFullscreenOpaqueOrDimmingWindowState = win;
2476 }
2477
2478 // We need to keep track of the top "fullscreen" opaque window for the docked stack
2479 // separately, because both the "real fullscreen" opaque window and the one for the docked
2480 // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2481 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2482 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2483 mTopDockedOpaqueWindowState = win;
2484 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2485 mTopDockedOpaqueOrDimmingWindowState = win;
2486 }
2487 }
2488
2489 // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2490 // docked stack.
2491 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2492 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2493 mTopDockedOpaqueOrDimmingWindowState = win;
2494 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002495 }
2496
2497 /**
2498 * Called following layout of all windows and after policy has been applied
2499 * to each window. If in this function you do
2500 * something that may have modified the animation state of another window,
2501 * be sure to return non-zero in order to perform another pass through layout.
2502 *
2503 * @return Return any bit set of
2504 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2505 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2506 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2507 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2508 */
2509 public int finishPostLayoutPolicyLw() {
2510 int changes = 0;
2511 boolean topIsFullscreen = false;
2512
2513 // If we are not currently showing a dream then remember the current
2514 // lockscreen state. We will use this to determine whether the dream
2515 // started while the lockscreen was showing and remember this state
2516 // while the dream is showing.
2517 if (!mShowingDream) {
2518 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2519 if (mDreamingSleepTokenNeeded) {
2520 mDreamingSleepTokenNeeded = false;
2521 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2522 }
2523 } else {
2524 if (!mDreamingSleepTokenNeeded) {
2525 mDreamingSleepTokenNeeded = true;
2526 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2527 }
2528 }
2529
2530 if (mStatusBar != null) {
2531 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
2532 + " forcefkg=" + mForceStatusBarFromKeyguard
2533 + " top=" + mTopFullscreenOpaqueWindowState);
2534 boolean shouldBeTransparent = mForceStatusBarTransparent
2535 && !mForceStatusBar
2536 && !mForceStatusBarFromKeyguard;
2537 if (!shouldBeTransparent) {
2538 mStatusBarController.setShowTransparent(false /* transparent */);
2539 } else if (!mStatusBar.isVisibleLw()) {
2540 mStatusBarController.setShowTransparent(true /* transparent */);
2541 }
2542
2543 boolean statusBarForcesShowingNavigation =
2544 (mStatusBar.getAttrs().privateFlags
2545 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
2546 boolean topAppHidesStatusBar = topAppHidesStatusBar();
2547 if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
2548 || statusBarForcesShowingNavigation) {
2549 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2550 if (mStatusBarController.setBarShowingLw(true)) {
2551 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2552 }
2553 // Maintain fullscreen layout until incoming animation is complete.
2554 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
2555 // Transient status bar is not allowed if status bar is on lockscreen or status bar
2556 // is expecting the navigation keys from the user.
2557 if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
2558 && mStatusBarController.isTransientShowing()) {
2559 mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2560 mLastSystemUiFlags, mLastSystemUiFlags);
2561 }
2562 } else if (mTopFullscreenOpaqueWindowState != null) {
2563 topIsFullscreen = topAppHidesStatusBar;
2564 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2565 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2566 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
2567 // case though.
2568 if (mStatusBarController.isTransientShowing()) {
2569 if (mStatusBarController.setBarShowingLw(true)) {
2570 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2571 }
2572 } else if (topIsFullscreen
2573 && !mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM)
2574 && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2575 if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2576 if (mStatusBarController.setBarShowingLw(false)) {
2577 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2578 } else {
2579 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2580 }
2581 } else {
2582 if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2583 if (mStatusBarController.setBarShowingLw(true)) {
2584 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2585 }
2586 topAppHidesStatusBar = false;
2587 }
2588 }
2589 mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2590 }
2591
2592 if (mTopIsFullscreen != topIsFullscreen) {
2593 if (!topIsFullscreen) {
2594 // Force another layout when status bar becomes fully shown.
2595 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2596 }
2597 mTopIsFullscreen = topIsFullscreen;
2598 }
2599
2600 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2601 // If the navigation bar has been hidden or shown, we need to do another
2602 // layout pass to update that window.
2603 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2604 }
2605
2606 if (mShowingDream != mLastShowingDream) {
2607 mLastShowingDream = mShowingDream;
2608 mService.notifyShowingDreamChanged();
2609 }
2610
2611 updateWindowSleepToken();
2612
2613 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2614 return changes;
2615 }
2616
2617 private void updateWindowSleepToken() {
2618 if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2619 mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2620 mHandler.post(mAcquireSleepTokenRunnable);
2621 } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2622 mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2623 mHandler.post(mReleaseSleepTokenRunnable);
2624 }
2625 mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2626 }
2627
2628 /**
2629 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2630 * window.
2631 */
2632 private boolean topAppHidesStatusBar() {
2633 if (mTopFullscreenOpaqueWindowState == null) {
2634 return false;
2635 }
2636 final int fl = PolicyControl.getWindowFlags(null,
2637 mTopFullscreenOpaqueWindowState.getAttrs());
2638 if (localLOGV) {
2639 Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2640 Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2641 + " lp.flags=0x" + Integer.toHexString(fl));
2642 }
2643 return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2644 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2645 }
2646
2647 /**
Winson Chungda20fec2019-04-10 12:19:59 -07002648 * Called when the user is switched.
2649 */
2650 public void switchUser() {
2651 updateCurrentUserResources();
2652 }
2653
2654 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002655 * Called when the resource overlays change.
2656 */
2657 public void onOverlayChangedLw() {
Winson Chungda20fec2019-04-10 12:19:59 -07002658 updateCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002659 onConfigurationChanged();
Jeff Changb0a061e2019-03-11 11:39:54 +08002660 mSystemGestures.onConfigurationChanged();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002661 }
2662
2663 /**
2664 * Called when the configuration has changed, and it's safe to load new values from resources.
2665 */
2666 public void onConfigurationChanged() {
2667 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2668
Winson Chungda20fec2019-04-10 12:19:59 -07002669 final Resources res = getCurrentUserResources();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002670 final int portraitRotation = displayRotation.getPortraitRotation();
2671 final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2672 final int landscapeRotation = displayRotation.getLandscapeRotation();
2673 final int seascapeRotation = displayRotation.getSeascapeRotation();
Matthew Nga7f24bc2019-04-09 17:06:41 -07002674 final int uiMode = mService.mPolicy.getUiMode();
Tiger Huang7c610aa2018-10-27 00:01:01 +08002675
Louis Changfc64c832018-12-04 11:38:26 +08002676 if (hasStatusBar()) {
2677 mStatusBarHeightForRotation[portraitRotation] =
2678 mStatusBarHeightForRotation[upsideDownRotation] =
2679 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2680 mStatusBarHeightForRotation[landscapeRotation] =
2681 mStatusBarHeightForRotation[seascapeRotation] =
2682 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2683 } else {
2684 mStatusBarHeightForRotation[portraitRotation] =
2685 mStatusBarHeightForRotation[upsideDownRotation] =
2686 mStatusBarHeightForRotation[landscapeRotation] =
2687 mStatusBarHeightForRotation[seascapeRotation] = 0;
2688 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002689
2690 // Height of the navigation bar when presented horizontally at bottom
2691 mNavigationBarHeightForRotationDefault[portraitRotation] =
2692 mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2693 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2694 mNavigationBarHeightForRotationDefault[landscapeRotation] =
2695 mNavigationBarHeightForRotationDefault[seascapeRotation] =
2696 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2697
Matthew Nga7f24bc2019-04-09 17:06:41 -07002698 // Height of the navigation bar frame when presented horizontally at bottom
2699 mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2700 mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2701 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2702 mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2703 mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2704 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2705
Tiger Huang7c610aa2018-10-27 00:01:01 +08002706 // Width of the navigation bar when presented vertically along one side
2707 mNavigationBarWidthForRotationDefault[portraitRotation] =
2708 mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2709 mNavigationBarWidthForRotationDefault[landscapeRotation] =
2710 mNavigationBarWidthForRotationDefault[seascapeRotation] =
2711 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2712
2713 if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2714 // Height of the navigation bar when presented horizontally at bottom
2715 mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2716 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2717 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2718 mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2719 mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2720 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2721
2722 // Width of the navigation bar when presented vertically along one side
2723 mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2724 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2725 mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2726 mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2727 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2728 }
2729
Winson Chung4723b4e2019-03-25 16:49:36 -07002730 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002731 mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
2732 mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
Winson Chung36941632019-04-19 15:21:38 -07002733 mNavigationBarAlwaysShowOnSideGesture =
2734 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
Winson Chung4723b4e2019-03-25 16:49:36 -07002735
Matthew Nga7f24bc2019-04-09 17:06:41 -07002736 // This should calculate how much above the frame we accept gestures.
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002737 mBottomGestureAdditionalInset =
Matthew Nga7f24bc2019-04-09 17:06:41 -07002738 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
Sunny Goyalb5e5bcb2019-05-22 14:28:44 -07002739 - getNavigationBarFrameHeight(portraitRotation, uiMode);
Adrian Roos11dfd272019-03-25 19:21:26 +01002740
Winson Chung4723b4e2019-03-25 16:49:36 -07002741 updateConfigurationAndScreenSizeDependentBehaviors();
Jorim Jaggi4981f152019-03-26 18:58:45 +01002742 mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
Winson Chung4723b4e2019-03-25 16:49:36 -07002743 }
2744
2745 void updateConfigurationAndScreenSizeDependentBehaviors() {
Winson Chungda20fec2019-04-10 12:19:59 -07002746 final Resources res = getCurrentUserResources();
Winson Chung4723b4e2019-03-25 16:49:36 -07002747 mNavigationBarCanMove =
2748 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2749 && res.getBoolean(R.bool.config_navBarCanMove);
Adrian Roosd3b40862019-04-16 15:39:23 +02002750 mAllowSeamlessRotationDespiteNavBarMoving =
2751 res.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002752 }
2753
Winson Chungda20fec2019-04-10 12:19:59 -07002754 /**
2755 * Updates the current user's resources to pick up any changes for the current user (including
2756 * overlay paths)
2757 */
2758 private void updateCurrentUserResources() {
2759 final int userId = mService.mAmInternal.getCurrentUserId();
2760 final Context uiContext = getSystemUiContext();
Winson Chung203e1522019-05-02 15:42:22 -07002761
2762 if (userId == UserHandle.USER_SYSTEM) {
2763 // Skip the (expensive) recreation of resources for the system user below and just
2764 // use the resources from the system ui context
2765 mCurrentUserResources = uiContext.getResources();
2766 return;
2767 }
2768
2769 // For non-system users, ensure that the resources are loaded from the current
2770 // user's package info (see ContextImpl.createDisplayContext)
Winson Chungda20fec2019-04-10 12:19:59 -07002771 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2772 uiContext.getPackageName(), null, 0, userId);
Winson Chungda20fec2019-04-10 12:19:59 -07002773 mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2774 pi.getResDir(),
2775 null /* splitResDirs */,
2776 pi.getOverlayDirs(),
2777 pi.getApplicationInfo().sharedLibraryFiles,
2778 mDisplayContent.getDisplayId(),
2779 null /* overrideConfig */,
2780 uiContext.getResources().getCompatibilityInfo(),
2781 null /* classLoader */);
2782 }
2783
Tiger Huang7c610aa2018-10-27 00:01:01 +08002784 @VisibleForTesting
Winson Chungda20fec2019-04-10 12:19:59 -07002785 Resources getCurrentUserResources() {
2786 if (mCurrentUserResources == null) {
2787 updateCurrentUserResources();
2788 }
2789 return mCurrentUserResources;
2790 }
2791
2792 @VisibleForTesting
2793 Context getContext() {
2794 return mContext;
2795 }
2796
2797 private Context getSystemUiContext() {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002798 final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
2799 return mDisplayContent.isDefaultDisplay
2800 ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay());
2801 }
2802
2803 private int getNavigationBarWidth(int rotation, int uiMode) {
2804 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2805 return mNavigationBarWidthForRotationInCarMode[rotation];
2806 } else {
2807 return mNavigationBarWidthForRotationDefault[rotation];
2808 }
2809 }
2810
Charles Chen3dedec32019-01-24 22:19:37 +08002811 void notifyDisplayReady() {
wilsonshih643bf132019-02-27 12:49:19 +08002812 mHandler.post(() -> {
2813 final int displayId = getDisplayId();
2814 getStatusBarManagerInternal().onDisplayReady(displayId);
2815 LocalServices.getService(WallpaperManagerInternal.class).onDisplayReady(displayId);
2816 });
Charles Chen3dedec32019-01-24 22:19:37 +08002817 }
2818
Tiger Huang7c610aa2018-10-27 00:01:01 +08002819 /**
2820 * Return the display width available after excluding any screen
2821 * decorations that could never be removed in Honeycomb. That is, system bar or
2822 * button bar.
2823 */
2824 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2825 DisplayCutout displayCutout) {
2826 int width = fullWidth;
2827 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002828 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2829 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002830 width -= getNavigationBarWidth(rotation, uiMode);
2831 }
2832 }
2833 if (displayCutout != null) {
2834 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2835 }
2836 return width;
2837 }
2838
2839 private int getNavigationBarHeight(int rotation, int uiMode) {
2840 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2841 return mNavigationBarHeightForRotationInCarMode[rotation];
2842 } else {
2843 return mNavigationBarHeightForRotationDefault[rotation];
2844 }
2845 }
2846
2847 /**
Matthew Nga7f24bc2019-04-09 17:06:41 -07002848 * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2849 * is used for spacing to show additional buttons on the navigation bar (such as the ime
2850 * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2851 * height that we send to the app as content insets that can be smaller.
2852 * <p>
2853 * In car mode it will return the same height as {@link #getNavigationBarHeight}
2854 *
2855 * @param rotation specifies rotation to return dimension from
2856 * @param uiMode to determine if in car mode
2857 * @return navigation bar frame height
2858 */
2859 private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2860 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2861 return mNavigationBarHeightForRotationInCarMode[rotation];
2862 } else {
2863 return mNavigationBarFrameHeightForRotationDefault[rotation];
2864 }
2865 }
2866
2867 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002868 * Return the display height available after excluding any screen
2869 * decorations that could never be removed in Honeycomb. That is, system bar or
2870 * button bar.
2871 */
2872 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2873 DisplayCutout displayCutout) {
2874 int height = fullHeight;
2875 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002876 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2877 if (navBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002878 height -= getNavigationBarHeight(rotation, uiMode);
2879 }
2880 }
2881 if (displayCutout != null) {
2882 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2883 }
2884 return height;
2885 }
2886
2887 /**
2888 * Return the available screen width that we should report for the
2889 * configuration. This must be no larger than
2890 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2891 * than that to account for more transient decoration like a status bar.
2892 */
2893 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2894 DisplayCutout displayCutout) {
2895 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2896 }
2897
2898 /**
2899 * Return the available screen height that we should report for the
2900 * configuration. This must be no larger than
2901 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2902 * than that to account for more transient decoration like a status bar.
2903 */
2904 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2905 DisplayCutout displayCutout) {
2906 // There is a separate status bar at the top of the display. We don't count that as part
2907 // of the fixed decor, since it can hide; however, for purposes of configurations,
2908 // we do want to exclude it since applications can't generally use that part
2909 // of the screen.
2910 int statusBarHeight = mStatusBarHeightForRotation[rotation];
2911 if (displayCutout != null) {
2912 // If there is a cutout, it may already have accounted for some part of the status
2913 // bar height.
2914 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2915 }
2916 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2917 - statusBarHeight;
2918 }
2919
Tiger Huang43b8fc22019-04-26 11:49:29 +08002920 /**
2921 * Return corner radius in pixels that should be used on windows in order to cover the display.
2922 * The radius is only valid for built-in displays since the one who configures window corner
2923 * radius cannot know the corner radius of non-built-in display.
2924 */
2925 float getWindowCornerRadius() {
2926 return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN
2927 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2928 }
2929
Tiger Huang7c610aa2018-10-27 00:01:01 +08002930 boolean isShowingDreamLw() {
2931 return mShowingDream;
2932 }
2933
2934 /**
Riddle Hsu61987bc2019-04-03 13:08:47 +08002935 * Calculates the stable insets if we already have the non-decor insets.
2936 *
2937 * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2938 * @param rotation The current display rotation.
2939 */
2940 void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2941 inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2942 }
2943
2944 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +08002945 * Calculates the stable insets without running a layout.
2946 *
2947 * @param displayRotation the current display rotation
2948 * @param displayWidth the current display width
2949 * @param displayHeight the current display height
2950 * @param displayCutout the current display cutout
2951 * @param outInsets the insets to return
2952 */
2953 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2954 DisplayCutout displayCutout, Rect outInsets) {
2955 outInsets.setEmpty();
2956
2957 // Navigation bar and status bar.
2958 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
Riddle Hsu61987bc2019-04-03 13:08:47 +08002959 convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
Tiger Huang7c610aa2018-10-27 00:01:01 +08002960 }
2961
2962 /**
2963 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2964 * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2965 *
2966 * @param displayRotation the current display rotation
2967 * @param displayWidth the current display width
2968 * @param displayHeight the current display height
2969 * @param displayCutout the current display cutout
2970 * @param outInsets the insets to return
2971 */
2972 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2973 DisplayCutout displayCutout, Rect outInsets) {
2974 outInsets.setEmpty();
2975
2976 // Only navigation bar
2977 if (hasNavigationBar()) {
2978 final int uiMode = mService.mPolicy.getUiMode();
2979 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2980 if (position == NAV_BAR_BOTTOM) {
2981 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2982 } else if (position == NAV_BAR_RIGHT) {
2983 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2984 } else if (position == NAV_BAR_LEFT) {
2985 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2986 }
2987 }
2988
2989 if (displayCutout != null) {
2990 outInsets.left += displayCutout.getSafeInsetLeft();
2991 outInsets.top += displayCutout.getSafeInsetTop();
2992 outInsets.right += displayCutout.getSafeInsetRight();
2993 outInsets.bottom += displayCutout.getSafeInsetBottom();
2994 }
2995 }
2996
Issei Suzukia5dbf522019-02-01 17:58:15 +01002997 /**
2998 * @see IWindowManager#setForwardedInsets
2999 */
3000 public void setForwardedInsets(@NonNull Insets forwardedInsets) {
3001 mForwardedInsets = forwardedInsets;
3002 }
3003
3004 @NonNull
3005 public Insets getForwardedInsets() {
3006 return mForwardedInsets;
3007 }
3008
Tiger Huang7c610aa2018-10-27 00:01:01 +08003009 @NavigationBarPosition
3010 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
3011 if (navigationBarCanMove() && displayWidth > displayHeight) {
3012 if (displayRotation == Surface.ROTATION_270) {
3013 return NAV_BAR_LEFT;
3014 } else if (displayRotation == Surface.ROTATION_90) {
3015 return NAV_BAR_RIGHT;
3016 }
3017 }
3018 return NAV_BAR_BOTTOM;
3019 }
3020
3021 /**
3022 * @return The side of the screen where navigation bar is positioned.
3023 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
3024 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
3025 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
3026 */
3027 @NavigationBarPosition
3028 public int getNavBarPosition() {
3029 return mNavigationBarPosition;
3030 }
3031
3032 /**
3033 * A new window has been focused.
3034 */
3035 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
3036 mFocusedWindow = newFocus;
3037 mLastFocusedWindow = lastFocus;
Issei Suzuki9f840c72018-12-07 15:09:30 -08003038 if (mDisplayContent.isDefaultDisplay) {
3039 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
3040 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08003041 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
3042 // If the navigation bar has been hidden or shown, we need to do another
3043 // layout pass to update that window.
3044 return FINISH_LAYOUT_REDO_LAYOUT;
3045 }
3046 return 0;
3047 }
3048
3049 /**
3050 * Return true if it is okay to perform animations for an app transition
3051 * that is about to occur. You may return false for this if, for example,
3052 * the dream window is currently displayed so the switch should happen
3053 * immediately.
3054 */
3055 public boolean allowAppAnimationsLw() {
3056 return !mShowingDream;
3057 }
3058
3059 private void updateDreamingSleepToken(boolean acquire) {
3060 if (acquire) {
3061 final int displayId = getDisplayId();
3062 if (mDreamingSleepToken == null) {
3063 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
3064 "DreamOnDisplay" + displayId, displayId);
3065 }
3066 } else {
3067 if (mDreamingSleepToken != null) {
3068 mDreamingSleepToken.release();
3069 mDreamingSleepToken = null;
3070 }
3071 }
3072 }
3073
3074 private void requestTransientBars(WindowState swipeTarget) {
3075 synchronized (mLock) {
3076 if (!mService.mPolicy.isUserSetupComplete()) {
3077 // Swipe-up for navigation bar is disabled during setup
3078 return;
3079 }
3080 boolean sb = mStatusBarController.checkShowTransientBarLw();
3081 boolean nb = mNavigationBarController.checkShowTransientBarLw()
3082 && !isNavBarEmpty(mLastSystemUiFlags);
3083 if (sb || nb) {
3084 // Don't show status bar when swiping on already visible navigation bar
3085 if (!nb && swipeTarget == mNavigationBar) {
3086 if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
3087 return;
3088 }
3089 if (sb) mStatusBarController.showTransient();
3090 if (nb) mNavigationBarController.showTransient();
3091 mImmersiveModeConfirmation.confirmCurrentPrompt();
3092 updateSystemUiVisibilityLw();
3093 }
3094 }
3095 }
3096
3097 private void disposeInputConsumer(InputConsumer inputConsumer) {
3098 if (inputConsumer != null) {
3099 inputConsumer.dismiss();
3100 }
3101 }
3102
3103 private boolean isStatusBarKeyguard() {
3104 return mStatusBar != null
3105 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
3106 }
3107
3108 private boolean isKeyguardOccluded() {
3109 // TODO (b/113840485): Handle per display keyguard.
3110 return mService.mPolicy.isKeyguardOccluded();
3111 }
3112
3113 void resetSystemUiVisibilityLw() {
3114 mLastSystemUiFlags = 0;
3115 updateSystemUiVisibilityLw();
3116 }
3117
3118 private int updateSystemUiVisibilityLw() {
3119 // If there is no window focused, there will be nobody to handle the events
3120 // anyway, so just hang on in whatever state we're in until things settle down.
3121 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
3122 : mTopFullscreenOpaqueWindowState;
3123 if (winCandidate == null) {
3124 return 0;
3125 }
3126
3127 // The immersive mode confirmation should never affect the system bar visibility, otherwise
3128 // it will unhide the navigation bar and hide itself.
3129 if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
3130
3131 // The immersive mode confirmation took the focus from mLastFocusedWindow which was
3132 // controlling the system ui visibility. So if mLastFocusedWindow can still receive
3133 // keys, we let it keep controlling the visibility.
3134 final boolean lastFocusCanReceiveKeys =
3135 (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
3136 winCandidate = isStatusBarKeyguard() ? mStatusBar
3137 : lastFocusCanReceiveKeys ? mLastFocusedWindow
3138 : mTopFullscreenOpaqueWindowState;
3139 if (winCandidate == null) {
3140 return 0;
3141 }
3142 }
3143 final WindowState win = winCandidate;
3144 if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) {
3145 // We are updating at a point where the keyguard has gotten
3146 // focus, but we were last in a state where the top window is
3147 // hiding it. This is probably because the keyguard as been
3148 // shown while the top window was displayed, so we want to ignore
3149 // it here because this is just a very transient change and it
3150 // will quickly lose focus once it correctly gets hidden.
3151 return 0;
3152 }
3153
Jorim Jaggib6030952018-10-23 18:31:52 +02003154 mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(
3155 mTopFullscreenOpaqueWindowState);
3156
Tiger Huang7c610aa2018-10-27 00:01:01 +08003157 int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
3158 & ~mResettingSystemUiFlags
3159 & ~mForceClearedSystemUiFlags;
3160 if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
3161 tmpVisibility
3162 &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
3163 }
3164
3165 final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
3166 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
3167 final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
3168 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
3169 mService.getStackBounds(
3170 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
3171 mService.getStackBounds(
3172 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003173 final Pair<Integer, Boolean> result =
3174 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
3175 final int visibility = result.first;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003176 final int diff = visibility ^ mLastSystemUiFlags;
3177 final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
3178 final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
3179 final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
3180 if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
3181 && mFocusedApp == win.getAppToken()
3182 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
3183 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
3184 return 0;
3185 }
3186 mLastSystemUiFlags = visibility;
3187 mLastFullscreenStackSysUiFlags = fullscreenVisibility;
3188 mLastDockedStackSysUiFlags = dockedVisibility;
3189 mLastFocusNeedsMenu = needsMenu;
3190 mFocusedApp = win.getAppToken();
Riddle Hsu4d6a63f2019-03-29 19:14:43 +08003191 mLastNonDockedStackBounds.set(mNonDockedStackBounds);
3192 mLastDockedStackBounds.set(mDockedStackBounds);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003193 final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
3194 final Rect dockedStackBounds = new Rect(mDockedStackBounds);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003195 final boolean isNavbarColorManagedByIme = result.second;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003196 mHandler.post(() -> {
3197 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
3198 if (statusBar != null) {
3199 final int displayId = getDisplayId();
3200 statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility,
3201 dockedVisibility, 0xffffffff, fullscreenStackBounds,
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003202 dockedStackBounds, isNavbarColorManagedByIme, win.toString());
Tiger Huang7c610aa2018-10-27 00:01:01 +08003203 statusBar.topAppWindowChanged(displayId, needsMenu);
3204 }
3205 });
3206 return diff;
3207 }
3208
3209 private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
3210 final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded();
3211 final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
3212 if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
3213 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
3214 // its light flag.
3215 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3216 vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
3217 & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3218 } else if (statusColorWin != null && statusColorWin.isDimming()) {
3219 // Otherwise if it's dimming, clear the light flag.
3220 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3221 }
3222 return vis;
3223 }
3224
3225 @VisibleForTesting
3226 @Nullable
3227 static WindowState chooseNavigationColorWindowLw(WindowState opaque,
3228 WindowState opaqueOrDimming, WindowState imeWindow,
3229 @NavigationBarPosition int navBarPosition) {
3230 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
3231 // window can be navigation color window.
3232 final boolean imeWindowCanNavColorWindow = imeWindow != null
3233 && imeWindow.isVisibleLw()
3234 && navBarPosition == NAV_BAR_BOTTOM
3235 && (PolicyControl.getWindowFlags(imeWindow, null)
3236 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3237
3238 if (opaque != null && opaqueOrDimming == opaque) {
3239 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
3240 // unless IME window is also eligible, since currently the IME window is always show
3241 // above the opaque fullscreen app window, regardless of the IME target window.
3242 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
3243 return imeWindowCanNavColorWindow ? imeWindow : opaque;
3244 }
3245
3246 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
3247 // No dimming window is involved. Determine the result only with the IME window.
3248 return imeWindowCanNavColorWindow ? imeWindow : null;
3249 }
3250
3251 if (!imeWindowCanNavColorWindow) {
3252 // No IME window is involved. Determine the result only with opaqueOrDimming.
3253 return opaqueOrDimming;
3254 }
3255
3256 // The IME window and the dimming window are competing. Check if the dimming window can be
3257 // IME target or not.
3258 if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3259 // The IME window is above the dimming window.
3260 return imeWindow;
3261 } else {
3262 // The dimming window is above the IME window.
3263 return opaqueOrDimming;
3264 }
3265 }
3266
3267 @VisibleForTesting
3268 static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3269 WindowState imeWindow, WindowState navColorWin) {
3270
3271 if (navColorWin != null) {
3272 if (navColorWin == imeWindow || navColorWin == opaque) {
3273 // Respect the light flag.
3274 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3275 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3276 & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3277 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3278 // Clear the light flag for dimming window.
3279 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3280 }
3281 }
3282 return vis;
3283 }
3284
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003285 private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003286 final boolean dockedStackVisible =
3287 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3288 final boolean freeformStackVisible =
3289 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3290 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3291
3292 // We need to force system bars when the docked stack is visible, when the freeform stack
3293 // is visible but also when we are resizing for the transitions when docked stack
3294 // visibility changes.
Brad Stenninge0573692019-03-11 13:52:46 -07003295 mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing
3296 || mForceShowSystemBarsFromExternal;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003297 final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
3298
3299 // apply translucent bar vis flags
3300 WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded()
3301 ? mStatusBar
3302 : mTopFullscreenOpaqueWindowState;
3303 vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3304 vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
Adrian Roosfaba4062019-05-14 15:27:17 +02003305 int dockedVis = mStatusBarController.applyTranslucentFlagLw(
Tiger Huang7c610aa2018-10-27 00:01:01 +08003306 mTopDockedOpaqueWindowState, 0, 0);
Adrian Roosfaba4062019-05-14 15:27:17 +02003307 dockedVis = mNavigationBarController.applyTranslucentFlagLw(
3308 mTopDockedOpaqueWindowState, dockedVis, 0);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003309
3310 final boolean fullscreenDrawsStatusBarBackground =
3311 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3312 final boolean dockedDrawsStatusBarBackground =
3313 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003314 final boolean fullscreenDrawsNavBarBackground =
3315 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
Adrian Roosfaba4062019-05-14 15:27:17 +02003316 final boolean dockedDrawsNavigationBarBackground =
3317 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003318
3319 // prevent status bar interaction from clearing certain flags
3320 int type = win.getAttrs().type;
3321 boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
3322 if (statusBarHasFocus && !isStatusBarKeyguard()) {
3323 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3324 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3325 | View.SYSTEM_UI_FLAG_IMMERSIVE
3326 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3327 | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3328 if (isKeyguardOccluded()) {
3329 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3330 }
3331 vis = (vis & ~flags) | (oldVis & flags);
3332 }
3333
3334 if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3335 vis |= View.STATUS_BAR_TRANSPARENT;
3336 vis &= ~View.STATUS_BAR_TRANSLUCENT;
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003337 } else if (forceOpaqueStatusBar) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003338 vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3339 }
3340
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003341 vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003342 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003343
3344 // update status bar
3345 boolean immersiveSticky =
3346 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3347 final boolean hideStatusBarWM =
3348 mTopFullscreenOpaqueWindowState != null
3349 && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3350 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3351 final boolean hideStatusBarSysui =
3352 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3353 final boolean hideNavBarSysui =
3354 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3355
3356 final boolean transientStatusBarAllowed = mStatusBar != null
3357 && (statusBarHasFocus || (!mForceShowSystemBars
3358 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3359
3360 final boolean transientNavBarAllowed = mNavigationBar != null
3361 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3362
3363 final long now = SystemClock.uptimeMillis();
3364 final boolean pendingPanic = mPendingPanicGestureUptime != 0
3365 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3366 final DisplayPolicy defaultDisplayPolicy =
3367 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
3368 if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
3369 // TODO (b/111955725): Show keyguard presentation on all external displays
3370 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3371 // The user performed the panic gesture recently, we're about to hide the bars,
3372 // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3373 mPendingPanicGestureUptime = 0;
3374 mStatusBarController.showTransient();
3375 if (!isNavBarEmpty(vis)) {
3376 mNavigationBarController.showTransient();
3377 }
3378 }
3379
3380 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3381 && !transientStatusBarAllowed && hideStatusBarSysui;
3382 final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3383 && !transientNavBarAllowed;
3384 if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3385 // clear the clearable flags instead
3386 clearClearableFlagsLw();
3387 vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3388 }
3389
3390 final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3391 immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3392 final boolean navAllowedHidden = immersive || immersiveSticky;
3393
3394 if (hideNavBarSysui && !navAllowedHidden
3395 && mService.mPolicy.getWindowLayerLw(win)
3396 > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3397 // We can't hide the navbar from this window otherwise the input consumer would not get
3398 // the input events.
3399 vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3400 }
3401
3402 vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3403
3404 // update navigation bar
3405 boolean oldImmersiveMode = isImmersiveMode(oldVis);
3406 boolean newImmersiveMode = isImmersiveMode(vis);
3407 if (oldImmersiveMode != newImmersiveMode) {
3408 final String pkg = win.getOwningPackage();
3409 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3410 mService.mPolicy.isUserSetupComplete(),
3411 isNavBarEmpty(win.getSystemUiVisibility()));
3412 }
3413
3414 vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3415
3416 final WindowState navColorWin = chooseNavigationColorWindowLw(
3417 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3418 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3419 vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3420 mTopFullscreenOpaqueOrDimmingWindowState,
3421 mDisplayContent.mInputMethodWindow, navColorWin);
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003422 // Navbar color is controlled by the IME.
3423 final boolean isManagedByIme =
3424 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003425
Tarandeep Singhe439dec2019-04-22 12:28:43 -07003426 return Pair.create(vis, isManagedByIme);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003427 }
3428
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003429 private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
3430 int translucentFlag) {
3431 if (!controller.isTransparentAllowed(win)) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003432 return false;
3433 }
3434 if (win == null) {
3435 return true;
3436 }
3437
3438 final boolean drawsSystemBars =
3439 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3440 final boolean forceDrawsSystemBars =
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003441 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
Tiger Huang7c610aa2018-10-27 00:01:01 +08003442
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003443 return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
3444 }
3445
3446 private boolean drawsStatusBarBackground(int vis, WindowState win) {
3447 return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
3448 }
3449
3450 private boolean drawsNavigationBarBackground(int vis, WindowState win) {
3451 return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003452 }
3453
3454 /**
3455 * @return the current visibility flags with the nav-bar opacity related flags toggled based
3456 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3457 */
3458 private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003459 boolean freeformStackVisible, boolean isDockedDividerResizing,
Adrian Roosfaba4062019-05-14 15:27:17 +02003460 boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
3461 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
3462 if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
3463 visibility = setNavBarTransparentFlag(visibility);
3464 } else if (dockedStackVisible) {
3465 visibility = setNavBarOpaqueFlag(visibility);
3466 }
3467 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003468 if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
3469 visibility = setNavBarOpaqueFlag(visibility);
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003470 } else if (fullscreenDrawsBackground) {
3471 visibility = setNavBarTransparentFlag(visibility);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003472 }
3473 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3474 if (isDockedDividerResizing) {
3475 visibility = setNavBarOpaqueFlag(visibility);
3476 } else if (freeformStackVisible) {
3477 visibility = setNavBarTranslucentFlag(visibility);
3478 } else {
3479 visibility = setNavBarOpaqueFlag(visibility);
3480 }
3481 }
3482
Tiger Huang7c610aa2018-10-27 00:01:01 +08003483 return visibility;
3484 }
3485
3486 private int setNavBarOpaqueFlag(int visibility) {
3487 return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3488 }
3489
3490 private int setNavBarTranslucentFlag(int visibility) {
3491 visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3492 return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3493 }
3494
Jorim Jaggia6aabac2019-03-11 14:23:16 -07003495 private int setNavBarTransparentFlag(int visibility) {
3496 visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3497 return visibility | View.NAVIGATION_BAR_TRANSPARENT;
3498 }
3499
Tiger Huang7c610aa2018-10-27 00:01:01 +08003500 private void clearClearableFlagsLw() {
3501 int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3502 if (newVal != mResettingSystemUiFlags) {
3503 mResettingSystemUiFlags = newVal;
3504 mDisplayContent.reevaluateStatusBarVisibility();
3505 }
3506 }
3507
3508 private boolean isImmersiveMode(int vis) {
3509 final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3510 return mNavigationBar != null
3511 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3512 && (vis & flags) != 0
3513 && canHideNavigationBar();
3514 }
3515
3516 /**
3517 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3518 */
3519 private boolean canHideNavigationBar() {
3520 return hasNavigationBar();
3521 }
3522
3523 private static boolean isNavBarEmpty(int systemUiFlags) {
3524 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3525 | View.STATUS_BAR_DISABLE_BACK
3526 | View.STATUS_BAR_DISABLE_RECENT);
3527
3528 return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3529 }
3530
Tiger Huang7c610aa2018-10-27 00:01:01 +08003531 boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
3532 int newRotation) {
3533 // For the upside down rotation we don't rotate seamlessly as the navigation
3534 // bar moves position.
3535 // Note most apps (using orientation:sensor or user as opposed to fullSensor)
3536 // will not enter the reverse portrait orientation, so actually the
3537 // orientation won't change at all.
3538 if (oldRotation == displayRotation.getUpsideDownRotation()
3539 || newRotation == displayRotation.getUpsideDownRotation()) {
3540 return false;
3541 }
3542 // If the navigation bar can't change sides, then it will
3543 // jump when we change orientations and we don't rotate
Adrian Roosd3b40862019-04-16 15:39:23 +02003544 // seamlessly - unless that is allowed, eg. with gesture
3545 // navigation where the navbar is low-profile enough that this isn't very noticeable.
3546 if (!navigationBarCanMove() && !mAllowSeamlessRotationDespiteNavBarMoving) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003547 return false;
3548 }
3549
3550 final WindowState w = mTopFullscreenOpaqueWindowState;
Riddle Hsuc90c4a52019-02-25 13:35:53 +08003551 if (w == null || w != mFocusedWindow) {
3552 return false;
3553 }
3554 // If the bounds of activity window is different from its parent, then reject to be seamless
3555 // because the window position may change after rotation that will look like a sudden jump.
3556 if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003557 return false;
3558 }
3559
3560 // We only enable seamless rotation if the top window has requested
3561 // it and is in the fullscreen opaque state. Seamless rotation
3562 // requires freezing various Surface states and won't work well
3563 // with animations, so we disable it in the animation case for now.
Riddle Hsuc90c4a52019-02-25 13:35:53 +08003564 if (!w.isAnimatingLw() && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003565 return true;
3566 }
3567 return false;
3568 }
3569
3570 private final Runnable mHiddenNavPanic = new Runnable() {
3571 @Override
3572 public void run() {
3573 synchronized (mLock) {
3574 if (!mService.mPolicy.isUserSetupComplete()) {
3575 // Swipe-up for navigation bar is disabled during setup
3576 return;
3577 }
3578 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3579 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3580 mNavigationBarController.showTransient();
3581 }
3582 }
3583 }
3584 };
3585
3586 void onPowerKeyDown(boolean isScreenOn) {
3587 // Detect user pressing the power button in panic when an application has
3588 // taken over the whole screen.
3589 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3590 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3591 isNavBarEmpty(mLastSystemUiFlags));
3592 if (panic) {
3593 mHandler.post(mHiddenNavPanic);
3594 }
3595 }
3596
3597 void onVrStateChangedLw(boolean enabled) {
3598 mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3599 }
3600
3601 /**
3602 * Called when the state of lock task mode changes. This should be used to disable immersive
3603 * mode confirmation.
3604 *
3605 * @param lockTaskState the new lock task mode state. One of
3606 * {@link ActivityManager#LOCK_TASK_MODE_NONE},
3607 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3608 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3609 */
3610 public void onLockTaskStateChangedLw(int lockTaskState) {
3611 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3612 }
3613
3614 /**
3615 * Request a screenshot be taken.
3616 *
3617 * @param screenshotType The type of screenshot, for example either
3618 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3619 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3620 */
3621 public void takeScreenshot(int screenshotType) {
3622 if (mScreenshotHelper != null) {
3623 mScreenshotHelper.takeScreenshot(screenshotType,
3624 mStatusBar != null && mStatusBar.isVisibleLw(),
James O'Learyfa5bb7a2019-09-05 13:43:29 -04003625 mNavigationBar != null && mNavigationBar.isVisibleLw(),
3626 mHandler, null /* completionConsumer */);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003627 }
3628 }
3629
Ady Abrahamf3e05312019-05-13 18:04:59 -07003630 RefreshRatePolicy getRefreshRatePolicy() {
3631 return mRefreshRatePolicy;
3632 }
3633
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003634 void dump(String prefix, PrintWriter pw) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003635 pw.print(prefix); pw.print("DisplayPolicy");
3636 prefix += " ";
3637 pw.print(prefix);
3638 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3639 pw.print(" mDeskDockEnablesAccelerometer=");
3640 pw.println(mDeskDockEnablesAccelerometer);
3641 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3642 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3643 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3644 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3645 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3646 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3647 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3648 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3649 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3650 || mForceClearedSystemUiFlags != 0) {
3651 pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3652 pw.print(Integer.toHexString(mLastSystemUiFlags));
3653 pw.print(" mResettingSystemUiFlags=0x");
3654 pw.print(Integer.toHexString(mResettingSystemUiFlags));
3655 pw.print(" mForceClearedSystemUiFlags=0x");
3656 pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3657 }
3658 if (mLastFocusNeedsMenu) {
3659 pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu);
3660 }
3661 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3662 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3663 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3664 if (mStatusBar != null) {
3665 pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
3666 pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard());
3667 }
3668 if (mNavigationBar != null) {
3669 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
Winson Chung4723b4e2019-03-25 16:49:36 -07003670 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
3671 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
3672 pw.print(prefix); pw.print("mNavigationBarPosition=");
3673 pw.println(mNavigationBarPosition);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003674 }
3675 if (mFocusedWindow != null) {
3676 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3677 }
3678 if (mFocusedApp != null) {
3679 pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3680 }
3681 if (mTopFullscreenOpaqueWindowState != null) {
3682 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3683 pw.println(mTopFullscreenOpaqueWindowState);
3684 }
3685 if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3686 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3687 pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3688 }
3689 if (mForcingShowNavBar) {
3690 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3691 pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3692 pw.println(mForcingShowNavBarLayer);
3693 }
3694 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
3695 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
3696 pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
Brad Stenninge0573692019-03-11 13:52:46 -07003697 pw.print(" mForceShowSystemBarsFromExternal=");
3698 pw.println(mForceShowSystemBarsFromExternal);
Tiger Huang7c610aa2018-10-27 00:01:01 +08003699 pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
3700 mStatusBarController.dump(pw, prefix);
3701 mNavigationBarController.dump(pw, prefix);
3702
3703 pw.print(prefix); pw.println("Looper state:");
3704 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003705 }
Arthur Hung20479922019-02-27 17:13:22 +08003706
3707 private boolean supportsPointerLocation() {
3708 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
3709 }
3710
3711 void setPointerLocationEnabled(boolean pointerLocationEnabled) {
3712 if (!supportsPointerLocation()) {
3713 return;
3714 }
3715
3716 mHandler.sendEmptyMessage(pointerLocationEnabled
3717 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
3718 }
3719
3720 private void enablePointerLocation() {
3721 if (mPointerLocationView != null) {
3722 return;
3723 }
3724
3725 mPointerLocationView = new PointerLocationView(mContext);
3726 mPointerLocationView.setPrintCoords(false);
3727 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
3728 WindowManager.LayoutParams.MATCH_PARENT,
3729 WindowManager.LayoutParams.MATCH_PARENT);
3730 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3731 lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
3732 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3733 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3734 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3735 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3736 if (ActivityManager.isHighEndGfx()) {
3737 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3738 lp.privateFlags |=
3739 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3740 }
3741 lp.format = PixelFormat.TRANSLUCENT;
3742 lp.setTitle("PointerLocation - display " + getDisplayId());
3743 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3744 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3745 wm.addView(mPointerLocationView, lp);
3746 mDisplayContent.registerPointerEventListener(mPointerLocationView);
3747 }
3748
3749 private void disablePointerLocation() {
3750 if (mPointerLocationView == null) {
3751 return;
3752 }
3753
3754 mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3755 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3756 wm.removeView(mPointerLocationView);
3757 mPointerLocationView = null;
3758 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003759}