diff options
6 files changed, 98 insertions, 16 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index fe50a6484ba8..e56a82ffabd2 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -16,6 +16,7 @@ package android.view; +import android.Manifest.permission; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; @@ -1425,6 +1426,15 @@ public interface WindowManager extends ViewManager { public static final int PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY = 0x00100000; /** + * If this flag is set on the window, window manager will acquire a sleep token that puts + * all activities to sleep as long as this window is visible. When this flag is set, the + * window needs to occlude all activity windows. + * @hide + */ + @RequiresPermission(permission.DEVICE_POWER) + public static final int PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN = 0x00200000; + + /** * Control flags that are private to the platform. * @hide */ diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index d2eb7850b6ab..66506a18296b 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -16,6 +16,7 @@ package android.view; +import static android.Manifest.permission; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; @@ -486,11 +487,17 @@ public interface WindowManagerPolicy { /** * Returns true if the window owner can add internal system windows. - * That is, they have {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW}. + * That is, they have {@link permission#INTERNAL_SYSTEM_WINDOW}. */ default boolean canAddInternalSystemWindow() { return false; } + + /** + * Returns true if the window owner has the permission to acquire a sleep token when it's + * visible. That is, they have the permission {@link permission#DEVICE_POWER}. + */ + boolean canAcquireSleepToken(); } /** @@ -775,7 +782,7 @@ public interface WindowManagerPolicy { * @param type The type of window being assigned. * @param canAddInternalSystemWindow If the owner window associated with the type we are * evaluating can add internal system windows. I.e they have - * {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window + * {@link permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window * types {@link android.view.WindowManager.LayoutParams#isSystemAlertWindowType(int)} * can be assigned layers greater than the layer for * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} Else, their diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index eaa6a33b05d7..ed96b4115888 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -30,6 +30,7 @@ import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; import com.android.keyguard.R; import com.android.systemui.Dumpable; @@ -230,6 +231,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D applyModalFlag(state); applyBrightness(state); applyHasTopUi(state); + applySleepToken(state); if (mLp.copyFrom(mLpChanged) != 0) { mWindowManager.updateViewLayout(mStatusBarView, mLp); } @@ -273,6 +275,14 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D mHasTopUiChanged = isExpanded(state); } + private void applySleepToken(State state) { + if (state.dozing) { + mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN; + } else { + mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN; + } + } + public void setKeyguardShowing(boolean showing) { mCurrentState.keyguardShowing = showing; apply(mCurrentState); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 7fda2aacfca2..73a29ac75b71 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -26,8 +26,8 @@ import static android.app.AppOpsManager.OP_TOAST_WINDOW; import static android.content.Context.CONTEXT_RESTRICTED; import static android.content.Context.DISPLAY_SERVICE; import static android.content.Context.WINDOW_SERVICE; -import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static android.content.pm.PackageManager.FEATURE_LEANBACK; +import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.res.Configuration.EMPTY; @@ -35,6 +35,8 @@ import static android.content.res.Configuration.UI_MODE_TYPE_CAR; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.O; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.STATE_OFF; import static android.view.WindowManager.DOCKED_LEFT; import static android.view.WindowManager.DOCKED_RIGHT; import static android.view.WindowManager.DOCKED_TOP; @@ -57,6 +59,7 @@ import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SYSTEM_WINDOW; import static android.view.WindowManager.LayoutParams.MATCH_PARENT; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; @@ -70,8 +73,8 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; @@ -180,8 +183,8 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UEventObserver; import android.os.UserHandle; -import android.os.Vibrator; import android.os.VibrationEffect; +import android.os.Vibrator; import android.provider.MediaStore; import android.provider.Settings; import android.service.dreams.DreamManagerInternal; @@ -230,6 +233,7 @@ import android.view.autofill.AutofillManagerInternal; import android.view.inputmethod.InputMethodManagerInternal; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; @@ -244,8 +248,8 @@ import com.android.server.policy.keyguard.KeyguardServiceDelegate; import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener; import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback; import com.android.server.statusbar.StatusBarManagerInternal; -import com.android.server.wm.AppTransition; import com.android.server.vr.VrManagerInternal; +import com.android.server.wm.AppTransition; import java.io.File; import java.io.FileReader; @@ -680,6 +684,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mLastShowingDream; boolean mDreamingLockscreen; boolean mDreamingSleepTokenNeeded; + private boolean mWindowSleepTokenNeeded; + private boolean mLastWindowSleepTokenNeeded; + + @GuardedBy("mHandler") + private SleepToken mWindowSleepToken; + SleepToken mDreamingSleepToken; SleepToken mScreenOffSleepToken; volatile boolean mKeyguardOccluded; @@ -1040,6 +1050,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; + private final Runnable mAcquireSleepTokenRunnable = () -> { + if (mWindowSleepToken != null) { + return; + } + mWindowSleepToken = mActivityManagerInternal.acquireSleepToken("WindowSleepToken", + DEFAULT_DISPLAY); + }; + + private final Runnable mReleaseSleepTokenRunnable = () -> { + if (mWindowSleepToken == null) { + return; + } + mWindowSleepToken.release(); + mWindowSleepToken = null; + }; + private ImmersiveModeConfirmation mImmersiveModeConfirmation; private SystemGesturesPointerEventListener mSystemGestures; @@ -2152,7 +2178,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // This method might be called before the policy has been fully initialized // or for other displays we don't care about. // TODO(multi-display): Define policy for secondary displays. - if (mContext == null || display.getDisplayId() != Display.DEFAULT_DISPLAY) { + if (mContext == null || display.getDisplayId() != DEFAULT_DISPLAY) { return; } mDisplay = display; @@ -2248,7 +2274,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) { // TODO(multi-display): Define policy for secondary displays. - if (display.getDisplayId() == Display.DEFAULT_DISPLAY) { + if (display.getDisplayId() == DEFAULT_DISPLAY) { mOverscanLeft = left; mOverscanTop = top; mOverscanRight = right; @@ -2704,7 +2730,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, int displayId) { // TODO(multi-display): Support navigation bar on secondary displays. - if (displayId == Display.DEFAULT_DISPLAY && mHasNavigationBar) { + if (displayId == DEFAULT_DISPLAY && mHasNavigationBar) { // For a basic navigation bar, when we are in landscape mode we place // the navigation bar to the side. if (mNavigationBarCanMove && fullWidth > fullHeight) { @@ -2726,7 +2752,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, int displayId) { // TODO(multi-display): Support navigation bar on secondary displays. - if (displayId == Display.DEFAULT_DISPLAY && mHasNavigationBar) { + if (displayId == DEFAULT_DISPLAY && mHasNavigationBar) { // For a basic navigation bar, when we are in portrait mode we place // the navigation bar to the bottom. if (!mNavigationBarCanMove || fullWidth < fullHeight) { @@ -2750,7 +2776,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // we do want to exclude it since applications can't generally use that part // of the screen. // TODO(multi-display): Support status bars on secondary displays. - if (displayId == Display.DEFAULT_DISPLAY) { + if (displayId == DEFAULT_DISPLAY) { return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayId) - mStatusBarHeight; } @@ -2802,7 +2828,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean keyguardLocked = isKeyguardLocked(); boolean hideDockDivider = attrs.type == TYPE_DOCK_DIVIDER && !mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID); - return (keyguardLocked && !allowWhenLocked && win.getDisplayId() == Display.DEFAULT_DISPLAY) + return (keyguardLocked && !allowWhenLocked && win.getDisplayId() == DEFAULT_DISPLAY) || hideDockDivider; } @@ -2972,7 +2998,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** Obtain proper context for showing splash screen on the provided display. */ private Context getDisplayContext(Context context, int displayId) { - if (displayId == Display.DEFAULT_DISPLAY) { + if (displayId == DEFAULT_DISPLAY) { // The default context fits. return context; } @@ -5370,6 +5396,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mAllowLockscreenWhenOn = false; mShowingDream = false; + mWindowSleepTokenNeeded = false; } /** {@inheritDoc} */ @@ -5467,6 +5494,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { && stackId == DOCKED_STACK_ID) { mTopDockedOpaqueOrDimmingWindowState = win; } + + // Take note if a window wants to acquire a sleep token. + if (win.isVisibleLw() && (attrs.privateFlags & PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN) != 0 + && win.canAcquireSleepToken()) { + mWindowSleepTokenNeeded = true; + } } private void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget) { @@ -5597,11 +5630,24 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerFuncs.notifyShowingDreamChanged(); } + updateWindowSleepToken(); + // update since mAllowLockscreenWhenOn might have changed updateLockScreenTimeout(); return changes; } + private void updateWindowSleepToken() { + if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) { + mHandler.removeCallbacks(mReleaseSleepTokenRunnable); + mHandler.post(mAcquireSleepTokenRunnable); + } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) { + mHandler.removeCallbacks(mAcquireSleepTokenRunnable); + mHandler.post(mReleaseSleepTokenRunnable); + } + mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded; + } + /** * Updates the occluded state of the Keyguard. * @@ -6335,7 +6381,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private boolean shouldDispatchInputWhenNonInteractive(KeyEvent event) { - final boolean displayOff = (mDisplay == null || mDisplay.getState() == Display.STATE_OFF); + final boolean displayOff = (mDisplay == null || mDisplay.getState() == STATE_OFF); if (displayOff && !mHasFeatureWatch) { return false; @@ -7476,7 +7522,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (acquire) { if (mDreamingSleepToken == null) { mDreamingSleepToken = mActivityManagerInternal.acquireSleepToken( - "Dream", Display.DEFAULT_DISPLAY); + "Dream", DEFAULT_DISPLAY); } } else { if (mDreamingSleepToken != null) { @@ -7491,7 +7537,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (acquire) { if (mScreenOffSleepToken == null) { mScreenOffSleepToken = mActivityManagerInternal.acquireSleepToken( - "ScreenOff", Display.DEFAULT_DISPLAY); + "ScreenOff", DEFAULT_DISPLAY); } } else { if (mScreenOffSleepToken != null) { diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 7a8c2f91b4e9..178124776823 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.Manifest.permission.DEVICE_POWER; import static android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -84,6 +85,7 @@ public class Session extends IWindowSession.Stub private final Set<WindowSurfaceController> mAlertWindowSurfaces = new HashSet<>(); final boolean mCanAddInternalSystemWindow; final boolean mCanHideNonSystemOverlayWindows; + final boolean mCanAcquireSleepToken; private AlertWindowNotification mAlertWindowNotification; private boolean mShowingAlertWindowNotificationAllowed; private boolean mClientDead = false; @@ -103,6 +105,8 @@ public class Session extends IWindowSession.Stub INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED; mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission( HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED; + mCanAcquireSleepToken = service.mContext.checkCallingOrSelfPermission(DEVICE_POWER) + == PERMISSION_GRANTED; mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications; StringBuilder sb = new StringBuilder(); sb.append("Session{"); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 85e3f6db7363..5a181f1077d3 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -752,6 +752,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mOwnerCanAddInternalSystemWindow; } + @Override + public boolean canAcquireSleepToken() { + return mSession.mCanAcquireSleepToken; + } + /** * Subtracts the insets calculated by intersecting {@param layoutFrame} with {@param insetFrame} * from {@param frame}. In other words, it applies the insets that would result if |