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

Commit f950399c authored by Beverly's avatar Beverly Committed by Beverly Tai
Browse files

Refactor doze suppressors into its own class

There are multiple ways doze/aod can be suppressed/blocked. This
CL consolidates the majority of the logic to DozeSuppressor.java
and breaks apart the terminology `doze suppressed` (which refers to
the entire doze experience) from `always on suppressed` (which refers
to only suppressing always-on-display, but continuing to register
for wake-up-gestures).

+ Added DozeSuppressorTests
+ Added extra logging to DozeLog

Test: atest SystemUITests
Test: atest DozeSuppressorTest
Bug: 218509239
Change-Id: I8cec55d57b67a6e171849febabf8e92804d74f4e
parent d62c6e6c
Loading
Loading
Loading
Loading
+7 −5
Original line number Original line Diff line number Diff line
@@ -31,7 +31,6 @@ public interface DozeHost {
    boolean isPowerSaveActive();
    boolean isPowerSaveActive();
    boolean isPulsingBlocked();
    boolean isPulsingBlocked();
    boolean isProvisioned();
    boolean isProvisioned();
    boolean isBlockingDoze();


    /**
    /**
     * Makes a current pulse last for twice as long.
     * Makes a current pulse last for twice as long.
@@ -80,8 +79,9 @@ public interface DozeHost {
     */
     */
    void stopPulsing();
    void stopPulsing();


    /** Returns whether doze is suppressed. */
    /** Returns whether always-on-display is suppressed. This does not include suppressing
    boolean isDozeSuppressed();
     * wake-up gestures. */
    boolean isAlwaysOnSuppressed();


    interface Callback {
    interface Callback {
        /**
        /**
@@ -97,8 +97,10 @@ public interface DozeHost {
         */
         */
        default void onPowerSaveChanged(boolean active) {}
        default void onPowerSaveChanged(boolean active) {}


        /** Called when the doze suppression state changes. */
        /**
        default void onDozeSuppressedChanged(boolean suppressed) {}
         * Called when the always on suppression state changes. See {@link #isAlwaysOnSuppressed()}.
         */
        default void onAlwaysOnSuppressedChanged(boolean suppressed) {}
    }
    }


    interface PulseCallback {
    interface PulseCallback {
+29 −12
Original line number Original line Diff line number Diff line
@@ -131,14 +131,6 @@ public class DozeLog implements Dumpable {
        mLogger.logDozingChanged(dozing);
        mLogger.logDozingChanged(dozing);
    }
    }


    /**
     * Appends dozing event to the logs
     * @param suppressed true if dozing is suppressed
     */
    public void traceDozingSuppressed(boolean suppressed) {
        mLogger.logDozingSuppressed(suppressed);
    }

    /**
    /**
     * Appends fling event to the logs
     * Appends fling event to the logs
     */
     */
@@ -325,15 +317,40 @@ public class DozeLog implements Dumpable {
    }
    }


    /**
    /**
     * Appends doze suppressed event to the logs
     * Appends the doze state that was suppressed to the doze event log
     * @param suppressedState The {@link DozeMachine.State} that was suppressed
     * @param suppressedState The {@link DozeMachine.State} that was suppressed
     */
     */
    public void traceDozeSuppressed(DozeMachine.State suppressedState) {
    public void traceAlwaysOnSuppressed(DozeMachine.State suppressedState) {
        mLogger.logDozeSuppressed(suppressedState);
        mLogger.logAlwaysOnSuppressed(suppressedState);
    }

    /**
     * Appends reason why doze immediately ended.
     */
    public void traceImmediatelyEndDoze(String reason) {
        mLogger.logImmediatelyEndDoze(reason);
    }

    /**
     * Appends power save changes that may cause a new doze state
     * @param powerSaveActive true if power saving is active
     * @param nextState the state that we'll transition to
     */
    public void tracePowerSaveChanged(boolean powerSaveActive, DozeMachine.State nextState) {
        mLogger.logPowerSaveChanged(powerSaveActive, nextState);
    }

    /**
     * Appends an event on AOD suppression change
     * @param suppressed true if AOD is being suppressed
     * @param nextState the state that we'll transition to
     */
    public void traceAlwaysOnSuppressedChange(boolean suppressed, DozeMachine.State nextState) {
        mLogger.logAlwaysOnSuppressedChange(suppressed, nextState);
    }
    }


    /**
    /**
     * Appends new AOD sreen brightness to logs
     * Appends new AOD screen brightness to logs
     * @param brightness display brightness setting
     * @param brightness display brightness setting
     */
     */
    public void traceDozeScreenBrightness(int brightness) {
    public void traceDozeScreenBrightness(int brightness) {
+23 −5
Original line number Original line Diff line number Diff line
@@ -74,11 +74,21 @@ class DozeLogger @Inject constructor(
        })
        })
    }
    }


    fun logDozingSuppressed(isDozingSuppressed: Boolean) {
    fun logPowerSaveChanged(powerSaveActive: Boolean, nextState: DozeMachine.State) {
        buffer.log(TAG, INFO, {
        buffer.log(TAG, INFO, {
            bool1 = isDozingSuppressed
            bool1 = powerSaveActive
            str1 = nextState.name
        }, {
        }, {
            "DozingSuppressed=$bool1"
            "Power save active=$bool1 nextState=$str1"
        })
    }

    fun logAlwaysOnSuppressedChange(isAodSuppressed: Boolean, nextState: DozeMachine.State) {
        buffer.log(TAG, INFO, {
            bool1 = isAodSuppressed
            str1 = nextState.name
        }, {
            "Always on (AOD) suppressed changed, suppressed=$bool1 nextState=$str1"
        })
        })
    }
    }


@@ -257,11 +267,19 @@ class DozeLogger @Inject constructor(
        })
        })
    }
    }


    fun logDozeSuppressed(state: DozeMachine.State) {
    fun logAlwaysOnSuppressed(state: DozeMachine.State) {
        buffer.log(TAG, INFO, {
        buffer.log(TAG, INFO, {
            str1 = state.name
            str1 = state.name
        }, {
        }, {
            "Doze state suppressed, state=$str1"
            "Always-on state suppressed, suppressed state=$str1"
        })
    }

    fun logImmediatelyEndDoze(reason: String) {
        buffer.log(TAG, INFO, {
            str1 = reason
        }, {
            "Doze immediately ended due to $str1"
        })
        })
    }
    }


+2 −3
Original line number Original line Diff line number Diff line
@@ -357,9 +357,9 @@ public class DozeMachine {
        if (mState == State.FINISH) {
        if (mState == State.FINISH) {
            return State.FINISH;
            return State.FINISH;
        }
        }
        if (mDozeHost.isDozeSuppressed() && requestedState.isAlwaysOn()) {
        if (mDozeHost.isAlwaysOnSuppressed() && requestedState.isAlwaysOn()) {
            Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState);
            Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState);
            mDozeLog.traceDozeSuppressed(requestedState);
            mDozeLog.traceAlwaysOnSuppressed(requestedState);
            return State.DOZE;
            return State.DOZE;
        }
        }
        if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING
        if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING
@@ -415,7 +415,6 @@ public class DozeMachine {
        pw.print(" state="); pw.println(mState);
        pw.print(" state="); pw.println(mState);
        pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState);
        pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState);
        pw.print(" wakeLock="); pw.println(mWakeLock);
        pw.print(" wakeLock="); pw.println(mWakeLock);
        pw.print(" isDozeSuppressed="); pw.println(mDozeHost.isDozeSuppressed());
        pw.println("Parts:");
        pw.println("Parts:");
        for (Part p : mParts) {
        for (Part p : mParts) {
            p.dump(pw);
            p.dump(pw);
+195 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.doze;

import static android.app.UiModeManager.ACTION_ENTER_CAR_MODE;

import android.app.UiModeManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.PowerManager;
import android.os.UserHandle;
import android.text.TextUtils;

import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.statusbar.phone.BiometricUnlockController;

import java.io.PrintWriter;

import javax.inject.Inject;

import dagger.Lazy;

/**
 * Handles suppressing doze on:
 * 1. INITIALIZED, don't allow dozing at all when:
 *      - in CAR_MODE
 *      - device is NOT provisioned
 *      - there's a pending authentication
 * 2. PowerSaveMode active
 *      - no always-on-display (DOZE_AOD)
 *      - continues to allow doze triggers (DOZE, DOZE_REQUEST_PULSE)
 * 3. Suppression changes from the PowerManager API. See {@link PowerManager#suppressAmbientDisplay}
 *      and {@link DozeHost#isAlwaysOnSuppressed()}.
 *      - no always-on-display (DOZE_AOD)
 *      - allow doze triggers (DOZE), but disallow notifications (handled by {@link DozeTriggers})
 *      - See extra check in {@link DozeMachine} to guarantee device never enters always-on states
 */
@DozeScope
public class DozeSuppressor implements DozeMachine.Part {
    private static final String TAG = "DozeSuppressor";

    private DozeMachine mMachine;
    private final DozeHost mDozeHost;
    private final AmbientDisplayConfiguration mConfig;
    private final DozeLog mDozeLog;
    private final BroadcastDispatcher mBroadcastDispatcher;
    private final UiModeManager mUiModeManager;
    private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;

    private boolean mBroadcastReceiverRegistered;

    @Inject
    public DozeSuppressor(
            DozeHost dozeHost,
            AmbientDisplayConfiguration config,
            DozeLog dozeLog,
            BroadcastDispatcher broadcastDispatcher,
            UiModeManager uiModeManager,
            Lazy<BiometricUnlockController> biometricUnlockControllerLazy) {
        mDozeHost = dozeHost;
        mConfig = config;
        mDozeLog = dozeLog;
        mBroadcastDispatcher = broadcastDispatcher;
        mUiModeManager = uiModeManager;
        mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
    }

    @Override
    public void setDozeMachine(DozeMachine dozeMachine) {
        mMachine = dozeMachine;
    }

    @Override
    public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
        switch (newState) {
            case INITIALIZED:
                registerBroadcastReceiver();
                mDozeHost.addCallback(mHostCallback);
                checkShouldImmediatelyEndDoze();
                break;
            case FINISH:
                destroy();
                break;
            default:
        }
    }

    @Override
    public void destroy() {
        unregisterBroadcastReceiver();
        mDozeHost.removeCallback(mHostCallback);
    }

    private void checkShouldImmediatelyEndDoze() {
        String reason = null;
        if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) {
            reason = "car_mode";
        } else if (!mDozeHost.isProvisioned()) {
            reason = "device_unprovisioned";
        } else if (mBiometricUnlockControllerLazy.get().hasPendingAuthentication()) {
            reason = "has_pending_auth";
        }

        if (!TextUtils.isEmpty(reason)) {
            mDozeLog.traceImmediatelyEndDoze(reason);
            mMachine.requestState(DozeMachine.State.FINISH);
        }
    }

    @Override
    public void dump(PrintWriter pw) {
        pw.println(" uiMode=" + mUiModeManager.getCurrentModeType());
        pw.println(" hasPendingAuth="
                + mBiometricUnlockControllerLazy.get().hasPendingAuthentication());
        pw.println(" isProvisioned=" + mDozeHost.isProvisioned());
        pw.println(" isAlwaysOnSuppressed=" + mDozeHost.isAlwaysOnSuppressed());
        pw.println(" aodPowerSaveActive=" + mDozeHost.isPowerSaveActive());
    }

    private void registerBroadcastReceiver() {
        if (mBroadcastReceiverRegistered) {
            return;
        }
        IntentFilter filter = new IntentFilter(ACTION_ENTER_CAR_MODE);
        mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
        mBroadcastReceiverRegistered = true;
    }

    private void unregisterBroadcastReceiver() {
        if (!mBroadcastReceiverRegistered) {
            return;
        }
        mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
        mBroadcastReceiverRegistered = false;
    }

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
                mDozeLog.traceImmediatelyEndDoze("car_mode");
                mMachine.requestState(DozeMachine.State.FINISH);
            }
        }
    };

    private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
        @Override
        public void onPowerSaveChanged(boolean active) {
            DozeMachine.State nextState = null;
            if (mDozeHost.isPowerSaveActive()) {
                nextState = DozeMachine.State.DOZE;
            } else if (mMachine.getState() == DozeMachine.State.DOZE
                    && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
                nextState = DozeMachine.State.DOZE_AOD;
            }

            if (nextState != null) {
                mDozeLog.tracePowerSaveChanged(mDozeHost.isPowerSaveActive(), nextState);
                mMachine.requestState(nextState);
            }
        }

        @Override
        public void onAlwaysOnSuppressedChanged(boolean suppressed) {
            final DozeMachine.State nextState;
            if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !suppressed) {
                nextState = DozeMachine.State.DOZE_AOD;
            } else {
                nextState = DozeMachine.State.DOZE;
            }
            mDozeLog.traceAlwaysOnSuppressedChange(suppressed, nextState);
            mMachine.requestState(nextState);
        }
    };
}
Loading