blob: e48361fa06671299a25a181b5cc3a502ef2887af [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;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020028import static android.view.InsetsState.TYPE_TOP_BAR;
Tiger Huang7c610aa2018-10-27 00:01:01 +080029import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
Jorim Jaggi648e5882019-01-24 13:24:02 +010030import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080031import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
32import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
33import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
34import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
35import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
36import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
37import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
38import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
39import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
40import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
41import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
42import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
43import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
44import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
45import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
46import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
47import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
48import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
Tiger Huang7c610aa2018-10-27 00:01:01 +080049import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
50import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
51import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
52import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
53import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
54import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
55import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
56import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
57import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
58import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
59import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
60import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
61import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
Vishnu Nair15382f12019-01-23 14:01:35 -080062import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
Tiger Huang7c610aa2018-10-27 00:01:01 +080063import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
64import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
65import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
66import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
67import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
68import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
69import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
70import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
71import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
72import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
73import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
74import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
75import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
76import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
77import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
78import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
79import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
80import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
81import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
82import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
83import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
84import static android.view.WindowManagerGlobal.ADD_OKAY;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080085import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
86import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
Tiger Huang7c610aa2018-10-27 00:01:01 +080087import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
88import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
89import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
90
91import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
92import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
93import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
94import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
95import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
96import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
97import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080098import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
Tiger Huang7c610aa2018-10-27 00:01:01 +080099import static com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
100import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
101import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800102import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
103import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
104import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800105import static com.android.server.wm.WindowManagerService.localLOGV;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800106
Issei Suzukia5dbf522019-02-01 17:58:15 +0100107import android.annotation.NonNull;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800108import android.annotation.Nullable;
109import android.app.ActivityManager;
110import android.app.ActivityThread;
111import android.app.StatusBarManager;
112import android.content.Context;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800113import android.content.Intent;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800114import android.content.res.Resources;
Issei Suzukia5dbf522019-02-01 17:58:15 +0100115import android.graphics.Insets;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800116import android.graphics.Rect;
117import android.hardware.input.InputManager;
118import android.hardware.power.V1_0.PowerHint;
119import android.os.Handler;
120import android.os.Looper;
121import android.os.Message;
122import android.os.SystemClock;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800123import android.os.SystemProperties;
124import android.os.UserHandle;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800125import android.util.ArraySet;
126import android.util.PrintWriterPrinter;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800127import android.util.Slog;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800128import android.view.DisplayCutout;
129import android.view.Gravity;
130import android.view.IApplicationToken;
131import android.view.InputChannel;
132import android.view.InputDevice;
133import android.view.InputEvent;
134import android.view.InputEventReceiver;
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200135import android.view.InsetsState;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800136import android.view.MotionEvent;
137import android.view.PointerIcon;
138import android.view.Surface;
139import android.view.View;
Jorim Jaggi648e5882019-01-24 13:24:02 +0100140import android.view.ViewRootImpl;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800141import android.view.WindowManager;
142import android.view.WindowManager.LayoutParams;
143import android.view.WindowManagerGlobal;
144import android.view.WindowManagerPolicyConstants;
145import android.view.accessibility.AccessibilityManager;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800146
Tiger Huang7c610aa2018-10-27 00:01:01 +0800147import com.android.internal.R;
148import com.android.internal.annotations.GuardedBy;
149import com.android.internal.annotations.VisibleForTesting;
150import com.android.internal.util.ScreenShapeHelper;
151import com.android.internal.util.ScreenshotHelper;
152import com.android.server.LocalServices;
153import com.android.server.UiThread;
154import com.android.server.policy.WindowManagerPolicy;
155import com.android.server.policy.WindowManagerPolicy.InputConsumer;
156import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800157import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
158import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800159import com.android.server.policy.WindowOrientationListener;
160import com.android.server.statusbar.StatusBarManagerInternal;
wilsonshih643bf132019-02-27 12:49:19 +0800161import com.android.server.wallpaper.WallpaperManagerInternal;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800162import com.android.server.wm.utils.InsetUtils;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800163
164import java.io.PrintWriter;
165
166/**
167 * The policy that provides the basic behaviors and states of a display to show UI.
168 */
169public class DisplayPolicy {
170 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800171 private static final boolean DEBUG = false;
172
173 private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
174
175 // The panic gesture may become active only after the keyguard is dismissed and the immersive
176 // app shows again. If that doesn't happen for 30s we drop the gesture.
177 private static final long PANIC_GESTURE_EXPIRATION = 30000;
178
179 // Controls navigation bar opacity depending on which workspace stacks are currently
180 // visible.
181 // Nav bar is always opaque when either the freeform stack or docked stack is visible.
182 private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
183 // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
184 private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
185
186 /**
187 * These are the system UI flags that, when changing, can cause the layout
188 * of the screen to change.
189 */
190 private static final int SYSTEM_UI_CHANGING_LAYOUT =
191 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
192 | View.SYSTEM_UI_FLAG_FULLSCREEN
193 | View.STATUS_BAR_TRANSLUCENT
194 | View.NAVIGATION_BAR_TRANSLUCENT
195 | View.STATUS_BAR_TRANSPARENT
196 | View.NAVIGATION_BAR_TRANSPARENT;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800197
198 private final WindowManagerService mService;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800199 private final Context mContext;
200 private final DisplayContent mDisplayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800201 private final Object mLock;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800202 private final Handler mHandler;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800203
204 private final boolean mCarDockEnablesAccelerometer;
205 private final boolean mDeskDockEnablesAccelerometer;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800206 private final boolean mTranslucentDecorEnabled;
207 private final AccessibilityManager mAccessibilityManager;
208 private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
209 private final ScreenshotHelper mScreenshotHelper;
210
211 private final Object mServiceAcquireLock = new Object();
212 private StatusBarManagerInternal mStatusBarManagerInternal;
213
214 private StatusBarManagerInternal getStatusBarManagerInternal() {
215 synchronized (mServiceAcquireLock) {
216 if (mStatusBarManagerInternal == null) {
217 mStatusBarManagerInternal =
218 LocalServices.getService(StatusBarManagerInternal.class);
219 }
220 return mStatusBarManagerInternal;
221 }
222 }
223
Tiger Huang7c610aa2018-10-27 00:01:01 +0800224 private final SystemGesturesPointerEventListener mSystemGestures;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800225
226 private volatile int mLidState = LID_ABSENT;
227 private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
228 private volatile boolean mHdmiPlugged;
229
Louis Changfc64c832018-12-04 11:38:26 +0800230 private volatile boolean mHasStatusBar;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800231 private volatile boolean mHasNavigationBar;
232 // Can the navigation bar ever move to the side?
233 private volatile boolean mNavigationBarCanMove;
234
235 // Written by vr manager thread, only read in this class.
236 private volatile boolean mPersistentVrModeEnabled;
237
238 private volatile boolean mAwake;
239 private volatile boolean mScreenOnEarly;
240 private volatile boolean mScreenOnFully;
241 private volatile ScreenOnListener mScreenOnListener;
242
243 private volatile boolean mKeyguardDrawComplete;
244 private volatile boolean mWindowManagerDrawComplete;
245
Tiger Huang7c610aa2018-10-27 00:01:01 +0800246 private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
247 private WindowState mStatusBar = null;
248 private final int[] mStatusBarHeightForRotation = new int[4];
249 private WindowState mNavigationBar = null;
250 @NavigationBarPosition
251 private int mNavigationBarPosition = NAV_BAR_BOTTOM;
252 private int[] mNavigationBarHeightForRotationDefault = new int[4];
253 private int[] mNavigationBarWidthForRotationDefault = new int[4];
254 private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
255 private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
256
257 private final StatusBarController mStatusBarController = new StatusBarController();
258
259 private final BarController mNavigationBarController = new BarController("NavigationBar",
260 View.NAVIGATION_BAR_TRANSIENT,
261 View.NAVIGATION_BAR_UNHIDE,
262 View.NAVIGATION_BAR_TRANSLUCENT,
263 StatusBarManager.WINDOW_NAVIGATION_BAR,
264 FLAG_TRANSLUCENT_NAVIGATION,
265 View.NAVIGATION_BAR_TRANSPARENT);
266
267 private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
268 new BarController.OnBarVisibilityChangedListener() {
269 @Override
270 public void onBarVisibilityChanged(boolean visible) {
271 if (mAccessibilityManager == null) {
272 return;
273 }
274 mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
275 }
276 };
277
278 // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
279 private NavigationBarExperiments mExperiments = new NavigationBarExperiments();
280 // EXPERIMENT END
281
282 @GuardedBy("mHandler")
283 private SleepToken mDreamingSleepToken;
284
285 @GuardedBy("mHandler")
286 private SleepToken mWindowSleepToken;
287
288 private final Runnable mAcquireSleepTokenRunnable;
289 private final Runnable mReleaseSleepTokenRunnable;
290
291 // The windows we were told about in focusChanged.
292 private WindowState mFocusedWindow;
293 private WindowState mLastFocusedWindow;
294
295 IApplicationToken mFocusedApp;
296
297 int mLastSystemUiFlags;
298 // Bits that we are in the process of clearing, so we want to prevent
299 // them from being set by applications until everything has been updated
300 // to have them clear.
301 private int mResettingSystemUiFlags = 0;
302 // Bits that we are currently always keeping cleared.
303 private int mForceClearedSystemUiFlags = 0;
304 private int mLastFullscreenStackSysUiFlags;
305 private int mLastDockedStackSysUiFlags;
306 private final Rect mNonDockedStackBounds = new Rect();
307 private final Rect mDockedStackBounds = new Rect();
308 private final Rect mLastNonDockedStackBounds = new Rect();
309 private final Rect mLastDockedStackBounds = new Rect();
310
311 // What we last reported to system UI about whether the compatibility
312 // menu needs to be displayed.
313 private boolean mLastFocusNeedsMenu = false;
314 // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
315 private long mPendingPanicGestureUptime;
316
317 private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
318 private static final Rect sTmpRect = new Rect();
319 private static final Rect sTmpDockedFrame = new Rect();
320 private static final Rect sTmpNavFrame = new Rect();
321 private static final Rect sTmpLastParentFrame = new Rect();
322
323 private WindowState mTopFullscreenOpaqueWindowState;
324 private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
325 private WindowState mTopDockedOpaqueWindowState;
326 private WindowState mTopDockedOpaqueOrDimmingWindowState;
327 private boolean mTopIsFullscreen;
328 private boolean mForceStatusBar;
329 private boolean mForceStatusBarFromKeyguard;
330 private boolean mForceStatusBarTransparent;
331 private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
332 private boolean mForcingShowNavBar;
333 private int mForcingShowNavBarLayer;
334 private boolean mForceShowSystemBars;
335
336 private boolean mShowingDream;
337 private boolean mLastShowingDream;
338 private boolean mDreamingLockscreen;
339 private boolean mDreamingSleepTokenNeeded;
340 private boolean mWindowSleepTokenNeeded;
341 private boolean mLastWindowSleepTokenNeeded;
342 private boolean mAllowLockscreenWhenOn;
343
344 private InputConsumer mInputConsumer = null;
345
Issei Suzukia5dbf522019-02-01 17:58:15 +0100346 /**
347 * The area covered by system windows which belong to another display. Forwarded insets is set
348 * in case this is a virtual display, this is displayed on another display that has insets, and
349 * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
350 * displayed on the host display, and it covers a part of this virtual display.)
351 * The forwarded insets is used to compute display frames of this virtual display, which will
352 * be then used to layout windows in the virtual display.
353 */
354 @NonNull private Insets mForwardedInsets = Insets.NONE;
355
Tiger Huang7c610aa2018-10-27 00:01:01 +0800356 // -------- PolicyHandler --------
357 private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
358 private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
359 private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
360
361 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
362 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
363
364 private class PolicyHandler extends Handler {
365
366 PolicyHandler(Looper looper) {
367 super(looper);
368 }
369
370 @Override
371 public void handleMessage(Message msg) {
372 switch (msg.what) {
373 case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
374 updateDreamingSleepToken(msg.arg1 != 0);
375 break;
376 case MSG_REQUEST_TRANSIENT_BARS:
377 WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
378 ? mStatusBar : mNavigationBar;
379 if (targetBar != null) {
380 requestTransientBars(targetBar);
381 }
382 break;
383 case MSG_DISPOSE_INPUT_CONSUMER:
384 disposeInputConsumer((InputConsumer) msg.obj);
385 break;
386 }
387 }
388 }
389
390 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800391 mService = service;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800392 mContext = displayContent.isDefaultDisplay ? service.mContext
393 : service.mContext.createDisplayContext(displayContent.getDisplay());
394 mDisplayContent = displayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800395 mLock = service.getWindowManagerLock();
Tiger Huang7c610aa2018-10-27 00:01:01 +0800396
397 final Resources r = mContext.getResources();
398 mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
399 mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
400 mTranslucentDecorEnabled = r.getBoolean(R.bool.config_enableTranslucentDecor);
401 updateConfigurationDependentBehaviors();
402
403 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
404 Context.ACCESSIBILITY_SERVICE);
405 if (!displayContent.isDefaultDisplay) {
406 mAwake = true;
407 mScreenOnEarly = true;
408 mScreenOnFully = true;
409 }
410
411 final Looper looper = UiThread.getHandler().getLooper();
412 mHandler = new PolicyHandler(looper);
413 mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
414 new SystemGesturesPointerEventListener.Callbacks() {
415 @Override
416 public void onSwipeFromTop() {
417 if (mStatusBar != null) {
418 requestTransientBars(mStatusBar);
419 }
420 }
421
422 @Override
423 public void onSwipeFromBottom() {
424 if (mNavigationBar != null
425 && mNavigationBarPosition == NAV_BAR_BOTTOM) {
426 requestTransientBars(mNavigationBar);
427 }
428 }
429
430 @Override
431 public void onSwipeFromRight() {
432 if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_RIGHT) {
433 requestTransientBars(mNavigationBar);
434 }
435 }
436
437 @Override
438 public void onSwipeFromLeft() {
439 if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_LEFT) {
440 requestTransientBars(mNavigationBar);
441 }
442 }
443
444 @Override
445 public void onFling(int duration) {
446 if (mService.mPowerManagerInternal != null) {
447 mService.mPowerManagerInternal.powerHint(
448 PowerHint.INTERACTION, duration);
449 }
450 }
451
452 @Override
453 public void onDebug() {
454 // no-op
455 }
456
457 private WindowOrientationListener getOrientationListener() {
458 final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
459 return rotation != null ? rotation.getOrientationListener() : null;
460 }
461
462 @Override
463 public void onDown() {
464 final WindowOrientationListener listener = getOrientationListener();
465 if (listener != null) {
466 listener.onTouchStart();
467 }
468 }
469
470 @Override
471 public void onUpOrCancel() {
472 final WindowOrientationListener listener = getOrientationListener();
473 if (listener != null) {
474 listener.onTouchEnd();
475 }
476 }
477
478 @Override
479 public void onMouseHoverAtTop() {
480 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
481 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
482 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
483 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
484 }
485
486 @Override
487 public void onMouseHoverAtBottom() {
488 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
489 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
490 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
491 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
492 }
493
494 @Override
495 public void onMouseLeaveFromEdge() {
496 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
497 }
498 });
499 displayContent.registerPointerEventListener(mSystemGestures);
500 displayContent.mAppTransition.registerListenerLocked(
501 mStatusBarController.getAppTransitionListener());
502 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
503 mService.mVrModeEnabled);
504 mAcquireSleepTokenRunnable = () -> {
505 if (mWindowSleepToken != null) {
506 return;
507 }
508 final int displayId = displayContent.getDisplayId();
509 mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
510 "WindowSleepTokenOnDisplay" + displayId, displayId);
511 };
512 mReleaseSleepTokenRunnable = () -> {
513 if (mWindowSleepToken == null) {
514 return;
515 }
516 mWindowSleepToken.release();
517 mWindowSleepToken = null;
518 };
519
520 // TODO: Make it can take screenshot on external display
521 mScreenshotHelper = displayContent.isDefaultDisplay
522 ? new ScreenshotHelper(mContext) : null;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800523
Tiger Huang7c610aa2018-10-27 00:01:01 +0800524 if (mDisplayContent.isDefaultDisplay) {
Louis Changfc64c832018-12-04 11:38:26 +0800525 mHasStatusBar = true;
Tiger Huang7c610aa2018-10-27 00:01:01 +0800526 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800527
Tiger Huang7c610aa2018-10-27 00:01:01 +0800528 // Allow a system property to override this. Used by the emulator.
529 // See also hasNavigationBar().
530 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
531 if ("1".equals(navBarOverride)) {
532 mHasNavigationBar = false;
533 } else if ("0".equals(navBarOverride)) {
534 mHasNavigationBar = true;
535 }
536 } else {
Louis Changfc64c832018-12-04 11:38:26 +0800537 mHasStatusBar = false;
Andrii Kuliandd989612019-02-21 12:13:28 -0800538 mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800539 }
540 }
541
Charles Chen5bdd3e22018-12-18 17:51:56 +0800542 void systemReady() {
543 mSystemGestures.systemReady();
544 }
545
546 private int getDisplayId() {
547 return mDisplayContent.getDisplayId();
548 }
549
Charles Chen5bdd3e22018-12-18 17:51:56 +0800550 void configure(int width, int height, int shortSizeDp) {
551 // Allow the navigation bar to move on non-square small devices (phones).
552 mNavigationBarCanMove = width != height && shortSizeDp < 600;
553 }
554
Tiger Huang7c610aa2018-10-27 00:01:01 +0800555 void updateConfigurationDependentBehaviors() {
556 mNavBarOpacityMode = mContext.getResources().getInteger(R.integer.config_navBarOpacityMode);
557 }
558
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800559 public void setHdmiPlugged(boolean plugged) {
560 setHdmiPlugged(plugged, false /* force */);
561 }
562
563 public void setHdmiPlugged(boolean plugged, boolean force) {
564 if (force || mHdmiPlugged != plugged) {
565 mHdmiPlugged = plugged;
566 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
567 final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
568 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
569 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800570 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800571 }
572 }
573
574 boolean isHdmiPlugged() {
575 return mHdmiPlugged;
576 }
577
578 boolean isCarDockEnablesAccelerometer() {
579 return mCarDockEnablesAccelerometer;
580 }
581
582 boolean isDeskDockEnablesAccelerometer() {
583 return mDeskDockEnablesAccelerometer;
584 }
585
586 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
587 mPersistentVrModeEnabled = persistentVrModeEnabled;
588 }
589
590 public boolean isPersistentVrModeEnabled() {
591 return mPersistentVrModeEnabled;
592 }
593
594 public void setDockMode(int dockMode) {
595 mDockMode = dockMode;
596 }
597
598 public int getDockMode() {
599 return mDockMode;
600 }
601
602 public boolean hasNavigationBar() {
603 return mHasNavigationBar;
604 }
605
Louis Changfc64c832018-12-04 11:38:26 +0800606 public boolean hasStatusBar() {
607 return mHasStatusBar;
608 }
609
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800610 public boolean navigationBarCanMove() {
611 return mNavigationBarCanMove;
612 }
613
614 public void setLidState(int lidState) {
615 mLidState = lidState;
616 }
617
618 public int getLidState() {
619 return mLidState;
620 }
621
622 public void setAwake(boolean awake) {
623 mAwake = awake;
624 }
625
626 public boolean isAwake() {
627 return mAwake;
628 }
629
630 public boolean isScreenOnEarly() {
631 return mScreenOnEarly;
632 }
633
634 public boolean isScreenOnFully() {
635 return mScreenOnFully;
636 }
637
638 public boolean isKeyguardDrawComplete() {
639 return mKeyguardDrawComplete;
640 }
641
642 public boolean isWindowManagerDrawComplete() {
643 return mWindowManagerDrawComplete;
644 }
645
646 public ScreenOnListener getScreenOnListener() {
647 return mScreenOnListener;
648 }
649
650 public void screenTurnedOn(ScreenOnListener screenOnListener) {
651 synchronized (mLock) {
652 mScreenOnEarly = true;
653 mScreenOnFully = false;
654 mKeyguardDrawComplete = false;
655 mWindowManagerDrawComplete = false;
656 mScreenOnListener = screenOnListener;
657 }
658 }
659
660 public void screenTurnedOff() {
661 synchronized (mLock) {
662 mScreenOnEarly = false;
663 mScreenOnFully = false;
664 mKeyguardDrawComplete = false;
665 mWindowManagerDrawComplete = false;
666 mScreenOnListener = null;
667 }
668 }
669
670 /** Return false if we are not awake yet or we have already informed of this event. */
671 public boolean finishKeyguardDrawn() {
672 synchronized (mLock) {
673 if (!mScreenOnEarly || mKeyguardDrawComplete) {
674 return false;
675 }
676
677 mKeyguardDrawComplete = true;
678 mWindowManagerDrawComplete = false;
679 }
680 return true;
681 }
682
683 /** Return false if screen is not turned on or we did already handle this case earlier. */
684 public boolean finishWindowsDrawn() {
685 synchronized (mLock) {
686 if (!mScreenOnEarly || mWindowManagerDrawComplete) {
687 return false;
688 }
689
690 mWindowManagerDrawComplete = true;
691 }
692 return true;
693 }
694
695 /** Return false if it is not ready to turn on. */
696 public boolean finishScreenTurningOn() {
697 synchronized (mLock) {
698 if (DEBUG_SCREEN_ON) Slog.d(TAG,
699 "finishScreenTurningOn: mAwake=" + mAwake
700 + ", mScreenOnEarly=" + mScreenOnEarly
701 + ", mScreenOnFully=" + mScreenOnFully
702 + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
703 + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
704
705 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
706 || (mAwake && !mKeyguardDrawComplete)) {
707 return false;
708 }
709
710 if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on...");
711 mScreenOnListener = null;
712 mScreenOnFully = true;
713 }
714 return true;
715 }
716
Tiger Huang7c610aa2018-10-27 00:01:01 +0800717 /**
718 * Sanitize the layout parameters coming from a client. Allows the policy
719 * to do things like ensure that windows of a specific type can't take
720 * input focus.
721 *
722 * @param attrs The window layout parameters to be modified. These values
723 * are modified in-place.
724 */
725 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
726 boolean hasStatusBarServicePermission) {
727
728 final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
729 if (mScreenDecorWindows.contains(win)) {
730 if (!isScreenDecor) {
731 // No longer has the flag set, so remove from the set.
732 mScreenDecorWindows.remove(win);
733 }
734 } else if (isScreenDecor && hasStatusBarServicePermission) {
735 mScreenDecorWindows.add(win);
736 }
737
738 switch (attrs.type) {
739 case TYPE_SYSTEM_OVERLAY:
740 case TYPE_SECURE_SYSTEM_OVERLAY:
741 // These types of windows can't receive input events.
742 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
743 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
744 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
745 break;
746 case TYPE_DREAM:
747 case TYPE_WALLPAPER:
748 // Dreams and wallpapers don't have an app window token and can thus not be
749 // letterboxed. Hence always let them extend under the cutout.
750 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
751 break;
752 case TYPE_STATUS_BAR:
753
754 // If the Keyguard is in a hidden state (occluded by another window), we force to
755 // remove the wallpaper and keyguard flag so that any change in-flight after setting
756 // the keyguard as occluded wouldn't set these flags again.
757 // See {@link #processKeyguardSetHiddenResultLw}.
758 if (mService.mPolicy.isKeyguardOccluded()) {
759 attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
760 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
761 }
762 break;
763
764 case TYPE_SCREENSHOT:
765 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
766 break;
767
768 case TYPE_TOAST:
769 // While apps should use the dedicated toast APIs to add such windows
770 // it possible legacy apps to add the window directly. Therefore, we
771 // make windows added directly by the app behave as a toast as much
772 // as possible in terms of timeout and animation.
773 if (attrs.hideTimeoutMilliseconds < 0
774 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
775 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
776 }
Rhed Jao406d3a22018-11-30 19:28:58 +0800777 // Accessibility users may need longer timeout duration. This api compares
778 // original timeout with user's preference and return longer one. It returns
779 // original timeout if there's no preference.
780 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
781 (int) attrs.hideTimeoutMilliseconds,
782 AccessibilityManager.FLAG_CONTENT_TEXT);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800783 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
784 break;
785 }
786
787 if (attrs.type != TYPE_STATUS_BAR) {
788 // The status bar is the only window allowed to exhibit keyguard behavior.
789 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
790 }
791 }
792
793 /**
794 * Preflight adding a window to the system.
795 *
796 * Currently enforces that three window types are singletons per display:
797 * <ul>
798 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
799 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
800 * </ul>
801 *
802 * @param win The window to be added
803 * @param attrs Information about the window to be added
804 *
805 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
806 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
807 */
808 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
809
810 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
811 mContext.enforceCallingOrSelfPermission(
812 android.Manifest.permission.STATUS_BAR_SERVICE,
813 "DisplayPolicy");
814 mScreenDecorWindows.add(win);
815 }
816
817 switch (attrs.type) {
818 case TYPE_STATUS_BAR:
819 mContext.enforceCallingOrSelfPermission(
820 android.Manifest.permission.STATUS_BAR_SERVICE,
821 "DisplayPolicy");
822 if (mStatusBar != null) {
823 if (mStatusBar.isAlive()) {
824 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
825 }
826 }
827 mStatusBar = win;
828 mStatusBarController.setWindow(win);
829 if (mDisplayContent.isDefaultDisplay) {
830 mService.mPolicy.setKeyguardCandidateLw(win);
831 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200832 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win,
833 (displayFrames, windowState, rect) -> {
834 rect.top = 0;
835 rect.bottom = getStatusBarHeight(displayFrames);
836 });
Tiger Huang7c610aa2018-10-27 00:01:01 +0800837 break;
838 case TYPE_NAVIGATION_BAR:
839 mContext.enforceCallingOrSelfPermission(
840 android.Manifest.permission.STATUS_BAR_SERVICE,
841 "DisplayPolicy");
842 if (mNavigationBar != null) {
843 if (mNavigationBar.isAlive()) {
844 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
845 }
846 }
847 mNavigationBar = win;
848 mNavigationBarController.setWindow(win);
849 mNavigationBarController.setOnBarVisibilityChangedListener(
850 mNavBarVisibilityListener, true);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200851 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR,
852 win, null /* frameProvider */);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800853 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
854 break;
855 case TYPE_NAVIGATION_BAR_PANEL:
856 case TYPE_STATUS_BAR_PANEL:
857 case TYPE_STATUS_BAR_SUB_PANEL:
858 case TYPE_VOICE_INTERACTION_STARTING:
859 mContext.enforceCallingOrSelfPermission(
860 android.Manifest.permission.STATUS_BAR_SERVICE,
861 "DisplayPolicy");
862 break;
863 }
864 return ADD_OKAY;
865 }
866
867 /**
868 * Called when a window is being removed from a window manager. Must not
869 * throw an exception -- clean up as much as possible.
870 *
871 * @param win The window being removed.
872 */
873 public void removeWindowLw(WindowState win) {
874 if (mStatusBar == win) {
875 mStatusBar = null;
876 mStatusBarController.setWindow(null);
877 if (mDisplayContent.isDefaultDisplay) {
878 mService.mPolicy.setKeyguardCandidateLw(null);
879 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200880 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800881 } else if (mNavigationBar == win) {
882 mNavigationBar = null;
883 mNavigationBarController.setWindow(null);
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200884 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, null, null);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800885 }
886 if (mLastFocusedWindow == win) {
887 mLastFocusedWindow = null;
888 }
889 mScreenDecorWindows.remove(win);
890 }
891
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200892 private int getStatusBarHeight(DisplayFrames displayFrames) {
893 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
894 displayFrames.mDisplayCutoutSafe.top);
895 }
896
Tiger Huang7c610aa2018-10-27 00:01:01 +0800897 /**
898 * Control the animation to run when a window's state changes. Return a
899 * non-0 number to force the animation to a specific resource ID, or 0
900 * to use the default animation.
901 *
902 * @param win The window that is changing.
903 * @param transit What is happening to the window:
904 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
905 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
906 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
907 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
908 *
909 * @return Resource ID of the actual animation to use, or 0 for none.
910 */
911 public int selectAnimationLw(WindowState win, int transit) {
912 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
913 + ": transit=" + transit);
914 if (win == mStatusBar) {
915 final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
916 final boolean expanded = win.getAttrs().height == MATCH_PARENT
917 && win.getAttrs().width == MATCH_PARENT;
918 if (isKeyguard || expanded) {
919 return -1;
920 }
921 if (transit == TRANSIT_EXIT
922 || transit == TRANSIT_HIDE) {
923 return R.anim.dock_top_exit;
924 } else if (transit == TRANSIT_ENTER
925 || transit == TRANSIT_SHOW) {
926 return R.anim.dock_top_enter;
927 }
928 } else if (win == mNavigationBar) {
929 if (win.getAttrs().windowAnimations != 0) {
930 return 0;
931 }
932 // This can be on either the bottom or the right or the left.
933 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
934 if (transit == TRANSIT_EXIT
935 || transit == TRANSIT_HIDE) {
936 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
937 return R.anim.dock_bottom_exit_keyguard;
938 } else {
939 return R.anim.dock_bottom_exit;
940 }
941 } else if (transit == TRANSIT_ENTER
942 || transit == TRANSIT_SHOW) {
943 return R.anim.dock_bottom_enter;
944 }
945 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
946 if (transit == TRANSIT_EXIT
947 || transit == TRANSIT_HIDE) {
948 return R.anim.dock_right_exit;
949 } else if (transit == TRANSIT_ENTER
950 || transit == TRANSIT_SHOW) {
951 return R.anim.dock_right_enter;
952 }
953 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
954 if (transit == TRANSIT_EXIT
955 || transit == TRANSIT_HIDE) {
956 return R.anim.dock_left_exit;
957 } else if (transit == TRANSIT_ENTER
958 || transit == TRANSIT_SHOW) {
959 return R.anim.dock_left_enter;
960 }
961 }
962 } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
963 return selectDockedDividerAnimationLw(win, transit);
964 }
965
966 if (transit == TRANSIT_PREVIEW_DONE) {
967 if (win.hasAppShownWindows()) {
968 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
969 return R.anim.app_starting_exit;
970 }
971 } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
972 && transit == TRANSIT_ENTER) {
973 // Special case: we are animating in a dream, while the keyguard
974 // is shown. We don't want an animation on the dream, because
975 // we need it shown immediately with the keyguard animating away
976 // to reveal it.
977 return -1;
978 }
979
980 return 0;
981 }
982
983 private int selectDockedDividerAnimationLw(WindowState win, int transit) {
984 int insets = mDisplayContent.getDockedDividerController().getContentInsets();
985
986 // If the divider is behind the navigation bar, don't animate.
987 final Rect frame = win.getFrameLw();
988 final boolean behindNavBar = mNavigationBar != null
989 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
990 && frame.top + insets >= mNavigationBar.getFrameLw().top)
991 || (mNavigationBarPosition == NAV_BAR_RIGHT
992 && frame.left + insets >= mNavigationBar.getFrameLw().left)
993 || (mNavigationBarPosition == NAV_BAR_LEFT
994 && frame.right - insets <= mNavigationBar.getFrameLw().right));
995 final boolean landscape = frame.height() > frame.width();
996 final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
997 || frame.left + insets >= win.getDisplayFrameLw().right);
998 final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
999 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1000 final boolean offscreen = offscreenLandscape || offscreenPortrait;
1001 if (behindNavBar || offscreen) {
1002 return 0;
1003 }
1004 if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1005 return R.anim.fade_in;
1006 } else if (transit == TRANSIT_EXIT) {
1007 return R.anim.fade_out;
1008 } else {
1009 return 0;
1010 }
1011 }
1012
1013 /**
1014 * Determine the animation to run for a rotation transition based on the
1015 * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
1016 * and whether it is currently fullscreen and frontmost.
1017 *
1018 * @param anim The exiting animation resource id is stored in anim[0], the
1019 * entering animation resource id is stored in anim[1].
1020 */
1021 public void selectRotationAnimationLw(int anim[]) {
1022 // If the screen is off or non-interactive, force a jumpcut.
1023 final boolean forceJumpcut = !mScreenOnFully || !mService.mPolicy.okToAnimate();
1024 if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
1025 + mTopFullscreenOpaqueWindowState + " rotationAnimation="
1026 + (mTopFullscreenOpaqueWindowState == null
1027 ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)
1028 + " forceJumpcut=" + forceJumpcut);
1029 if (forceJumpcut) {
1030 anim[0] = R.anim.rotation_animation_jump_exit;
1031 anim[1] = R.anim.rotation_animation_enter;
1032 return;
1033 }
1034 if (mTopFullscreenOpaqueWindowState != null) {
1035 int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint();
1036 if (animationHint < 0 && mTopIsFullscreen) {
1037 animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation;
1038 }
1039 switch (animationHint) {
1040 case ROTATION_ANIMATION_CROSSFADE:
1041 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
1042 anim[0] = R.anim.rotation_animation_xfade_exit;
1043 anim[1] = R.anim.rotation_animation_enter;
1044 break;
1045 case ROTATION_ANIMATION_JUMPCUT:
1046 anim[0] = R.anim.rotation_animation_jump_exit;
1047 anim[1] = R.anim.rotation_animation_enter;
1048 break;
1049 case ROTATION_ANIMATION_ROTATE:
1050 default:
1051 anim[0] = anim[1] = 0;
1052 break;
1053 }
1054 } else {
1055 anim[0] = anim[1] = 0;
1056 }
1057 }
1058
1059 /**
1060 * Validate whether the current top fullscreen has specified the same
1061 * {@link WindowManager.LayoutParams#rotationAnimation} value as that
1062 * being passed in from the previous top fullscreen window.
1063 *
1064 * @param exitAnimId exiting resource id from the previous window.
1065 * @param enterAnimId entering resource id from the previous window.
1066 * @param forceDefault For rotation animations only, if true ignore the
1067 * animation values and just return false.
1068 * @return true if the previous values are still valid, false if they
1069 * should be replaced with the default.
1070 */
1071 public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
1072 boolean forceDefault) {
1073 switch (exitAnimId) {
1074 case R.anim.rotation_animation_xfade_exit:
1075 case R.anim.rotation_animation_jump_exit:
1076 // These are the only cases that matter.
1077 if (forceDefault) {
1078 return false;
1079 }
1080 int anim[] = new int[2];
1081 selectRotationAnimationLw(anim);
1082 return (exitAnimId == anim[0] && enterAnimId == anim[1]);
1083 default:
1084 return true;
1085 }
1086 }
1087
1088 /**
1089 * Called when a new system UI visibility is being reported, allowing
1090 * the policy to adjust what is actually reported.
1091 * @param visibility The raw visibility reported by the status bar.
1092 * @return The new desired visibility.
1093 */
1094 public int adjustSystemUiVisibilityLw(int visibility) {
1095 mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1096 mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1097
1098 // Reset any bits in mForceClearingStatusBarVisibility that
1099 // are now clear.
1100 mResettingSystemUiFlags &= visibility;
1101 // Clear any bits in the new visibility that are currently being
1102 // force cleared, before reporting it.
1103 return visibility & ~mResettingSystemUiFlags
1104 & ~mForceClearedSystemUiFlags;
1105 }
1106
1107 /**
1108 * @return true if the navigation bar is forced to stay visible
1109 */
1110 public boolean isNavBarForcedShownLw(WindowState windowState) {
1111 return mForceShowSystemBars;
1112 }
1113
1114 // TODO: Should probably be moved into DisplayFrames.
1115 /**
1116 * Return the layout hints for a newly added window. These values are computed on the
1117 * most recent layout, so they are not guaranteed to be correct.
1118 *
1119 * @param attrs The LayoutParams of the window.
1120 * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1121 * associated with the window.
1122 * @param displayFrames display frames.
1123 * @param floatingStack Whether the window's stack is floating.
1124 * @param outFrame The frame of the window.
1125 * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1126 * @param outStableInsets The areas covered by stable system windows irrespective of their
1127 * current visibility. Expressed as positive insets.
1128 * @param outOutsets The areas that are not real display, but we would like to treat as such.
1129 * @param outDisplayCutout The area that has been cut away from the display.
1130 * @return Whether to always consume the navigation bar.
1131 * See {@link #isNavBarForcedShownLw(WindowState)}.
1132 */
1133 public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1134 DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1135 Rect outContentInsets, Rect outStableInsets,
1136 Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
1137 final int fl = PolicyControl.getWindowFlags(null, attrs);
1138 final int pfl = attrs.privateFlags;
1139 final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1140 final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
1141 final int displayRotation = displayFrames.mRotation;
1142
1143 final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
1144 if (useOutsets) {
1145 int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
1146 if (outset > 0) {
1147 if (displayRotation == Surface.ROTATION_0) {
1148 outOutsets.bottom += outset;
1149 } else if (displayRotation == Surface.ROTATION_90) {
1150 outOutsets.right += outset;
1151 } else if (displayRotation == Surface.ROTATION_180) {
1152 outOutsets.top += outset;
1153 } else if (displayRotation == Surface.ROTATION_270) {
1154 outOutsets.left += outset;
1155 }
1156 }
1157 }
1158
1159 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1160 final boolean layoutInScreenAndInsetDecor = layoutInScreen
1161 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1162 final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1163
1164 if (layoutInScreenAndInsetDecor && !screenDecor) {
1165 if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
1166 outFrame.set(displayFrames.mUnrestricted);
1167 } else {
1168 outFrame.set(displayFrames.mRestricted);
1169 }
1170
1171 final Rect sf;
1172 if (floatingStack) {
1173 sf = null;
1174 } else {
1175 sf = displayFrames.mStable;
1176 }
1177
1178 final Rect cf;
1179 if (floatingStack) {
1180 cf = null;
1181 } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1182 if ((fl & FLAG_FULLSCREEN) != 0) {
1183 cf = displayFrames.mStableFullscreen;
1184 } else {
1185 cf = displayFrames.mStable;
1186 }
1187 } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
1188 cf = displayFrames.mOverscan;
1189 } else {
1190 cf = displayFrames.mCurrent;
1191 }
1192
1193 if (taskBounds != null) {
1194 outFrame.intersect(taskBounds);
1195 }
1196 InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1197 InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1198 outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1199 .getDisplayCutout());
1200 return mForceShowSystemBars;
1201 } else {
1202 if (layoutInScreen) {
1203 outFrame.set(displayFrames.mUnrestricted);
1204 } else {
1205 outFrame.set(displayFrames.mStable);
1206 }
1207 if (taskBounds != null) {
1208 outFrame.intersect(taskBounds);
1209 }
1210
1211 outContentInsets.setEmpty();
1212 outStableInsets.setEmpty();
1213 outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1214 return mForceShowSystemBars;
1215 }
1216 }
1217
1218 private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1219 int impliedFlags = 0;
1220 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
1221 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1222 }
1223 final boolean forceWindowDrawsStatusBarBackground =
1224 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
1225 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
1226 || forceWindowDrawsStatusBarBackground
1227 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT) {
1228 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1229 }
1230 return impliedFlags;
1231 }
1232
1233 private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
1234 return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
1235 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
1236 }
1237
1238 private final Runnable mClearHideNavigationFlag = new Runnable() {
1239 @Override
1240 public void run() {
1241 synchronized (mLock) {
1242 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1243 mDisplayContent.reevaluateStatusBarVisibility();
1244 }
1245 }
1246 };
1247
1248 /**
1249 * Input handler used while nav bar is hidden. Captures any touch on the screen,
1250 * to determine when the nav bar should be shown and prevent applications from
1251 * receiving those touches.
1252 */
1253 private final class HideNavInputEventReceiver extends InputEventReceiver {
1254 HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1255 super(inputChannel, looper);
1256 }
1257
1258 @Override
1259 public void onInputEvent(InputEvent event) {
1260 try {
1261 if (event instanceof MotionEvent
1262 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1263 final MotionEvent motionEvent = (MotionEvent) event;
1264 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1265 // When the user taps down, we re-show the nav bar.
1266 boolean changed = false;
1267 synchronized (mLock) {
1268 if (mInputConsumer == null) {
1269 return;
1270 }
1271 // Any user activity always causes us to show the
1272 // navigation controls, if they had been hidden.
1273 // We also clear the low profile and only content
1274 // flags so that tapping on the screen will atomically
1275 // restore all currently hidden screen decorations.
1276 int newVal = mResettingSystemUiFlags
1277 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1278 | View.SYSTEM_UI_FLAG_LOW_PROFILE
1279 | View.SYSTEM_UI_FLAG_FULLSCREEN;
1280 if (mResettingSystemUiFlags != newVal) {
1281 mResettingSystemUiFlags = newVal;
1282 changed = true;
1283 }
1284 // We don't allow the system's nav bar to be hidden
1285 // again for 1 second, to prevent applications from
1286 // spamming us and keeping it from being shown.
1287 newVal = mForceClearedSystemUiFlags
1288 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1289 if (mForceClearedSystemUiFlags != newVal) {
1290 mForceClearedSystemUiFlags = newVal;
1291 changed = true;
1292 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1293 }
1294 if (changed) {
1295 mDisplayContent.reevaluateStatusBarVisibility();
1296 }
1297 }
1298 }
1299 }
1300 } finally {
1301 finishInputEvent(event, false /* handled */);
1302 }
1303 }
1304 }
1305
1306 /**
1307 * Called when layout of the windows is about to start.
1308 *
1309 * @param displayFrames frames of the display we are doing layout on.
1310 * @param uiMode The current uiMode in configuration.
1311 */
1312 public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1313 displayFrames.onBeginLayout();
1314 mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1315 mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1316
1317 // For purposes of putting out fake window up to steal focus, we will
1318 // drive nav being hidden only by whether it is requested.
1319 final int sysui = mLastSystemUiFlags;
1320 boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
1321 boolean navTranslucent = (sysui
1322 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
1323 boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
1324 boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
1325 boolean navAllowedHidden = immersive || immersiveSticky;
1326 navTranslucent &= !immersiveSticky; // transient trumps translucent
1327 boolean isKeyguardShowing = isStatusBarKeyguard()
1328 && !mService.mPolicy.isKeyguardOccluded();
1329 if (!isKeyguardShowing) {
1330 navTranslucent &= areTranslucentBarsAllowed();
1331 }
1332 boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
1333 && (mStatusBar.getAttrs().privateFlags
1334 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1335
1336 // When the navigation bar isn't visible, we put up a fake input window to catch all
1337 // touch events. This way we can detect when the user presses anywhere to bring back the
1338 // nav bar and ensure the application doesn't see the event.
1339 if (navVisible || navAllowedHidden) {
1340 if (mInputConsumer != null) {
1341 mHandler.sendMessage(
1342 mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1343 mInputConsumer = null;
1344 }
1345 } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1346 mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1347 INPUT_CONSUMER_NAVIGATION,
1348 HideNavInputEventReceiver::new,
1349 displayFrames.mDisplayId);
1350 // As long as mInputConsumer is active, hover events are not dispatched to the app
1351 // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1352 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1353 }
1354
1355 // For purposes of positioning and showing the nav bar, if we have decided that it can't
1356 // be hidden (because of the screen aspect ratio), then take that into account.
1357 navVisible |= !canHideNavigationBar();
1358
1359 boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
1360 navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
1361 if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1362 updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1363 if (updateSysUiVisibility) {
1364 updateSystemUiVisibilityLw();
1365 }
1366 layoutScreenDecorWindows(displayFrames);
1367
1368 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1369 // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1370 // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1371 // bar.
1372 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1373 displayFrames.mStable.top);
1374 }
Issei Suzukia5dbf522019-02-01 17:58:15 +01001375
1376 // In case this is a virtual display, and the host display has insets that overlap this
1377 // virtual display, apply the insets of the overlapped area onto the current and content
1378 // frame of this virtual display. This let us layout windows in the virtual display as
1379 // expected when the window needs to avoid overlap with the system windows.
1380 // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1381 // IME.
1382 displayFrames.mCurrent.inset(mForwardedInsets);
1383 displayFrames.mContent.inset(mForwardedInsets);
Tiger Huang7c610aa2018-10-27 00:01:01 +08001384 }
1385
1386 private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1387 if (mScreenDecorWindows.isEmpty()) {
1388 return;
1389 }
1390
1391 sTmpRect.setEmpty();
1392 sTmpDockedFrame.set(displayFrames.mDock);
1393
1394 final int displayId = displayFrames.mDisplayId;
1395 final Rect dockFrame = displayFrames.mDock;
1396 final int displayHeight = displayFrames.mDisplayHeight;
1397 final int displayWidth = displayFrames.mDisplayWidth;
1398
1399 for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1400 final WindowState w = mScreenDecorWindows.valueAt(i);
1401 if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1402 // Skip if not on the same display or not visible.
1403 continue;
1404 }
1405
1406 w.getWindowFrames().setFrames(sTmpDockedFrame /* parentFrame */,
1407 sTmpDockedFrame /* displayFrame */, sTmpDockedFrame /* overscanFrame */,
1408 sTmpDockedFrame /* contentFrame */, sTmpDockedFrame /* visibleFrame */,
1409 sTmpRect /* decorFrame */, sTmpDockedFrame /* stableFrame */,
1410 sTmpDockedFrame /* outsetFrame */);
1411 w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1412 w.computeFrameLw();
1413 final Rect frame = w.getFrameLw();
1414
1415 if (frame.left <= 0 && frame.top <= 0) {
1416 // Docked at left or top.
1417 if (frame.bottom >= displayHeight) {
1418 // Docked left.
1419 dockFrame.left = Math.max(frame.right, dockFrame.left);
1420 } else if (frame.right >= displayWidth) {
1421 // Docked top.
1422 dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1423 } else {
1424 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1425 + " not docked on left or top of display. frame=" + frame
1426 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1427 }
1428 } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1429 // Docked at right or bottom.
1430 if (frame.top <= 0) {
1431 // Docked right.
1432 dockFrame.right = Math.min(frame.left, dockFrame.right);
1433 } else if (frame.left <= 0) {
1434 // Docked bottom.
1435 dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1436 } else {
1437 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1438 + " not docked on right or bottom" + " of display. frame=" + frame
1439 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1440 }
1441 } else {
1442 // Screen decor windows are required to be docked on one of the sides of the screen.
1443 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1444 + " not docked on one of the sides of the display. frame=" + frame
1445 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1446 }
1447 }
1448
1449 displayFrames.mRestricted.set(dockFrame);
1450 displayFrames.mCurrent.set(dockFrame);
1451 displayFrames.mVoiceContent.set(dockFrame);
1452 displayFrames.mSystem.set(dockFrame);
1453 displayFrames.mContent.set(dockFrame);
1454 displayFrames.mRestrictedOverscan.set(dockFrame);
1455 }
1456
1457 private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1458 boolean isKeyguardShowing) {
1459 // decide where the status bar goes ahead of time
1460 if (mStatusBar == null) {
1461 return false;
1462 }
1463 // apply any navigation bar insets
1464 sTmpRect.setEmpty();
1465 mStatusBar.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1466 displayFrames.mUnrestricted /* displayFrame */,
1467 displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
1468 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
1469 displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
1470 mStatusBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1471
1472 // Let the status bar determine its size.
1473 mStatusBar.computeFrameLw();
1474
1475 // For layout, the status bar is always at the top with our fixed height.
1476 displayFrames.mStable.top = displayFrames.mUnrestricted.top
1477 + mStatusBarHeightForRotation[displayFrames.mRotation];
1478 // Make sure the status bar covers the entire cutout height
1479 displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1480 displayFrames.mDisplayCutoutSafe.top);
1481
1482 // Tell the bar controller where the collapsed status bar content is
1483 sTmpRect.set(mStatusBar.getContentFrameLw());
1484 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1485 sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
1486 sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
1487 mStatusBarController.setContentFrame(sTmpRect);
1488
1489 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
1490 boolean statusBarTranslucent = (sysui
1491 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
1492 if (!isKeyguardShowing) {
1493 statusBarTranslucent &= areTranslucentBarsAllowed();
1494 }
1495
1496 // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1497 if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1498 // Status bar may go away, so the screen area it occupies is available to apps but just
1499 // covering them when the status bar is visible.
1500 final Rect dockFrame = displayFrames.mDock;
1501 dockFrame.top = displayFrames.mStable.top;
1502 displayFrames.mContent.set(dockFrame);
1503 displayFrames.mVoiceContent.set(dockFrame);
1504 displayFrames.mCurrent.set(dockFrame);
1505
1506 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1507 "dock=%s content=%s cur=%s", dockFrame.toString(),
1508 displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1509
1510 if (!mStatusBar.isAnimatingLw() && !statusBarTranslucent
1511 && !mStatusBarController.wasRecentlyTranslucent()) {
1512 // If the opaque status bar is currently requested to be visible, and not in the
1513 // process of animating on or off, then we can tell the app that it is covered by
1514 // it.
1515 displayFrames.mSystem.top = displayFrames.mStable.top;
1516 }
1517 }
1518 return mStatusBarController.checkHiddenLw();
1519 }
1520
1521 private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1522 boolean navTranslucent, boolean navAllowedHidden,
1523 boolean statusBarForcesShowingNavigation) {
1524 if (mNavigationBar == null) {
1525 return false;
1526 }
1527
1528 final Rect navigationFrame = sTmpNavFrame;
1529 boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1530 // Force the navigation bar to its appropriate place and size. We need to do this directly,
1531 // instead of relying on it to bubble up from the nav bar, because this needs to change
1532 // atomically with screen rotations.
1533 final int rotation = displayFrames.mRotation;
1534 final int displayHeight = displayFrames.mDisplayHeight;
1535 final int displayWidth = displayFrames.mDisplayWidth;
1536 final Rect dockFrame = displayFrames.mDock;
1537 mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1538
1539 final Rect cutoutSafeUnrestricted = sTmpRect;
1540 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1541 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1542
1543 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1544 // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1545 final int top = cutoutSafeUnrestricted.bottom
1546 - getNavigationBarHeight(rotation, uiMode);
1547 // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
1548 final int topNavBar = cutoutSafeUnrestricted.bottom
1549 - mExperiments.getNavigationBarFrameHeight();
1550 navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
1551 // EXPERIMENT END
1552 displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1553 if (transientNavBarShowing) {
1554 mNavigationBarController.setBarShowingLw(true);
1555 } else if (navVisible) {
1556 mNavigationBarController.setBarShowingLw(true);
1557 dockFrame.bottom = displayFrames.mRestricted.bottom =
1558 displayFrames.mRestrictedOverscan.bottom = top;
1559 } else {
1560 // We currently want to hide the navigation UI - unless we expanded the status bar.
1561 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1562 }
1563 if (navVisible && !navTranslucent && !navAllowedHidden
1564 && !mNavigationBar.isAnimatingLw()
1565 && !mNavigationBarController.wasRecentlyTranslucent()) {
1566 // If the opaque nav bar is currently requested to be visible and not in the process
1567 // of animating on or off, then we can tell the app that it is covered by it.
1568 displayFrames.mSystem.bottom = top;
1569 }
1570 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1571 // Landscape screen; nav bar goes to the right.
1572 final int left = cutoutSafeUnrestricted.right
1573 - getNavigationBarWidth(rotation, uiMode);
1574 // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
1575 final int leftNavBar = cutoutSafeUnrestricted.right
1576 - mExperiments.getNavigationBarFrameWidth();
1577 navigationFrame.set(leftNavBar, 0, displayFrames.mUnrestricted.right, displayHeight);
1578 // EXPERIMENT END
1579 displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1580 if (transientNavBarShowing) {
1581 mNavigationBarController.setBarShowingLw(true);
1582 } else if (navVisible) {
1583 mNavigationBarController.setBarShowingLw(true);
1584 dockFrame.right = displayFrames.mRestricted.right =
1585 displayFrames.mRestrictedOverscan.right = left;
1586 } else {
1587 // We currently want to hide the navigation UI - unless we expanded the status bar.
1588 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1589 }
1590 if (navVisible && !navTranslucent && !navAllowedHidden
1591 && !mNavigationBar.isAnimatingLw()
1592 && !mNavigationBarController.wasRecentlyTranslucent()) {
1593 // If the nav bar is currently requested to be visible, and not in the process of
1594 // animating on or off, then we can tell the app that it is covered by it.
1595 displayFrames.mSystem.right = left;
1596 }
1597 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1598 // Seascape screen; nav bar goes to the left.
1599 final int right = cutoutSafeUnrestricted.left
1600 + getNavigationBarWidth(rotation, uiMode);
1601 // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
1602 final int rightNavBar = cutoutSafeUnrestricted.left
1603 + mExperiments.getNavigationBarFrameWidth();
1604 navigationFrame.set(displayFrames.mUnrestricted.left, 0, rightNavBar, displayHeight);
1605 // EXPERIMENT END
1606 displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1607 if (transientNavBarShowing) {
1608 mNavigationBarController.setBarShowingLw(true);
1609 } else if (navVisible) {
1610 mNavigationBarController.setBarShowingLw(true);
1611 dockFrame.left = displayFrames.mRestricted.left =
1612 displayFrames.mRestrictedOverscan.left = right;
1613 } else {
1614 // We currently want to hide the navigation UI - unless we expanded the status bar.
1615 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1616 }
1617 if (navVisible && !navTranslucent && !navAllowedHidden
1618 && !mNavigationBar.isAnimatingLw()
1619 && !mNavigationBarController.wasRecentlyTranslucent()) {
1620 // If the nav bar is currently requested to be visible, and not in the process of
1621 // animating on or off, then we can tell the app that it is covered by it.
1622 displayFrames.mSystem.left = right;
1623 }
1624 }
1625
1626 // Make sure the content and current rectangles are updated to account for the restrictions
1627 // from the navigation bar.
1628 displayFrames.mCurrent.set(dockFrame);
1629 displayFrames.mVoiceContent.set(dockFrame);
1630 displayFrames.mContent.set(dockFrame);
1631 // And compute the final frame.
1632 sTmpRect.setEmpty();
1633 mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
1634 navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
1635 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1636 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
1637 navigationFrame /* stableFrame */,
1638 displayFrames.mDisplayCutoutSafe /* outsetFrame */);
1639 mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1640 mNavigationBar.computeFrameLw();
1641 mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1642
1643 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1644 return mNavigationBarController.checkHiddenLw();
1645 }
1646
1647 private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
1648 boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
1649 DisplayFrames displayFrames) {
1650 if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1651 // Here's a special case: if the child window is not the 'dock window'
1652 // or input method target, and the window it is attached to is below
1653 // the dock window, then the frames we computed for the window it is
1654 // attached to can not be used because the dock is effectively part
1655 // of the underlying window and the attached window is floating on top
1656 // of the whole thing. So, we ignore the attached window and explicitly
1657 // compute the frames that would be appropriate without the dock.
1658 vf.set(displayFrames.mDock);
1659 cf.set(displayFrames.mDock);
1660 of.set(displayFrames.mDock);
1661 df.set(displayFrames.mDock);
1662 } else {
1663 // The effective display frame of the attached window depends on whether it is taking
1664 // care of insetting its content. If not, we need to use the parent's content frame so
1665 // that the entire window is positioned within that content. Otherwise we can use the
1666 // overscan frame and let the attached window take care of positioning its content
1667 // appropriately.
1668 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1669 // Set the content frame of the attached window to the parent's decor frame
1670 // (same as content frame when IME isn't present) if specifically requested by
1671 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1672 // Otherwise, use the overscan frame.
1673 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
1674 ? attached.getContentFrameLw() : attached.getOverscanFrameLw());
1675 } else {
1676 // If the window is resizing, then we want to base the content frame on our attached
1677 // content frame to resize...however, things can be tricky if the attached window is
1678 // NOT in resize mode, in which case its content frame will be larger.
1679 // Ungh. So to deal with that, make sure the content frame we end up using is not
1680 // covering the IM dock.
1681 cf.set(attached.getContentFrameLw());
1682 if (attached.isVoiceInteraction()) {
1683 cf.intersectUnchecked(displayFrames.mVoiceContent);
1684 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1685 cf.intersectUnchecked(displayFrames.mContent);
1686 }
1687 }
1688 df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
1689 of.set(insetDecors ? attached.getOverscanFrameLw() : cf);
1690 vf.set(attached.getVisibleFrameLw());
1691 }
1692 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1693 // positioned relative to its parent or the entire screen.
1694 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1695 }
1696
1697 private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1698 if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1699 return;
1700 }
1701 // If app is requesting a stable layout, don't let the content insets go below the stable
1702 // values.
1703 if ((fl & FLAG_FULLSCREEN) != 0) {
1704 r.intersectUnchecked(displayFrames.mStableFullscreen);
1705 } else {
1706 r.intersectUnchecked(displayFrames.mStable);
1707 }
1708 }
1709
1710 private boolean canReceiveInput(WindowState win) {
1711 boolean notFocusable =
1712 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1713 boolean altFocusableIm =
1714 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1715 boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1716 return !notFocusableForIm;
1717 }
1718
1719 /**
1720 * Called for each window attached to the window manager as layout is proceeding. The
1721 * implementation of this function must take care of setting the window's frame, either here or
1722 * in finishLayout().
1723 *
1724 * @param win The window being positioned.
1725 * @param attached For sub-windows, the window it is attached to; this
1726 * window will already have had layoutWindow() called on it
1727 * so you can use its Rect. Otherwise null.
1728 * @param displayFrames The display frames.
1729 */
1730 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1731 // We've already done the navigation bar, status bar, and all screen decor windows. If the
1732 // status bar can receive input, we need to layout it again to accommodate for the IME
1733 // window.
1734 if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1735 || mScreenDecorWindows.contains(win)) {
1736 return;
1737 }
1738 final WindowManager.LayoutParams attrs = win.getAttrs();
1739 final boolean isDefaultDisplay = win.isDefaultDisplay();
1740
1741 final int type = attrs.type;
1742 final int fl = PolicyControl.getWindowFlags(win, attrs);
1743 final int pfl = attrs.privateFlags;
1744 final int sim = attrs.softInputMode;
1745 final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1746 final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1747
1748 final WindowFrames windowFrames = win.getWindowFrames();
1749
1750 windowFrames.setHasOutsets(false);
1751 sTmpLastParentFrame.set(windowFrames.mParentFrame);
1752 final Rect pf = windowFrames.mParentFrame;
1753 final Rect df = windowFrames.mDisplayFrame;
1754 final Rect of = windowFrames.mOverscanFrame;
1755 final Rect cf = windowFrames.mContentFrame;
1756 final Rect vf = windowFrames.mVisibleFrame;
1757 final Rect dcf = windowFrames.mDecorFrame;
1758 final Rect sf = windowFrames.mStableFrame;
1759 dcf.setEmpty();
1760 windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1761 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1762
1763 final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1764 && mNavigationBar.isVisibleLw();
1765
1766 final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1767
1768 final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
1769 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
1770
1771 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1772 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1773
1774 sf.set(displayFrames.mStable);
1775
1776 if (type == TYPE_INPUT_METHOD) {
1777 vf.set(displayFrames.mDock);
1778 cf.set(displayFrames.mDock);
1779 of.set(displayFrames.mDock);
1780 df.set(displayFrames.mDock);
1781 windowFrames.mParentFrame.set(displayFrames.mDock);
1782 // IM dock windows layout below the nav bar...
1783 pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
1784 // ...with content insets above the nav bar
1785 cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1786 if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1787 // The status bar forces the navigation bar while it's visible. Make sure the IME
1788 // avoids the navigation bar in that case.
1789 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1790 pf.right = df.right = of.right = cf.right = vf.right =
1791 displayFrames.mStable.right;
1792 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1793 pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
1794 }
1795 }
1796
1797 // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
1798 // Offset the ime to avoid overlapping with the nav bar
1799 mExperiments.offsetWindowFramesForNavBar(mNavigationBarPosition, win);
1800 // EXPERIMENT END
1801
1802 // IM dock windows always go to the bottom of the screen.
1803 attrs.gravity = Gravity.BOTTOM;
1804 } else if (type == TYPE_VOICE_INTERACTION) {
1805 of.set(displayFrames.mUnrestricted);
1806 df.set(displayFrames.mUnrestricted);
1807 pf.set(displayFrames.mUnrestricted);
1808 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1809 cf.set(displayFrames.mDock);
1810 } else {
1811 cf.set(displayFrames.mContent);
1812 }
1813 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1814 vf.set(displayFrames.mCurrent);
1815 } else {
1816 vf.set(cf);
1817 }
1818 } else if (type == TYPE_WALLPAPER) {
1819 layoutWallpaper(displayFrames, pf, df, of, cf);
1820 } else if (win == mStatusBar) {
1821 of.set(displayFrames.mUnrestricted);
1822 df.set(displayFrames.mUnrestricted);
1823 pf.set(displayFrames.mUnrestricted);
1824 cf.set(displayFrames.mStable);
1825 vf.set(displayFrames.mStable);
1826
1827 if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
1828 cf.bottom = displayFrames.mContent.bottom;
1829 } else {
1830 cf.bottom = displayFrames.mDock.bottom;
1831 vf.bottom = displayFrames.mContent.bottom;
1832 }
1833 } else {
1834 dcf.set(displayFrames.mSystem);
1835 final boolean inheritTranslucentDecor =
1836 (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
1837 final boolean isAppWindow =
1838 type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1839 final boolean topAtRest =
1840 win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
1841 if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
1842 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
1843 && (fl & FLAG_FULLSCREEN) == 0
1844 && (fl & FLAG_TRANSLUCENT_STATUS) == 0
1845 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1846 && (pfl & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) == 0) {
1847 // Ensure policy decor includes status bar
1848 dcf.top = displayFrames.mStable.top;
1849 }
1850 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
1851 && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
1852 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
1853 // Ensure policy decor includes navigation bar
1854 dcf.bottom = displayFrames.mStable.bottom;
1855 dcf.right = displayFrames.mStable.right;
1856 }
1857 }
1858
1859 if (layoutInScreen && layoutInsetDecor) {
1860 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1861 + "): IN_SCREEN, INSET_DECOR");
1862 // This is the case for a normal activity window: we want it to cover all of the
1863 // screen space, and it can take care of moving its contents to account for screen
1864 // decorations that intrude into that space.
1865 if (attached != null) {
1866 // If this window is attached to another, our display
1867 // frame is the same as the one we are attached to.
1868 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
1869 displayFrames);
1870 } else {
1871 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
1872 // Status bar panels are the only windows who can go on top of the status
1873 // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
1874 // have the same privileges as the status bar itself.
1875 //
1876 // However, they should still dodge the navigation bar if it exists.
1877
1878 pf.left = df.left = of.left = hasNavBar
1879 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
1880 pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
1881 pf.right = df.right = of.right = hasNavBar
1882 ? displayFrames.mRestricted.right
1883 : displayFrames.mUnrestricted.right;
1884 pf.bottom = df.bottom = of.bottom = hasNavBar
1885 ? displayFrames.mRestricted.bottom
1886 : displayFrames.mUnrestricted.bottom;
1887
1888 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
1889 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
1890 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
1891 // Asking to layout into the overscan region, so give it that pure
1892 // unrestricted area.
1893 of.set(displayFrames.mOverscan);
1894 df.set(displayFrames.mOverscan);
1895 pf.set(displayFrames.mOverscan);
1896 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
1897 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
1898 || type == TYPE_VOLUME_OVERLAY)) {
1899 // Asking for layout as if the nav bar is hidden, lets the application
1900 // extend into the unrestricted overscan screen area. We only do this for
1901 // application windows and certain system windows to ensure no window that
1902 // can be above the nav bar can do this.
1903 df.set(displayFrames.mOverscan);
1904 pf.set(displayFrames.mOverscan);
1905 // We need to tell the app about where the frame inside the overscan is, so
1906 // it can inset its content by that amount -- it didn't ask to actually
1907 // extend itself into the overscan region.
1908 of.set(displayFrames.mUnrestricted);
1909 } else {
1910 df.set(displayFrames.mRestrictedOverscan);
1911 pf.set(displayFrames.mRestrictedOverscan);
1912 // We need to tell the app about where the frame inside the overscan
1913 // is, so it can inset its content by that amount -- it didn't ask
1914 // to actually extend itself into the overscan region.
1915 of.set(displayFrames.mUnrestricted);
1916 }
1917
1918 if ((fl & FLAG_FULLSCREEN) == 0) {
1919 if (win.isVoiceInteraction()) {
1920 cf.set(displayFrames.mVoiceContent);
1921 } else {
Jorim Jaggi648e5882019-01-24 13:24:02 +01001922 // IME Insets are handled on the client for ADJUST_RESIZE in the new
1923 // insets world
1924 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
1925 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001926 cf.set(displayFrames.mDock);
1927 } else {
1928 cf.set(displayFrames.mContent);
1929 }
1930 }
1931 } else {
1932 // Full screen windows are always given a layout that is as if the status
1933 // bar and other transient decors are gone. This is to avoid bad states when
1934 // moving from a window that is not hiding the status bar to one that is.
1935 cf.set(displayFrames.mRestricted);
1936 }
1937 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
1938 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1939 vf.set(displayFrames.mCurrent);
1940 } else {
1941 vf.set(cf);
1942 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08001943 }
1944 } else if (layoutInScreen || (sysUiFl
1945 & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
1946 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
1947 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1948 + "): IN_SCREEN");
1949 // A window that has requested to fill the entire screen just
1950 // gets everything, period.
1951 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
1952 cf.set(displayFrames.mUnrestricted);
1953 of.set(displayFrames.mUnrestricted);
1954 df.set(displayFrames.mUnrestricted);
1955 pf.set(displayFrames.mUnrestricted);
1956 if (hasNavBar) {
1957 pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
1958 pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
1959 pf.bottom = df.bottom = of.bottom = cf.bottom =
1960 displayFrames.mRestricted.bottom;
1961 }
1962 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
1963 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
1964 // The navigation bar has Real Ultimate Power.
1965 of.set(displayFrames.mUnrestricted);
1966 df.set(displayFrames.mUnrestricted);
1967 pf.set(displayFrames.mUnrestricted);
1968 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
1969 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
1970 && ((fl & FLAG_FULLSCREEN) != 0)) {
1971 // Fullscreen secure system overlays get what they ask for. Screenshot region
1972 // selection overlay should also expand to full screen.
1973 cf.set(displayFrames.mOverscan);
1974 of.set(displayFrames.mOverscan);
1975 df.set(displayFrames.mOverscan);
1976 pf.set(displayFrames.mOverscan);
1977 } else if (type == TYPE_BOOT_PROGRESS) {
1978 // Boot progress screen always covers entire display.
1979 cf.set(displayFrames.mOverscan);
1980 of.set(displayFrames.mOverscan);
1981 df.set(displayFrames.mOverscan);
1982 pf.set(displayFrames.mOverscan);
1983 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
1984 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
1985 // Asking to layout into the overscan region, so give it that pure unrestricted
1986 // area.
1987 cf.set(displayFrames.mOverscan);
1988 of.set(displayFrames.mOverscan);
1989 df.set(displayFrames.mOverscan);
1990 pf.set(displayFrames.mOverscan);
1991 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
1992 && (type == TYPE_STATUS_BAR
1993 || type == TYPE_TOAST
1994 || type == TYPE_DOCK_DIVIDER
1995 || type == TYPE_VOICE_INTERACTION_STARTING
1996 || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
1997 // Asking for layout as if the nav bar is hidden, lets the
1998 // application extend into the unrestricted screen area. We
1999 // only do this for application windows (or toasts) to ensure no window that
2000 // can be above the nav bar can do this.
2001 // XXX This assumes that an app asking for this will also
2002 // ask for layout in only content. We can't currently figure out
2003 // what the screen would be if only laying out to hide the nav bar.
2004 cf.set(displayFrames.mUnrestricted);
2005 of.set(displayFrames.mUnrestricted);
2006 df.set(displayFrames.mUnrestricted);
2007 pf.set(displayFrames.mUnrestricted);
2008 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
2009 of.set(displayFrames.mRestricted);
2010 df.set(displayFrames.mRestricted);
2011 pf.set(displayFrames.mRestricted);
Jorim Jaggi648e5882019-01-24 13:24:02 +01002012
2013 // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2014 // world
2015 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2016 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002017 cf.set(displayFrames.mDock);
2018 } else {
2019 cf.set(displayFrames.mContent);
2020 }
2021 } else {
2022 cf.set(displayFrames.mRestricted);
2023 of.set(displayFrames.mRestricted);
2024 df.set(displayFrames.mRestricted);
2025 pf.set(displayFrames.mRestricted);
2026 }
2027
2028 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2029
2030 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2031 vf.set(displayFrames.mCurrent);
2032 } else {
2033 vf.set(cf);
2034 }
2035 } else if (attached != null) {
2036 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2037 + "): attached to " + attached);
2038 // A child window should be placed inside of the same visible
2039 // frame that its parent had.
2040 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
2041 displayFrames);
2042 } else {
2043 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2044 + "): normal window");
2045 // Otherwise, a normal window must be placed inside the content
2046 // of all screen decorations.
2047 if (type == TYPE_STATUS_BAR_PANEL) {
2048 // Status bar panels can go on
2049 // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2050 // permission, so they have the same privileges as the status bar itself.
2051 cf.set(displayFrames.mRestricted);
2052 of.set(displayFrames.mRestricted);
2053 df.set(displayFrames.mRestricted);
2054 pf.set(displayFrames.mRestricted);
Vishnu Nair15382f12019-01-23 14:01:35 -08002055 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT
2056 || type == TYPE_APPLICATION_OVERLAY) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002057 // These dialogs are stable to interim decor changes.
2058 cf.set(displayFrames.mStable);
2059 of.set(displayFrames.mStable);
2060 df.set(displayFrames.mStable);
2061 pf.set(displayFrames.mStable);
2062 } else {
2063 pf.set(displayFrames.mContent);
2064 if (win.isVoiceInteraction()) {
2065 cf.set(displayFrames.mVoiceContent);
2066 of.set(displayFrames.mVoiceContent);
2067 df.set(displayFrames.mVoiceContent);
2068 } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2069 cf.set(displayFrames.mDock);
2070 of.set(displayFrames.mDock);
2071 df.set(displayFrames.mDock);
2072 } else {
2073 cf.set(displayFrames.mContent);
2074 of.set(displayFrames.mContent);
2075 df.set(displayFrames.mContent);
2076 }
2077 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2078 vf.set(displayFrames.mCurrent);
2079 } else {
2080 vf.set(cf);
2081 }
2082 }
2083 }
2084 }
2085
2086 final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2087 final boolean attachedInParent = attached != null && !layoutInScreen;
2088 final boolean requestedHideNavigation =
2089 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
2090
2091 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2092 // cropped / shifted to the displayFrame in WindowState.
2093 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2094 && type != TYPE_BASE_APPLICATION;
2095
2096 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2097 // the cutout safe zone.
2098 if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
2099 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2100 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2101 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2102 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2103 // At the top we have the status bar, so apps that are
2104 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2105 // already expect that there's an inset there and we don't need to exclude
2106 // the window from that area.
2107 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2108 }
2109 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2110 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2111 // Same for the navigation bar.
2112 switch (mNavigationBarPosition) {
2113 case NAV_BAR_BOTTOM:
2114 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2115 break;
2116 case NAV_BAR_RIGHT:
2117 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2118 break;
2119 case NAV_BAR_LEFT:
2120 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2121 break;
2122 }
2123 }
2124 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2125 // The IME can always extend under the bottom cutout if the navbar is there.
2126 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2127 }
2128 // Windows that are attached to a parent and laid out in said parent already avoid
2129 // the cutout according to that parent and don't need to be further constrained.
2130 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2131 // They will later be cropped or shifted using the displayFrame in WindowState,
2132 // which prevents overlap with the DisplayCutout.
2133 if (!attachedInParent && !floatingInScreenWindow) {
2134 sTmpRect.set(pf);
2135 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2136 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2137 }
2138 // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2139 // cutout.
2140 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2141 }
2142
2143 // Content should never appear in the cutout.
2144 cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2145
2146 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2147 // Also, we don't allow windows in multi-window mode to extend out of the screen.
2148 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
2149 && !win.isInMultiWindowMode()) {
2150 df.left = df.top = -10000;
2151 df.right = df.bottom = 10000;
2152 if (type != TYPE_WALLPAPER) {
2153 of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
2154 of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
2155 }
2156 }
2157
2158 // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
2159 // need to provide information to the clients that want to pretend that you can draw there.
2160 // We only want to apply outsets to certain types of windows. For example, we never want to
2161 // apply the outsets to floating dialogs, because they wouldn't make sense there.
2162 final boolean useOutsets = shouldUseOutsets(attrs, fl);
2163 if (isDefaultDisplay && useOutsets) {
2164 final Rect osf = windowFrames.mOutsetFrame;
2165 osf.set(cf.left, cf.top, cf.right, cf.bottom);
2166 windowFrames.setHasOutsets(true);
2167 int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
2168 if (outset > 0) {
2169 int rotation = displayFrames.mRotation;
2170 if (rotation == Surface.ROTATION_0) {
2171 osf.bottom += outset;
2172 } else if (rotation == Surface.ROTATION_90) {
2173 osf.right += outset;
2174 } else if (rotation == Surface.ROTATION_180) {
2175 osf.top -= outset;
2176 } else if (rotation == Surface.ROTATION_270) {
2177 osf.left -= outset;
2178 }
2179 if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
2180 + " with rotation " + rotation + ", result: " + osf);
2181 }
2182 }
2183
2184 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2185 + ": sim=#" + Integer.toHexString(sim)
2186 + " attach=" + attached + " type=" + type
2187 + String.format(" flags=0x%08x", fl)
2188 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
2189 + " of=" + of.toShortString()
2190 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2191 + " dcf=" + dcf.toShortString()
2192 + " sf=" + sf.toShortString()
2193 + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
2194
2195 if (!sTmpLastParentFrame.equals(pf)) {
2196 windowFrames.setContentChanged(true);
2197 }
2198
2199 win.computeFrameLw();
2200 // Dock windows carve out the bottom of the screen, so normal windows
2201 // can't appear underneath them.
2202 if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2203 && !win.getGivenInsetsPendingLw()) {
2204 offsetInputMethodWindowLw(win, displayFrames);
2205 }
2206 if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2207 && !win.getGivenInsetsPendingLw()) {
2208 offsetVoiceInputWindowLw(win, displayFrames);
2209 }
2210 }
2211
2212 private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
2213 // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
2214 df.set(displayFrames.mOverscan);
2215 pf.set(displayFrames.mOverscan);
2216 cf.set(displayFrames.mUnrestricted);
2217 of.set(displayFrames.mUnrestricted);
2218 }
2219
2220 private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
2221 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2222 top += win.getGivenContentInsetsLw().top;
2223 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
2224 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2225 top = win.getVisibleFrameLw().top;
2226 top += win.getGivenVisibleInsetsLw().top;
2227 displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2228 if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2229 + displayFrames.mDock.bottom + " mContentBottom="
2230 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2231 }
2232
2233 private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2234 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2235 top += win.getGivenContentInsetsLw().top;
2236 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2237 }
2238
2239 /**
2240 * Called following layout of all windows before each window has policy applied.
2241 */
2242 public void beginPostLayoutPolicyLw() {
2243 mTopFullscreenOpaqueWindowState = null;
2244 mTopFullscreenOpaqueOrDimmingWindowState = null;
2245 mTopDockedOpaqueWindowState = null;
2246 mTopDockedOpaqueOrDimmingWindowState = null;
2247 mForceStatusBar = false;
2248 mForceStatusBarFromKeyguard = false;
2249 mForceStatusBarTransparent = false;
2250 mForcingShowNavBar = false;
2251 mForcingShowNavBarLayer = -1;
2252
2253 mAllowLockscreenWhenOn = false;
2254 mShowingDream = false;
2255 mWindowSleepTokenNeeded = false;
2256 }
2257
2258 /**
2259 * Called following layout of all window to apply policy to each window.
2260 *
2261 * @param win The window being positioned.
2262 * @param attrs The LayoutParams of the window.
2263 * @param attached For sub-windows, the window it is attached to. Otherwise null.
2264 */
2265 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2266 WindowState attached, WindowState imeTarget) {
2267 final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2268 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2269 mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2270 final int fl = PolicyControl.getWindowFlags(win, attrs);
2271 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2272 && attrs.type == TYPE_INPUT_METHOD) {
2273 mForcingShowNavBar = true;
2274 mForcingShowNavBarLayer = win.getSurfaceLayer();
2275 }
2276 if (attrs.type == TYPE_STATUS_BAR) {
2277 if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
2278 mForceStatusBarFromKeyguard = true;
2279 }
2280 if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
2281 mForceStatusBarTransparent = true;
2282 }
2283 }
2284
2285 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2286 && attrs.type < FIRST_SYSTEM_WINDOW;
2287 final int windowingMode = win.getWindowingMode();
2288 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2289 windowingMode == WINDOWING_MODE_FULLSCREEN
2290 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2291 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2292 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2293 mForceStatusBar = true;
2294 }
2295 if (attrs.type == TYPE_DREAM) {
2296 // If the lockscreen was showing when the dream started then wait
2297 // for the dream to draw before hiding the lockscreen.
2298 if (!mDreamingLockscreen
2299 || (win.isVisibleLw() && win.hasDrawnLw())) {
2300 mShowingDream = true;
2301 appWindow = true;
2302 }
2303 }
2304
2305 // For app windows that are not attached, we decide if all windows in the app they
2306 // represent should be hidden or if we should hide the lockscreen. For attached app
2307 // windows we defer the decision to the window it is attached to.
2308 if (appWindow && attached == null) {
2309 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2310 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2311 mTopFullscreenOpaqueWindowState = win;
2312 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2313 mTopFullscreenOpaqueOrDimmingWindowState = win;
2314 }
2315 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2316 mAllowLockscreenWhenOn = true;
2317 }
2318 }
2319 }
2320 }
2321
2322 // Voice interaction overrides both top fullscreen and top docked.
2323 if (affectsSystemUi && win.getAttrs().type == TYPE_VOICE_INTERACTION) {
2324 if (mTopFullscreenOpaqueWindowState == null) {
2325 mTopFullscreenOpaqueWindowState = win;
2326 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2327 mTopFullscreenOpaqueOrDimmingWindowState = win;
2328 }
2329 }
2330 if (mTopDockedOpaqueWindowState == null) {
2331 mTopDockedOpaqueWindowState = win;
2332 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2333 mTopDockedOpaqueOrDimmingWindowState = win;
2334 }
2335 }
2336 }
2337
2338 // Keep track of the window if it's dimming but not necessarily fullscreen.
2339 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2340 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2341 mTopFullscreenOpaqueOrDimmingWindowState = win;
2342 }
2343
2344 // We need to keep track of the top "fullscreen" opaque window for the docked stack
2345 // separately, because both the "real fullscreen" opaque window and the one for the docked
2346 // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2347 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2348 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2349 mTopDockedOpaqueWindowState = win;
2350 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2351 mTopDockedOpaqueOrDimmingWindowState = win;
2352 }
2353 }
2354
2355 // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2356 // docked stack.
2357 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2358 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2359 mTopDockedOpaqueOrDimmingWindowState = win;
2360 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002361 }
2362
2363 /**
2364 * Called following layout of all windows and after policy has been applied
2365 * to each window. If in this function you do
2366 * something that may have modified the animation state of another window,
2367 * be sure to return non-zero in order to perform another pass through layout.
2368 *
2369 * @return Return any bit set of
2370 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2371 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2372 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2373 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2374 */
2375 public int finishPostLayoutPolicyLw() {
2376 int changes = 0;
2377 boolean topIsFullscreen = false;
2378
2379 // If we are not currently showing a dream then remember the current
2380 // lockscreen state. We will use this to determine whether the dream
2381 // started while the lockscreen was showing and remember this state
2382 // while the dream is showing.
2383 if (!mShowingDream) {
2384 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2385 if (mDreamingSleepTokenNeeded) {
2386 mDreamingSleepTokenNeeded = false;
2387 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2388 }
2389 } else {
2390 if (!mDreamingSleepTokenNeeded) {
2391 mDreamingSleepTokenNeeded = true;
2392 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2393 }
2394 }
2395
2396 if (mStatusBar != null) {
2397 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
2398 + " forcefkg=" + mForceStatusBarFromKeyguard
2399 + " top=" + mTopFullscreenOpaqueWindowState);
2400 boolean shouldBeTransparent = mForceStatusBarTransparent
2401 && !mForceStatusBar
2402 && !mForceStatusBarFromKeyguard;
2403 if (!shouldBeTransparent) {
2404 mStatusBarController.setShowTransparent(false /* transparent */);
2405 } else if (!mStatusBar.isVisibleLw()) {
2406 mStatusBarController.setShowTransparent(true /* transparent */);
2407 }
2408
2409 boolean statusBarForcesShowingNavigation =
2410 (mStatusBar.getAttrs().privateFlags
2411 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
2412 boolean topAppHidesStatusBar = topAppHidesStatusBar();
2413 if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
2414 || statusBarForcesShowingNavigation) {
2415 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2416 if (mStatusBarController.setBarShowingLw(true)) {
2417 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2418 }
2419 // Maintain fullscreen layout until incoming animation is complete.
2420 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
2421 // Transient status bar is not allowed if status bar is on lockscreen or status bar
2422 // is expecting the navigation keys from the user.
2423 if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
2424 && mStatusBarController.isTransientShowing()) {
2425 mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2426 mLastSystemUiFlags, mLastSystemUiFlags);
2427 }
2428 } else if (mTopFullscreenOpaqueWindowState != null) {
2429 topIsFullscreen = topAppHidesStatusBar;
2430 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2431 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2432 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
2433 // case though.
2434 if (mStatusBarController.isTransientShowing()) {
2435 if (mStatusBarController.setBarShowingLw(true)) {
2436 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2437 }
2438 } else if (topIsFullscreen
2439 && !mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM)
2440 && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2441 if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2442 if (mStatusBarController.setBarShowingLw(false)) {
2443 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2444 } else {
2445 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2446 }
2447 } else {
2448 if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2449 if (mStatusBarController.setBarShowingLw(true)) {
2450 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2451 }
2452 topAppHidesStatusBar = false;
2453 }
2454 }
2455 mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2456 }
2457
2458 if (mTopIsFullscreen != topIsFullscreen) {
2459 if (!topIsFullscreen) {
2460 // Force another layout when status bar becomes fully shown.
2461 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2462 }
2463 mTopIsFullscreen = topIsFullscreen;
2464 }
2465
2466 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2467 // If the navigation bar has been hidden or shown, we need to do another
2468 // layout pass to update that window.
2469 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2470 }
2471
2472 if (mShowingDream != mLastShowingDream) {
2473 mLastShowingDream = mShowingDream;
2474 mService.notifyShowingDreamChanged();
2475 }
2476
2477 updateWindowSleepToken();
2478
2479 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2480 return changes;
2481 }
2482
2483 private void updateWindowSleepToken() {
2484 if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2485 mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2486 mHandler.post(mAcquireSleepTokenRunnable);
2487 } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2488 mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2489 mHandler.post(mReleaseSleepTokenRunnable);
2490 }
2491 mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2492 }
2493
2494 /**
2495 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2496 * window.
2497 */
2498 private boolean topAppHidesStatusBar() {
2499 if (mTopFullscreenOpaqueWindowState == null) {
2500 return false;
2501 }
2502 final int fl = PolicyControl.getWindowFlags(null,
2503 mTopFullscreenOpaqueWindowState.getAttrs());
2504 if (localLOGV) {
2505 Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2506 Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2507 + " lp.flags=0x" + Integer.toHexString(fl));
2508 }
2509 return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2510 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2511 }
2512
2513 /**
2514 * Called when the resource overlays change.
2515 */
2516 public void onOverlayChangedLw() {
2517 onConfigurationChanged();
2518 }
2519
2520 /**
2521 * Called when the configuration has changed, and it's safe to load new values from resources.
2522 */
2523 public void onConfigurationChanged() {
2524 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2525
2526 final Context uiContext = getSystemUiContext();
2527 final Resources res = uiContext.getResources();
2528 final int portraitRotation = displayRotation.getPortraitRotation();
2529 final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2530 final int landscapeRotation = displayRotation.getLandscapeRotation();
2531 final int seascapeRotation = displayRotation.getSeascapeRotation();
2532
Louis Changfc64c832018-12-04 11:38:26 +08002533 if (hasStatusBar()) {
2534 mStatusBarHeightForRotation[portraitRotation] =
2535 mStatusBarHeightForRotation[upsideDownRotation] =
2536 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2537 mStatusBarHeightForRotation[landscapeRotation] =
2538 mStatusBarHeightForRotation[seascapeRotation] =
2539 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2540 } else {
2541 mStatusBarHeightForRotation[portraitRotation] =
2542 mStatusBarHeightForRotation[upsideDownRotation] =
2543 mStatusBarHeightForRotation[landscapeRotation] =
2544 mStatusBarHeightForRotation[seascapeRotation] = 0;
2545 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002546
2547 // Height of the navigation bar when presented horizontally at bottom
2548 mNavigationBarHeightForRotationDefault[portraitRotation] =
2549 mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2550 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2551 mNavigationBarHeightForRotationDefault[landscapeRotation] =
2552 mNavigationBarHeightForRotationDefault[seascapeRotation] =
2553 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2554
2555 // Width of the navigation bar when presented vertically along one side
2556 mNavigationBarWidthForRotationDefault[portraitRotation] =
2557 mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2558 mNavigationBarWidthForRotationDefault[landscapeRotation] =
2559 mNavigationBarWidthForRotationDefault[seascapeRotation] =
2560 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2561
2562 if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2563 // Height of the navigation bar when presented horizontally at bottom
2564 mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2565 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2566 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2567 mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2568 mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2569 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2570
2571 // Width of the navigation bar when presented vertically along one side
2572 mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2573 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2574 mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2575 mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2576 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2577 }
2578
2579 // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
2580 mExperiments.onConfigurationChanged(uiContext);
2581 // EXPERIMENT END
2582 }
2583
2584 @VisibleForTesting
2585 Context getSystemUiContext() {
2586 final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
2587 return mDisplayContent.isDefaultDisplay
2588 ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay());
2589 }
2590
2591 private int getNavigationBarWidth(int rotation, int uiMode) {
2592 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2593 return mNavigationBarWidthForRotationInCarMode[rotation];
2594 } else {
2595 return mNavigationBarWidthForRotationDefault[rotation];
2596 }
2597 }
2598
Charles Chen3dedec32019-01-24 22:19:37 +08002599 void notifyDisplayReady() {
wilsonshih643bf132019-02-27 12:49:19 +08002600 mHandler.post(() -> {
2601 final int displayId = getDisplayId();
2602 getStatusBarManagerInternal().onDisplayReady(displayId);
2603 LocalServices.getService(WallpaperManagerInternal.class).onDisplayReady(displayId);
2604 });
Charles Chen3dedec32019-01-24 22:19:37 +08002605 }
2606
Tiger Huang7c610aa2018-10-27 00:01:01 +08002607 /**
2608 * Return the display width available after excluding any screen
2609 * decorations that could never be removed in Honeycomb. That is, system bar or
2610 * button bar.
2611 */
2612 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2613 DisplayCutout displayCutout) {
2614 int width = fullWidth;
2615 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002616 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2617 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002618 width -= getNavigationBarWidth(rotation, uiMode);
2619 }
2620 }
2621 if (displayCutout != null) {
2622 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2623 }
2624 return width;
2625 }
2626
2627 private int getNavigationBarHeight(int rotation, int uiMode) {
2628 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2629 return mNavigationBarHeightForRotationInCarMode[rotation];
2630 } else {
2631 return mNavigationBarHeightForRotationDefault[rotation];
2632 }
2633 }
2634
2635 /**
2636 * Return the display height available after excluding any screen
2637 * decorations that could never be removed in Honeycomb. That is, system bar or
2638 * button bar.
2639 */
2640 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2641 DisplayCutout displayCutout) {
2642 int height = fullHeight;
2643 if (hasNavigationBar()) {
Tiger Huang3d2b8982019-01-29 22:56:48 +08002644 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2645 if (navBarPosition == NAV_BAR_BOTTOM) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08002646 height -= getNavigationBarHeight(rotation, uiMode);
2647 }
2648 }
2649 if (displayCutout != null) {
2650 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2651 }
2652 return height;
2653 }
2654
2655 /**
2656 * Return the available screen width that we should report for the
2657 * configuration. This must be no larger than
2658 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2659 * than that to account for more transient decoration like a status bar.
2660 */
2661 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2662 DisplayCutout displayCutout) {
2663 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2664 }
2665
2666 /**
2667 * Return the available screen height that we should report for the
2668 * configuration. This must be no larger than
2669 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2670 * than that to account for more transient decoration like a status bar.
2671 */
2672 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2673 DisplayCutout displayCutout) {
2674 // There is a separate status bar at the top of the display. We don't count that as part
2675 // of the fixed decor, since it can hide; however, for purposes of configurations,
2676 // we do want to exclude it since applications can't generally use that part
2677 // of the screen.
2678 int statusBarHeight = mStatusBarHeightForRotation[rotation];
2679 if (displayCutout != null) {
2680 // If there is a cutout, it may already have accounted for some part of the status
2681 // bar height.
2682 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2683 }
2684 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2685 - statusBarHeight;
2686 }
2687
2688 boolean isShowingDreamLw() {
2689 return mShowingDream;
2690 }
2691
2692 /**
2693 * Calculates the stable insets without running a layout.
2694 *
2695 * @param displayRotation the current display rotation
2696 * @param displayWidth the current display width
2697 * @param displayHeight the current display height
2698 * @param displayCutout the current display cutout
2699 * @param outInsets the insets to return
2700 */
2701 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2702 DisplayCutout displayCutout, Rect outInsets) {
2703 outInsets.setEmpty();
2704
2705 // Navigation bar and status bar.
2706 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
2707 outInsets.top = Math.max(outInsets.top, mStatusBarHeightForRotation[displayRotation]);
2708 }
2709
2710 /**
2711 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2712 * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2713 *
2714 * @param displayRotation the current display rotation
2715 * @param displayWidth the current display width
2716 * @param displayHeight the current display height
2717 * @param displayCutout the current display cutout
2718 * @param outInsets the insets to return
2719 */
2720 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2721 DisplayCutout displayCutout, Rect outInsets) {
2722 outInsets.setEmpty();
2723
2724 // Only navigation bar
2725 if (hasNavigationBar()) {
2726 final int uiMode = mService.mPolicy.getUiMode();
2727 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2728 if (position == NAV_BAR_BOTTOM) {
2729 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2730 } else if (position == NAV_BAR_RIGHT) {
2731 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2732 } else if (position == NAV_BAR_LEFT) {
2733 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2734 }
2735 }
2736
2737 if (displayCutout != null) {
2738 outInsets.left += displayCutout.getSafeInsetLeft();
2739 outInsets.top += displayCutout.getSafeInsetTop();
2740 outInsets.right += displayCutout.getSafeInsetRight();
2741 outInsets.bottom += displayCutout.getSafeInsetBottom();
2742 }
2743 }
2744
Issei Suzukia5dbf522019-02-01 17:58:15 +01002745 /**
2746 * @see IWindowManager#setForwardedInsets
2747 */
2748 public void setForwardedInsets(@NonNull Insets forwardedInsets) {
2749 mForwardedInsets = forwardedInsets;
2750 }
2751
2752 @NonNull
2753 public Insets getForwardedInsets() {
2754 return mForwardedInsets;
2755 }
2756
Tiger Huang7c610aa2018-10-27 00:01:01 +08002757 @NavigationBarPosition
2758 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
2759 if (navigationBarCanMove() && displayWidth > displayHeight) {
2760 if (displayRotation == Surface.ROTATION_270) {
2761 return NAV_BAR_LEFT;
2762 } else if (displayRotation == Surface.ROTATION_90) {
2763 return NAV_BAR_RIGHT;
2764 }
2765 }
2766 return NAV_BAR_BOTTOM;
2767 }
2768
2769 /**
2770 * @return The side of the screen where navigation bar is positioned.
2771 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
2772 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
2773 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
2774 */
2775 @NavigationBarPosition
2776 public int getNavBarPosition() {
2777 return mNavigationBarPosition;
2778 }
2779
2780 /**
2781 * A new window has been focused.
2782 */
2783 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
2784 mFocusedWindow = newFocus;
2785 mLastFocusedWindow = lastFocus;
Issei Suzuki9f840c72018-12-07 15:09:30 -08002786 if (mDisplayContent.isDefaultDisplay) {
2787 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
2788 }
Tiger Huang7c610aa2018-10-27 00:01:01 +08002789 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2790 // If the navigation bar has been hidden or shown, we need to do another
2791 // layout pass to update that window.
2792 return FINISH_LAYOUT_REDO_LAYOUT;
2793 }
2794 return 0;
2795 }
2796
2797 /**
2798 * Return true if it is okay to perform animations for an app transition
2799 * that is about to occur. You may return false for this if, for example,
2800 * the dream window is currently displayed so the switch should happen
2801 * immediately.
2802 */
2803 public boolean allowAppAnimationsLw() {
2804 return !mShowingDream;
2805 }
2806
2807 private void updateDreamingSleepToken(boolean acquire) {
2808 if (acquire) {
2809 final int displayId = getDisplayId();
2810 if (mDreamingSleepToken == null) {
2811 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
2812 "DreamOnDisplay" + displayId, displayId);
2813 }
2814 } else {
2815 if (mDreamingSleepToken != null) {
2816 mDreamingSleepToken.release();
2817 mDreamingSleepToken = null;
2818 }
2819 }
2820 }
2821
2822 private void requestTransientBars(WindowState swipeTarget) {
2823 synchronized (mLock) {
2824 if (!mService.mPolicy.isUserSetupComplete()) {
2825 // Swipe-up for navigation bar is disabled during setup
2826 return;
2827 }
2828 boolean sb = mStatusBarController.checkShowTransientBarLw();
2829 boolean nb = mNavigationBarController.checkShowTransientBarLw()
2830 && !isNavBarEmpty(mLastSystemUiFlags);
2831 if (sb || nb) {
2832 // Don't show status bar when swiping on already visible navigation bar
2833 if (!nb && swipeTarget == mNavigationBar) {
2834 if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
2835 return;
2836 }
2837 if (sb) mStatusBarController.showTransient();
2838 if (nb) mNavigationBarController.showTransient();
2839 mImmersiveModeConfirmation.confirmCurrentPrompt();
2840 updateSystemUiVisibilityLw();
2841 }
2842 }
2843 }
2844
2845 private void disposeInputConsumer(InputConsumer inputConsumer) {
2846 if (inputConsumer != null) {
2847 inputConsumer.dismiss();
2848 }
2849 }
2850
2851 private boolean isStatusBarKeyguard() {
2852 return mStatusBar != null
2853 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
2854 }
2855
2856 private boolean isKeyguardOccluded() {
2857 // TODO (b/113840485): Handle per display keyguard.
2858 return mService.mPolicy.isKeyguardOccluded();
2859 }
2860
2861 void resetSystemUiVisibilityLw() {
2862 mLastSystemUiFlags = 0;
2863 updateSystemUiVisibilityLw();
2864 }
2865
2866 private int updateSystemUiVisibilityLw() {
2867 // If there is no window focused, there will be nobody to handle the events
2868 // anyway, so just hang on in whatever state we're in until things settle down.
2869 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
2870 : mTopFullscreenOpaqueWindowState;
2871 if (winCandidate == null) {
2872 return 0;
2873 }
2874
2875 // The immersive mode confirmation should never affect the system bar visibility, otherwise
2876 // it will unhide the navigation bar and hide itself.
2877 if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
2878
2879 // The immersive mode confirmation took the focus from mLastFocusedWindow which was
2880 // controlling the system ui visibility. So if mLastFocusedWindow can still receive
2881 // keys, we let it keep controlling the visibility.
2882 final boolean lastFocusCanReceiveKeys =
2883 (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
2884 winCandidate = isStatusBarKeyguard() ? mStatusBar
2885 : lastFocusCanReceiveKeys ? mLastFocusedWindow
2886 : mTopFullscreenOpaqueWindowState;
2887 if (winCandidate == null) {
2888 return 0;
2889 }
2890 }
2891 final WindowState win = winCandidate;
2892 if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) {
2893 // We are updating at a point where the keyguard has gotten
2894 // focus, but we were last in a state where the top window is
2895 // hiding it. This is probably because the keyguard as been
2896 // shown while the top window was displayed, so we want to ignore
2897 // it here because this is just a very transient change and it
2898 // will quickly lose focus once it correctly gets hidden.
2899 return 0;
2900 }
2901
Jorim Jaggib6030952018-10-23 18:31:52 +02002902 mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(
2903 mTopFullscreenOpaqueWindowState);
2904
Tiger Huang7c610aa2018-10-27 00:01:01 +08002905 int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
2906 & ~mResettingSystemUiFlags
2907 & ~mForceClearedSystemUiFlags;
2908 if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
2909 tmpVisibility
2910 &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
2911 }
2912
2913 final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
2914 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
2915 final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
2916 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
2917 mService.getStackBounds(
2918 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
2919 mService.getStackBounds(
2920 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
2921 final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
2922 final int diff = visibility ^ mLastSystemUiFlags;
2923 final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
2924 final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
2925 final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
2926 if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
2927 && mFocusedApp == win.getAppToken()
2928 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
2929 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
2930 return 0;
2931 }
2932 mLastSystemUiFlags = visibility;
2933 mLastFullscreenStackSysUiFlags = fullscreenVisibility;
2934 mLastDockedStackSysUiFlags = dockedVisibility;
2935 mLastFocusNeedsMenu = needsMenu;
2936 mFocusedApp = win.getAppToken();
2937 final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
2938 final Rect dockedStackBounds = new Rect(mDockedStackBounds);
2939 mHandler.post(() -> {
2940 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
2941 if (statusBar != null) {
2942 final int displayId = getDisplayId();
2943 statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility,
2944 dockedVisibility, 0xffffffff, fullscreenStackBounds,
2945 dockedStackBounds, win.toString());
2946 statusBar.topAppWindowChanged(displayId, needsMenu);
2947 }
2948 });
2949 return diff;
2950 }
2951
2952 private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
2953 final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded();
2954 final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
2955 if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
2956 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
2957 // its light flag.
2958 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
2959 vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
2960 & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
2961 } else if (statusColorWin != null && statusColorWin.isDimming()) {
2962 // Otherwise if it's dimming, clear the light flag.
2963 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
2964 }
2965 return vis;
2966 }
2967
2968 @VisibleForTesting
2969 @Nullable
2970 static WindowState chooseNavigationColorWindowLw(WindowState opaque,
2971 WindowState opaqueOrDimming, WindowState imeWindow,
2972 @NavigationBarPosition int navBarPosition) {
2973 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
2974 // window can be navigation color window.
2975 final boolean imeWindowCanNavColorWindow = imeWindow != null
2976 && imeWindow.isVisibleLw()
2977 && navBarPosition == NAV_BAR_BOTTOM
2978 && (PolicyControl.getWindowFlags(imeWindow, null)
2979 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
2980
2981 if (opaque != null && opaqueOrDimming == opaque) {
2982 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
2983 // unless IME window is also eligible, since currently the IME window is always show
2984 // above the opaque fullscreen app window, regardless of the IME target window.
2985 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
2986 return imeWindowCanNavColorWindow ? imeWindow : opaque;
2987 }
2988
2989 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
2990 // No dimming window is involved. Determine the result only with the IME window.
2991 return imeWindowCanNavColorWindow ? imeWindow : null;
2992 }
2993
2994 if (!imeWindowCanNavColorWindow) {
2995 // No IME window is involved. Determine the result only with opaqueOrDimming.
2996 return opaqueOrDimming;
2997 }
2998
2999 // The IME window and the dimming window are competing. Check if the dimming window can be
3000 // IME target or not.
3001 if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3002 // The IME window is above the dimming window.
3003 return imeWindow;
3004 } else {
3005 // The dimming window is above the IME window.
3006 return opaqueOrDimming;
3007 }
3008 }
3009
3010 @VisibleForTesting
3011 static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3012 WindowState imeWindow, WindowState navColorWin) {
3013
3014 if (navColorWin != null) {
3015 if (navColorWin == imeWindow || navColorWin == opaque) {
3016 // Respect the light flag.
3017 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3018 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3019 & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3020 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3021 // Clear the light flag for dimming window.
3022 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3023 }
3024 }
3025 return vis;
3026 }
3027
3028 private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
3029 final boolean dockedStackVisible =
3030 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3031 final boolean freeformStackVisible =
3032 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3033 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3034
3035 // We need to force system bars when the docked stack is visible, when the freeform stack
3036 // is visible but also when we are resizing for the transitions when docked stack
3037 // visibility changes.
3038 mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
3039 final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
3040
3041 // apply translucent bar vis flags
3042 WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded()
3043 ? mStatusBar
3044 : mTopFullscreenOpaqueWindowState;
3045 vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3046 vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3047 final int dockedVis = mStatusBarController.applyTranslucentFlagLw(
3048 mTopDockedOpaqueWindowState, 0, 0);
3049
3050 final boolean fullscreenDrawsStatusBarBackground =
3051 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3052 final boolean dockedDrawsStatusBarBackground =
3053 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
3054
3055 // prevent status bar interaction from clearing certain flags
3056 int type = win.getAttrs().type;
3057 boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
3058 if (statusBarHasFocus && !isStatusBarKeyguard()) {
3059 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3060 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3061 | View.SYSTEM_UI_FLAG_IMMERSIVE
3062 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3063 | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3064 if (isKeyguardOccluded()) {
3065 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3066 }
3067 vis = (vis & ~flags) | (oldVis & flags);
3068 }
3069
3070 if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3071 vis |= View.STATUS_BAR_TRANSPARENT;
3072 vis &= ~View.STATUS_BAR_TRANSLUCENT;
3073 } else if ((!areTranslucentBarsAllowed() && fullscreenTransWin != mStatusBar)
3074 || forceOpaqueStatusBar) {
3075 vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3076 }
3077
3078 vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing);
3079
3080 // update status bar
3081 boolean immersiveSticky =
3082 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3083 final boolean hideStatusBarWM =
3084 mTopFullscreenOpaqueWindowState != null
3085 && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3086 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3087 final boolean hideStatusBarSysui =
3088 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3089 final boolean hideNavBarSysui =
3090 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3091
3092 final boolean transientStatusBarAllowed = mStatusBar != null
3093 && (statusBarHasFocus || (!mForceShowSystemBars
3094 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3095
3096 final boolean transientNavBarAllowed = mNavigationBar != null
3097 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3098
3099 final long now = SystemClock.uptimeMillis();
3100 final boolean pendingPanic = mPendingPanicGestureUptime != 0
3101 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3102 final DisplayPolicy defaultDisplayPolicy =
3103 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
3104 if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
3105 // TODO (b/111955725): Show keyguard presentation on all external displays
3106 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3107 // The user performed the panic gesture recently, we're about to hide the bars,
3108 // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3109 mPendingPanicGestureUptime = 0;
3110 mStatusBarController.showTransient();
3111 if (!isNavBarEmpty(vis)) {
3112 mNavigationBarController.showTransient();
3113 }
3114 }
3115
3116 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3117 && !transientStatusBarAllowed && hideStatusBarSysui;
3118 final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3119 && !transientNavBarAllowed;
3120 if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3121 // clear the clearable flags instead
3122 clearClearableFlagsLw();
3123 vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3124 }
3125
3126 final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3127 immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3128 final boolean navAllowedHidden = immersive || immersiveSticky;
3129
3130 if (hideNavBarSysui && !navAllowedHidden
3131 && mService.mPolicy.getWindowLayerLw(win)
3132 > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3133 // We can't hide the navbar from this window otherwise the input consumer would not get
3134 // the input events.
3135 vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3136 }
3137
3138 vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3139
3140 // update navigation bar
3141 boolean oldImmersiveMode = isImmersiveMode(oldVis);
3142 boolean newImmersiveMode = isImmersiveMode(vis);
3143 if (oldImmersiveMode != newImmersiveMode) {
3144 final String pkg = win.getOwningPackage();
3145 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3146 mService.mPolicy.isUserSetupComplete(),
3147 isNavBarEmpty(win.getSystemUiVisibility()));
3148 }
3149
3150 vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3151
3152 final WindowState navColorWin = chooseNavigationColorWindowLw(
3153 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3154 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3155 vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3156 mTopFullscreenOpaqueOrDimmingWindowState,
3157 mDisplayContent.mInputMethodWindow, navColorWin);
3158
3159 return vis;
3160 }
3161
3162 private boolean drawsStatusBarBackground(int vis, WindowState win) {
3163 if (!mStatusBarController.isTransparentAllowed(win)) {
3164 return false;
3165 }
3166 if (win == null) {
3167 return true;
3168 }
3169
3170 final boolean drawsSystemBars =
3171 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3172 final boolean forceDrawsSystemBars =
3173 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
3174
3175 return forceDrawsSystemBars || drawsSystemBars && (vis & View.STATUS_BAR_TRANSLUCENT) == 0;
3176 }
3177
3178 /**
3179 * @return the current visibility flags with the nav-bar opacity related flags toggled based
3180 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3181 */
3182 private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
3183 boolean freeformStackVisible, boolean isDockedDividerResizing) {
3184 if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
3185 if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
3186 visibility = setNavBarOpaqueFlag(visibility);
3187 }
3188 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3189 if (isDockedDividerResizing) {
3190 visibility = setNavBarOpaqueFlag(visibility);
3191 } else if (freeformStackVisible) {
3192 visibility = setNavBarTranslucentFlag(visibility);
3193 } else {
3194 visibility = setNavBarOpaqueFlag(visibility);
3195 }
3196 }
3197
3198 if (!areTranslucentBarsAllowed()) {
3199 visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3200 }
3201 return visibility;
3202 }
3203
3204 private int setNavBarOpaqueFlag(int visibility) {
3205 return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3206 }
3207
3208 private int setNavBarTranslucentFlag(int visibility) {
3209 visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3210 return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3211 }
3212
3213 private void clearClearableFlagsLw() {
3214 int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3215 if (newVal != mResettingSystemUiFlags) {
3216 mResettingSystemUiFlags = newVal;
3217 mDisplayContent.reevaluateStatusBarVisibility();
3218 }
3219 }
3220
3221 private boolean isImmersiveMode(int vis) {
3222 final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3223 return mNavigationBar != null
3224 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3225 && (vis & flags) != 0
3226 && canHideNavigationBar();
3227 }
3228
3229 /**
3230 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3231 */
3232 private boolean canHideNavigationBar() {
3233 return hasNavigationBar();
3234 }
3235
3236 private static boolean isNavBarEmpty(int systemUiFlags) {
3237 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3238 | View.STATUS_BAR_DISABLE_BACK
3239 | View.STATUS_BAR_DISABLE_RECENT);
3240
3241 return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3242 }
3243
3244 /**
3245 * @return whether the navigation or status bar can be made translucent
3246 *
3247 * This should return true unless touch exploration is not enabled or
3248 * R.boolean.config_enableTranslucentDecor is false.
3249 */
3250 private boolean areTranslucentBarsAllowed() {
3251 return mTranslucentDecorEnabled;
3252 }
3253
3254 boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
3255 int newRotation) {
3256 // For the upside down rotation we don't rotate seamlessly as the navigation
3257 // bar moves position.
3258 // Note most apps (using orientation:sensor or user as opposed to fullSensor)
3259 // will not enter the reverse portrait orientation, so actually the
3260 // orientation won't change at all.
3261 if (oldRotation == displayRotation.getUpsideDownRotation()
3262 || newRotation == displayRotation.getUpsideDownRotation()) {
3263 return false;
3264 }
3265 // If the navigation bar can't change sides, then it will
3266 // jump when we change orientations and we don't rotate
3267 // seamlessly.
3268 if (!navigationBarCanMove()) {
3269 return false;
3270 }
3271
3272 final WindowState w = mTopFullscreenOpaqueWindowState;
Riddle Hsuc90c4a52019-02-25 13:35:53 +08003273 if (w == null || w != mFocusedWindow) {
3274 return false;
3275 }
3276 // If the bounds of activity window is different from its parent, then reject to be seamless
3277 // because the window position may change after rotation that will look like a sudden jump.
3278 if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003279 return false;
3280 }
3281
3282 // We only enable seamless rotation if the top window has requested
3283 // it and is in the fullscreen opaque state. Seamless rotation
3284 // requires freezing various Surface states and won't work well
3285 // with animations, so we disable it in the animation case for now.
Riddle Hsuc90c4a52019-02-25 13:35:53 +08003286 if (!w.isAnimatingLw() && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003287 return true;
3288 }
3289 return false;
3290 }
3291
3292 private final Runnable mHiddenNavPanic = new Runnable() {
3293 @Override
3294 public void run() {
3295 synchronized (mLock) {
3296 if (!mService.mPolicy.isUserSetupComplete()) {
3297 // Swipe-up for navigation bar is disabled during setup
3298 return;
3299 }
3300 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3301 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3302 mNavigationBarController.showTransient();
3303 }
3304 }
3305 }
3306 };
3307
3308 void onPowerKeyDown(boolean isScreenOn) {
3309 // Detect user pressing the power button in panic when an application has
3310 // taken over the whole screen.
3311 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3312 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3313 isNavBarEmpty(mLastSystemUiFlags));
3314 if (panic) {
3315 mHandler.post(mHiddenNavPanic);
3316 }
3317 }
3318
3319 void onVrStateChangedLw(boolean enabled) {
3320 mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3321 }
3322
3323 /**
3324 * Called when the state of lock task mode changes. This should be used to disable immersive
3325 * mode confirmation.
3326 *
3327 * @param lockTaskState the new lock task mode state. One of
3328 * {@link ActivityManager#LOCK_TASK_MODE_NONE},
3329 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3330 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3331 */
3332 public void onLockTaskStateChangedLw(int lockTaskState) {
3333 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3334 }
3335
3336 /**
3337 * Request a screenshot be taken.
3338 *
3339 * @param screenshotType The type of screenshot, for example either
3340 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3341 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3342 */
3343 public void takeScreenshot(int screenshotType) {
3344 if (mScreenshotHelper != null) {
3345 mScreenshotHelper.takeScreenshot(screenshotType,
3346 mStatusBar != null && mStatusBar.isVisibleLw(),
3347 mNavigationBar != null && mNavigationBar.isVisibleLw(), mHandler);
3348 }
3349 }
3350
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003351 void dump(String prefix, PrintWriter pw) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08003352 pw.print(prefix); pw.print("DisplayPolicy");
3353 prefix += " ";
3354 pw.print(prefix);
3355 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3356 pw.print(" mDeskDockEnablesAccelerometer=");
3357 pw.println(mDeskDockEnablesAccelerometer);
3358 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3359 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3360 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3361 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3362 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3363 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3364 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3365 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3366 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3367 || mForceClearedSystemUiFlags != 0) {
3368 pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3369 pw.print(Integer.toHexString(mLastSystemUiFlags));
3370 pw.print(" mResettingSystemUiFlags=0x");
3371 pw.print(Integer.toHexString(mResettingSystemUiFlags));
3372 pw.print(" mForceClearedSystemUiFlags=0x");
3373 pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3374 }
3375 if (mLastFocusNeedsMenu) {
3376 pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu);
3377 }
3378 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3379 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3380 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3381 if (mStatusBar != null) {
3382 pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
3383 pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard());
3384 }
3385 if (mNavigationBar != null) {
3386 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
3387 }
3388 if (mFocusedWindow != null) {
3389 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3390 }
3391 if (mFocusedApp != null) {
3392 pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3393 }
3394 if (mTopFullscreenOpaqueWindowState != null) {
3395 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3396 pw.println(mTopFullscreenOpaqueWindowState);
3397 }
3398 if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3399 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3400 pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3401 }
3402 if (mForcingShowNavBar) {
3403 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3404 pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3405 pw.println(mForcingShowNavBarLayer);
3406 }
3407 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
3408 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
3409 pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
3410 pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
3411 mStatusBarController.dump(pw, prefix);
3412 mNavigationBarController.dump(pw, prefix);
3413
3414 pw.print(prefix); pw.println("Looper state:");
3415 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08003416 }
3417}