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