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

Commit 416c49c4 authored by Jeff Brown's avatar Jeff Brown
Browse files

Tell PhoneWindowManager when we start/finish interactive changes.

Added some new callbacks that can be used to more precisely trigger
certain behaviors that need to happen around the time the device
is put to sleep and locked.

Fixed an issue where the going to sleep signal might be sent too
early on devices that don't support ambient mode due to the extra
wakefulness change between DOZING and ASLEEP.  We are now track
the early / late interactive change work separately from the rest.

Bug: 21375811
Change-Id: I95387195e216ae92a6e45485bd1bd362e41aa45a
parent bdf2d1fa
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -941,17 +941,30 @@ public interface WindowManagerPolicy {
    public int focusChangedLw(WindowState lastFocus, WindowState newFocus);

    /**
     * Called when the device is waking up.
     * Called when the device has started waking up.
     */
    public void wakingUp();
    public void startedWakingUp();

    /**
     * Called when the device is going to sleep.
     * Called when the device has finished waking up.
     */
    public void finishedWakingUp();

    /**
     * Called when the device has started going to sleep.
     *
     * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN},
     * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
     */
    public void startedGoingToSleep(int why);

    /**
     * Called when the device has finished going to sleep.
     *
     * @param why {@link #OFF_BECAUSE_OF_USER} or
     * {@link #OFF_BECAUSE_OF_TIMEOUT}.
     * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN},
     * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
     */
    public void goingToSleep(int why);
    public void finishedGoingToSleep(int why);

    /**
     * Called when the device is about to turn on the screen to show content.
+32 −19
Original line number Diff line number Diff line
@@ -1451,7 +1451,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {

        // Match current screen state.
        if (!mPowerManager.isInteractive()) {
            goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
            startedGoingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
            finishedGoingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
        }

        mWindowManagerInternal.registerAppTransitionListener(
@@ -5215,9 +5216,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {

    // Called on the PowerManager's Notifier thread.
    @Override
    public void goingToSleep(int why) {
    public void startedGoingToSleep(int why) {
        if (DEBUG_WAKEUP) Slog.i(TAG, "Started going to sleep... (why=" + why + ")");
    }

    // Called on the PowerManager's Notifier thread.
    @Override
    public void finishedGoingToSleep(int why) {
        EventLog.writeEvent(70000, 0);
        if (DEBUG_WAKEUP) Slog.i(TAG, "Going to sleep...");
        if (DEBUG_WAKEUP) Slog.i(TAG, "Finished going to sleep... (why=" + why + ")");

        // We must get this work done here because the power manager will drop
        // the wake lock and let the system suspend once this function returns.
@@ -5234,24 +5241,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
    }

    private void wakeUpFromPowerKey(long eventTime) {
        wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey);
    }

    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) {
        if (!wakeInTheaterMode && isTheaterModeEnabled()) {
            return false;
        }

        mPowerManager.wakeUp(wakeTime);
        return true;
    }

    // Called on the PowerManager's Notifier thread.
    @Override
    public void wakingUp() {
    public void startedWakingUp() {
        EventLog.writeEvent(70000, 1);
        if (DEBUG_WAKEUP) Slog.i(TAG, "Waking up...");
        if (DEBUG_WAKEUP) Slog.i(TAG, "Started waking up...");

        // Since goToSleep performs these functions synchronously, we must
        // do the same here.  We cannot post this work to a handler because
@@ -5279,6 +5273,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
    }

    // Called on the PowerManager's Notifier thread.
    @Override
    public void finishedWakingUp() {
        if (DEBUG_WAKEUP) Slog.i(TAG, "Finished waking up...");
    }

    private void wakeUpFromPowerKey(long eventTime) {
        wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey);
    }

    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) {
        if (!wakeInTheaterMode && isTheaterModeEnabled()) {
            return false;
        }

        mPowerManager.wakeUp(wakeTime);
        return true;
    }

    private void finishKeyguardDrawn() {
        synchronized (mLock) {
            if (!mAwake || mKeyguardDrawComplete) {
@@ -5771,7 +5784,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        synchronized (mLock) {
            mSystemBooted = true;
        }
        wakingUp();
        startedWakingUp();
        screenTurningOn(null);
    }

+136 −88
Original line number Diff line number Diff line
@@ -95,11 +95,19 @@ final class Notifier {
    private final Intent mScreenOffIntent;
    private final Intent mScreenBrightnessBoostIntent;

    // The current interactive state.
    private int mActualInteractiveState;
    private int mLastReason;

    // True if there is a pending transition that needs to be reported.
    // The current interactive state.  This is set as soon as an interactive state
    // transition begins so as to capture the reason that it happened.  At some point
    // this state will propagate to the pending state then eventually to the
    // broadcasted state over the course of reporting the transition asynchronously.
    private boolean mInteractive = true;
    private int mInteractiveChangeReason;
    private boolean mInteractiveChanging;

    // The pending interactive state that we will eventually want to broadcast.
    // This is designed so that we can collapse redundant sequences of awake/sleep
    // transition pairs while still guaranteeing that at least one transition is observed
    // whenever this happens.
    private int mPendingInteractiveState;
    private boolean mPendingWakeUpBroadcast;
    private boolean mPendingGoToSleepBroadcast;

@@ -244,113 +252,152 @@ final class Notifier {

    /**
     * Notifies that the device is changing wakefulness.
     * This function may be called even if the previous change hasn't finished in
     * which case it will assume that the state did not fully converge before the
     * next transition began and will recover accordingly.
     */
    public void onWakefulnessChangeStarted(int wakefulness, int reason) {
    public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
        if (DEBUG) {
            Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
                    + ", reason=" + reason);
                    + ", reason=" + reason + ", interactive=" + interactive);
        }

        // We handle interactive state changes once they start so that the system can
        // set everything up or the user to begin interacting with applications.
        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
        if (interactive) {
            handleWakefulnessChange(wakefulness, interactive, reason);
        } else {
            mLastReason = reason;
        // Tell the activity manager about changes in wakefulness, not just interactivity.
        // It needs more granularity than other components.
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mActivityManagerInternal.onWakefulnessChanged(wakefulness);
            }
        });

        // Handle any early interactive state changes.
        // Finish pending incomplete ones from a previous cycle.
        if (mInteractive != interactive) {
            // Finish up late behaviors if needed.
            if (mInteractiveChanging) {
                handleLateInteractiveChange();
            }

            // Start input as soon as we start waking up or going to sleep.
            mInputManagerInternal.setInteractive(interactive);

            // Notify battery stats.
            try {
                mBatteryStats.noteInteractive(interactive);
            } catch (RemoteException ex) { }

            // Handle early behaviors.
            mInteractive = interactive;
            mInteractiveChangeReason = reason;
            mInteractiveChanging = true;
            handleEarlyInteractiveChange();
        }
    }

    /**
     * Notifies that the device has finished changing wakefulness.
     */
    public void onWakefulnessChangeFinished(int wakefulness) {
    public void onWakefulnessChangeFinished() {
        if (DEBUG) {
            Slog.d(TAG, "onWakefulnessChangeFinished: wakefulness=" + wakefulness);
            Slog.d(TAG, "onWakefulnessChangeFinished");
        }

        // Handle interactive state changes once they are finished so that the system can
        // finish pending transitions (such as turning the screen off) before causing
        // applications to change state visibly.
        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
        if (!interactive) {
            handleWakefulnessChange(wakefulness, interactive, mLastReason);
        if (mInteractiveChanging) {
            mInteractiveChanging = false;
            handleLateInteractiveChange();
        }
    }

    private void handleWakefulnessChange(final int wakefulness, boolean interactive,
            final int reason) {
        // Tell the activity manager about changes in wakefulness, not just interactivity.
        // It needs more granularity than other components.
    /**
     * Handle early interactive state changes such as getting applications or the lock
     * screen running and ready for the user to see (such as when turning on the screen).
     */
    private void handleEarlyInteractiveChange() {
        synchronized (mLock) {
            if (mInteractive) {
                // Waking up...
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                mActivityManagerInternal.onWakefulnessChanged(wakefulness);
                        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
                        mPolicy.startedWakingUp();
                    }
                });

        // Handle changes in the overall interactive state.
        boolean interactiveChanged = false;
        synchronized (mLock) {
            // Broadcast interactive state changes.
            if (interactive) {
                // Waking up...
                interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_AWAKE);
                if (interactiveChanged) {
                    mActualInteractiveState = INTERACTIVE_STATE_AWAKE;
                // Send interactive broadcast.
                mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
                mPendingWakeUpBroadcast = true;
                updatePendingBroadcastLocked();
            } else {
                // Going to sleep...
                // Tell the policy that we started going to sleep.
                final int why = translateOffReason(mInteractiveChangeReason);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                            EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
                            mPolicy.wakingUp();
                        mPolicy.startedGoingToSleep(why);
                    }
                });
                    updatePendingBroadcastLocked();
            }
        }
    }

    /**
     * Handle late interactive state changes once they are finished so that the system can
     * finish pending transitions (such as turning the screen off) before causing
     * applications to change state visibly.
     */
    private void handleLateInteractiveChange() {
        synchronized (mLock) {
            if (mInteractive) {
                // Finished waking up...
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mPolicy.finishedWakingUp();
                    }
                });
            } else {
                // Going to sleep...
                // Finished going to sleep...
                // This is a good time to make transitions that we don't want the user to see,
                // such as bringing the key guard to focus.  There's no guarantee for this,
                // such as bringing the key guard to focus.  There's no guarantee for this
                // however because the user could turn the device on again at any time.
                // Some things may need to be protected by other mechanisms that defer screen on.
                interactiveChanged = (mActualInteractiveState != INTERACTIVE_STATE_ASLEEP);
                if (interactiveChanged) {
                    mActualInteractiveState = INTERACTIVE_STATE_ASLEEP;
                    mPendingGoToSleepBroadcast = true;

                // Cancel pending user activity.
                if (mUserActivityPending) {
                    mUserActivityPending = false;
                    mHandler.removeMessages(MSG_USER_ACTIVITY);
                }

                // Tell the policy we finished going to sleep.
                final int why = translateOffReason(mInteractiveChangeReason);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                            int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
                            switch (reason) {
                                case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
                                    why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
                                    break;
                                case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
                                    why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
                                    break;
                            }
                        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
                            mPolicy.goingToSleep(why);
                        mPolicy.finishedGoingToSleep(why);
                    }
                });

                // Send non-interactive broadcast.
                mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;
                mPendingGoToSleepBroadcast = true;
                updatePendingBroadcastLocked();
            }
        }
    }

        // Notify battery stats.
        if (interactiveChanged) {
            try {
                mBatteryStats.noteInteractive(interactive);
            } catch (RemoteException ex) { }
    private static int translateOffReason(int reason) {
        switch (reason) {
            case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
                return WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
            case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
                return WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
            default:
                return WindowManagerPolicy.OFF_BECAUSE_OF_USER;
        }
    }

@@ -367,6 +414,7 @@ final class Notifier {
        msg.setAsynchronous(true);
        mHandler.sendMessage(msg);
    }

    /**
     * Called when there has been user activity.
     */
@@ -407,9 +455,9 @@ final class Notifier {

    private void updatePendingBroadcastLocked() {
        if (!mBroadcastInProgress
                && mActualInteractiveState != INTERACTIVE_STATE_UNKNOWN
                && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
                && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mActualInteractiveState != mBroadcastedInteractiveState)) {
                        || mPendingInteractiveState != mBroadcastedInteractiveState)) {
            mBroadcastInProgress = true;
            mSuspendBlocker.acquire();
            Message msg = mHandler.obtainMessage(MSG_BROADCAST);
@@ -444,7 +492,7 @@ final class Notifier {
            } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
                // Broadcasted power state is awake.  Send asleep if needed.
                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mActualInteractiveState == INTERACTIVE_STATE_ASLEEP) {
                        || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
                    mPendingGoToSleepBroadcast = false;
                    mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
                } else {
@@ -454,7 +502,7 @@ final class Notifier {
            } else {
                // Broadcasted power state is asleep.  Send awake if needed.
                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mActualInteractiveState == INTERACTIVE_STATE_AWAKE) {
                        || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
                    mPendingWakeUpBroadcast = false;
                    mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
                } else {
+8 −8
Original line number Diff line number Diff line
@@ -1217,8 +1217,6 @@ public final class PowerManagerService extends SystemService

    private void setWakefulnessLocked(int wakefulness, int reason) {
        if (mWakefulness != wakefulness) {
            finishWakefulnessChangeLocked();

            mWakefulness = wakefulness;
            mWakefulnessChanging = true;
            mDirty |= DIRTY_WAKEFULNESS;
@@ -1226,10 +1224,14 @@ public final class PowerManagerService extends SystemService
        }
    }

    private void finishWakefulnessChangeLocked() {
        if (mWakefulnessChanging) {
            mNotifier.onWakefulnessChangeFinished(mWakefulness);
    private void finishWakefulnessChangeIfNeededLocked() {
        if (mWakefulnessChanging && mDisplayReady) {
            if (mWakefulness == WAKEFULNESS_DOZING
                    && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
                return; // wait until dream has enabled dozing
            }
            mWakefulnessChanging = false;
            mNotifier.onWakefulnessChangeFinished();
        }
    }

@@ -1280,9 +1282,7 @@ public final class PowerManagerService extends SystemService
            updateDreamLocked(dirtyPhase2, displayBecameReady);

            // Phase 4: Send notifications, if needed.
            if (mDisplayReady) {
                finishWakefulnessChangeLocked();
            }
            finishWakefulnessChangeIfNeededLocked();

            // Phase 5: Update suspend blocker.
            // Because we might release the last suspend blocker here, we need to make sure