Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f12ec0fb authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

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
parent dd09e994
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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
+9 −2
Original line number Diff line number Diff line
@@ -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
+10 −0
Original line number Diff line number Diff line
@@ -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);
+60 −14
Original line number Diff line number Diff line
@@ -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) {
+4 −0
Original line number Diff line number Diff line
@@ -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{");
Loading