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