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