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

Commit 51304d73 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Take snapshot when screen is turning off

Since we can't take a snapshot when screen is turned off, we need
to snapshot before we are turning the screen off. For this, we
- Add a callback from DisplayPowerController to give policy a
chance to do something before display will be turned off.
- Implement this callback by taking snapshots of all visible
tasks.

Test: Inspect logs/traces about screen off blocking to make sure
callback is working correctly.
Test: Insert artificial 500ms delay in onScreenTurningOff and make
sure we are unblocking screen off when turning on screen in the
meantime.
Test: Open Maps, go to recents, open maps again, scroll to another
location, toggle power button, make sure the old location isn't
shown during unlock.

Change-Id: I489f31358f838d418f894f996495946084f136a4
Fixes: 37107783
parent 95cf170c
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -589,6 +589,13 @@ public interface WindowManagerPolicy {
         * Notifies window manager that {@link #isKeyguardTrustedLw} has changed.
         */
        void notifyKeyguardTrustedChanged();

        /**
         * Notifies the window manager that screen is being turned off.
         *
         * @param listener callback to call when display can be turned off
         */
        void screenTurningOff(ScreenOffListener listener);
    }

    public interface PointerEventListener {
@@ -1266,6 +1273,15 @@ public interface WindowManagerPolicy {
     */
    public void screenTurnedOn();

    /**
     * Called when the display would like to be turned off. This gives policy a chance to do some
     * things before the display power state is actually changed to off.
     *
     * @param screenOffListener Must be called to tell that the display power state can actually be
     *                          changed now after policy has done its work.
     */
    public void screenTurningOff(ScreenOffListener screenOffListener);

    /**
     * Called when the device has turned the screen off.
     */
@@ -1275,6 +1291,13 @@ public interface WindowManagerPolicy {
        void onScreenOn();
    }

    /**
     * See {@link #screenTurnedOff}
     */
    public interface ScreenOffListener {
        void onScreenOff();
    }

    /**
     * Return whether the default display is on and not blocked by a black surface.
     */
+66 −3
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ import java.io.PrintWriter;
final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
    private static final String TAG = "DisplayPowerController";
    private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
    private static final String SCREEN_OFF_BLOCKED_TRACE_NAME = "Screen off blocked";

    private static final boolean DEBUG = false;
    private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
@@ -90,6 +91,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
    private static final int MSG_UPDATE_POWER_STATE = 1;
    private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
    private static final int MSG_SCREEN_ON_UNBLOCKED = 3;
    private static final int MSG_SCREEN_OFF_UNBLOCKED = 4;

    private static final int PROXIMITY_UNKNOWN = -1;
    private static final int PROXIMITY_NEGATIVE = 0;
@@ -105,6 +107,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
    private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;
    private static final int REPORTED_TO_POLICY_SCREEN_TURNING_ON = 1;
    private static final int REPORTED_TO_POLICY_SCREEN_ON = 2;
    private static final int REPORTED_TO_POLICY_SCREEN_TURNING_OFF = 3;

    private final Object mLock = new Object();

@@ -219,6 +222,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
    // The currently active screen on unblocker.  This field is non-null whenever
    // we are waiting for a callback to release it and unblock the screen.
    private ScreenOnUnblocker mPendingScreenOnUnblocker;
    private ScreenOffUnblocker mPendingScreenOffUnblocker;

    // True if we were in the process of turning off the screen.
    // This allows us to recover more gracefully from situations where we abort
@@ -230,6 +234,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call

    // The elapsed real time when the screen on was blocked.
    private long mScreenOnBlockStartRealTime;
    private long mScreenOffBlockStartRealTime;

    // Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_SCREEN_* fields.
    private int mReportedScreenStateToPolicy;
@@ -810,9 +815,43 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        }
    }

    private void blockScreenOff() {
        if (mPendingScreenOffUnblocker == null) {
            Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_OFF_BLOCKED_TRACE_NAME, 0);
            mPendingScreenOffUnblocker = new ScreenOffUnblocker();
            mScreenOffBlockStartRealTime = SystemClock.elapsedRealtime();
            Slog.i(TAG, "Blocking screen off");
        }
    }

    private void unblockScreenOff() {
        if (mPendingScreenOffUnblocker != null) {
            mPendingScreenOffUnblocker = null;
            long delay = SystemClock.elapsedRealtime() - mScreenOffBlockStartRealTime;
            Slog.i(TAG, "Unblocked screen off after " + delay + " ms");
            Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_OFF_BLOCKED_TRACE_NAME, 0);
        }
    }

    private boolean setScreenState(int state) {
        final boolean isOff = (state == Display.STATE_OFF);
        if (mPowerState.getScreenState() != state) {
            final boolean wasOn = (mPowerState.getScreenState() != Display.STATE_OFF);

            // If we are trying to turn screen off, give policy a chance to do something before we
            // actually turn the screen off.
            if (isOff && !mScreenOffBecauseOfProximity) {
                if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON) {
                    mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_TURNING_OFF;
                    blockScreenOff();
                    mWindowManagerPolicy.screenTurningOff(mPendingScreenOffUnblocker);
                    return false;
                } else if (mPendingScreenOffUnblocker != null) {

                    // Abort doing the state change until screen off is unblocked.
                    return false;
                }
            }

            mPowerState.setScreenState(state);

            // Tell battery stats about the transition.
@@ -829,13 +868,21 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
        // This surface is essentially the final state of the color fade animation and
        // it is only removed once the window manager tells us that the activity has
        // finished drawing underneath.
        final boolean isOff = (state == Display.STATE_OFF);
        if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF
                && !mScreenOffBecauseOfProximity) {
            mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_OFF;
            unblockScreenOn();
            mWindowManagerPolicy.screenTurnedOff();
        } else if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
        } else if (!isOff
                && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_OFF) {

            // We told policy already that screen was turning off, but now we changed our minds.
            // Complete the full state transition on -> turningOff -> off.
            unblockScreenOff();
            mWindowManagerPolicy.screenTurnedOff();
            mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_OFF;
        }
        if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
            mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_TURNING_ON;
            if (mPowerState.getColorFadeLevel() == 0.0f) {
                blockScreenOn();
@@ -1282,6 +1329,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
                        updatePowerState();
                    }
                    break;
                case MSG_SCREEN_OFF_UNBLOCKED:
                    if (mPendingScreenOffUnblocker == msg.obj) {
                        unblockScreenOff();
                        updatePowerState();
                    }
                    break;
            }
        }
    }
@@ -1311,4 +1364,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
            mHandler.sendMessage(msg);
        }
    }

    private final class ScreenOffUnblocker implements WindowManagerPolicy.ScreenOffListener {

        @Override
        public void onScreenOff() {
            Message msg = mHandler.obtainMessage(MSG_SCREEN_OFF_UNBLOCKED, this);
            msg.setAsynchronous(true);
            mHandler.sendMessage(msg);
        }
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -6667,6 +6667,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        reportScreenStateToVrManager(true);
    }

    @Override
    public void screenTurningOff(ScreenOffListener screenOffListener) {
        mWindowManagerFuncs.screenTurningOff(screenOffListener);
    }

    private void reportScreenStateToVrManager(boolean isScreenOn) {
        if (mVrManagerInternal == null) {
            return;
+5 −0
Original line number Diff line number Diff line
@@ -2898,6 +2898,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
        final MutableBoolean mutableIncludeFullDisplay = new MutableBoolean(includeFullDisplay);
        synchronized(mService.mWindowMap) {
            if (!mService.mPolicy.isScreenOn()) {
                if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Attempted to take screenshot while display"
                        + " was off.");
                return null;
            }
            // Figure out the part of the screen that is actually the app.
            mScreenshotApplicationState.appWin = null;
            forAllWindows(w -> {
+6 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;

import java.io.PrintWriter;
import java.util.function.Consumer;

class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerUser {
    static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
@@ -683,6 +684,11 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
        return (TaskWindowContainerController) super.getController();
    }

    @Override
    void forAllTasks(Consumer<Task> callback) {
        callback.accept(this);
    }

    @Override
    public String toString() {
        return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
Loading