From f12ec0fb6419920d3aa606141a91343cc9421275 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Wed, 23 Aug 2017 16:14:10 +0200 Subject: [PATCH] Sleep activities with AOD Previously in the last release we started sleeping as soon as the device was not interactive anymore. However, this caused issues with ambiactive activites on Android Wear. Instead, we introduce a new private flag on a window that signals that all activities should be put to sleep. We use this flag in SystemUI as soon as SystemUI is "dozing", which means its ambient display is showing. This flag gets set before we request PWM to wake-up, so it's ensured that this will not cause any spurious lifecycle events. Test: go/wm-smoke Test: android.server.cts.KeyguardTests Change-Id: I20f6dd4bfde220f945ef94d2ac1b89dd3694de32 Fixes: 64940094 --- core/java/android/view/WindowManager.java | 10 +++ .../android/view/WindowManagerPolicy.java | 11 ++- .../phone/StatusBarWindowManager.java | 10 +++ .../server/policy/PhoneWindowManager.java | 74 +++++++++++++++---- .../java/com/android/server/wm/Session.java | 4 + .../com/android/server/wm/WindowState.java | 5 ++ 6 files changed, 98 insertions(+), 16 deletions(-) diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 1e50a85833ec8..86402a7c6abeb 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; @@ -1423,6 +1424,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 49b7ed8bac0e1..c4ffb4c06a26d 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; @@ -485,11 +486,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(); } /** @@ -774,7 +781,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 eaa6a33b05d71..ed96b41158885 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 3c11a539dff63..6a8fc2e14cfdf 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; @@ -177,8 +180,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; @@ -226,6 +229,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; @@ -240,8 +244,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; @@ -676,6 +680,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; @@ -1036,6 +1046,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; @@ -2148,7 +2174,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; @@ -2244,7 +2270,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; @@ -2699,7 +2725,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) { @@ -2721,7 +2747,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) { @@ -2745,7 +2771,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; } @@ -2797,7 +2823,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; } @@ -2967,7 +2993,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; } @@ -5365,6 +5391,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mAllowLockscreenWhenOn = false; mShowingDream = false; + mWindowSleepTokenNeeded = false; } /** {@inheritDoc} */ @@ -5462,6 +5489,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) { @@ -5592,11 +5625,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. * @@ -6330,7 +6376,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; @@ -7471,7 +7517,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) { @@ -7486,7 +7532,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 7a8c2f91b4e9b..1781247768232 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 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 da739ac93b146..b61a873ea0362 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -734,6 +734,11 @@ class WindowState extends WindowContainer 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