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

Commit 6430c547 authored by Lucas Silva's avatar Lucas Silva
Browse files

Update PowerManager to make ambient display suppression apply

to dreams.

Bug: 246472225
Test: manually by triggering ambient suppression/unsuppresion via adb
Test: atest PowerManagerServiceTest
Change-Id: Ib8cb68239be04e0481a1af14d974d9623f509eb9
parent 12cac9c1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2479,6 +2479,8 @@
    <integer name="config_attentionMaximumExtension">900000</integer> <!-- 15 minutes.  -->
    <!-- Is the system user the only user allowed to dream. -->
    <bool name="config_dreamsOnlyEnabledForSystemUser">false</bool>
    <!-- Whether dreams are disabled when ambient mode is suppressed. -->
    <bool name="config_dreamsDisabledByAmbientModeSuppressionConfig">false</bool>

    <!-- Whether to dismiss the active dream when an activity is started. Doesn't apply to
         assistant activities (ACTIVITY_TYPE_ASSISTANT) -->
+1 −0
Original line number Diff line number Diff line
@@ -2235,6 +2235,7 @@
  <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenNotPowered" />
  <java-symbol type="integer" name="config_dreamsBatteryLevelDrainCutoff" />
  <java-symbol type="string" name="config_dreamsDefaultComponent" />
  <java-symbol type="bool" name="config_dreamsDisabledByAmbientModeSuppressionConfig" />
  <java-symbol type="bool" name="config_dreamsOnlyEnabledForSystemUser" />
  <java-symbol type="array" name="config_supportedDreamComplications" />
  <java-symbol type="array" name="config_disabledDreamComponents" />
+21 −4
Original line number Diff line number Diff line
@@ -40,13 +40,24 @@ import java.util.Set;
public class AmbientDisplaySuppressionController {
    private static final String TAG = "AmbientDisplaySuppressionController";

    private final Context mContext;
    private final Set<Pair<String, Integer>> mSuppressionTokens;
    private final AmbientDisplaySuppressionChangedCallback mCallback;
    private IStatusBarService mStatusBarService;

    AmbientDisplaySuppressionController(Context context) {
        mContext = requireNonNull(context);
    /** Interface to get a list of available logical devices. */
    interface AmbientDisplaySuppressionChangedCallback {
        /**
         * Called when the suppression state changes.
         *
         * @param isSuppressed Whether ambient is suppressed.
         */
        void onSuppressionChanged(boolean isSuppressed);
    }

    AmbientDisplaySuppressionController(
            @NonNull AmbientDisplaySuppressionChangedCallback callback) {
        mSuppressionTokens = Collections.synchronizedSet(new ArraySet<>());
        mCallback = requireNonNull(callback);
    }

    /**
@@ -58,6 +69,7 @@ public class AmbientDisplaySuppressionController {
     */
    public void suppress(@NonNull String token, int callingUid, boolean suppress) {
        Pair<String, Integer> suppressionToken = Pair.create(requireNonNull(token), callingUid);
        final boolean wasSuppressed = isSuppressed();

        if (suppress) {
            mSuppressionTokens.add(suppressionToken);
@@ -65,9 +77,14 @@ public class AmbientDisplaySuppressionController {
            mSuppressionTokens.remove(suppressionToken);
        }

        final boolean isSuppressed = isSuppressed();
        if (isSuppressed != wasSuppressed) {
            mCallback.onSuppressionChanged(isSuppressed);
        }

        try {
            synchronized (mSuppressionTokens) {
                getStatusBar().suppressAmbientDisplay(isSuppressed());
                getStatusBar().suppressAmbientDisplay(isSuppressed);
            }
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to suppress ambient display", e);
+41 −4
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ import com.android.server.am.BatteryStatsService;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.AmbientDisplaySuppressionController.AmbientDisplaySuppressionChangedCallback;
import com.android.server.power.batterysaver.BatterySaverController;
import com.android.server.power.batterysaver.BatterySaverPolicy;
import com.android.server.power.batterysaver.BatterySaverStateMachine;
@@ -507,6 +508,9 @@ public final class PowerManagerService extends SystemService
    // effectively and terminate the dream.  Use -1 to disable this safety feature.
    private int mDreamsBatteryLevelDrainCutoffConfig;

    // Whether dreams should be disabled when ambient mode is suppressed.
    private boolean mDreamsDisabledByAmbientModeSuppressionConfig;

    // True if dreams are enabled by the user.
    private boolean mDreamsEnabledSetting;

@@ -964,8 +968,8 @@ public final class PowerManagerService extends SystemService
        }

        AmbientDisplaySuppressionController createAmbientDisplaySuppressionController(
                Context context) {
            return new AmbientDisplaySuppressionController(context);
                @NonNull AmbientDisplaySuppressionChangedCallback callback) {
            return new AmbientDisplaySuppressionController(callback);
        }

        InattentiveSleepWarningController createInattentiveSleepWarningController() {
@@ -1044,7 +1048,8 @@ public final class PowerManagerService extends SystemService
        mConstants = new Constants(mHandler);
        mAmbientDisplayConfiguration = mInjector.createAmbientDisplayConfiguration(context);
        mAmbientDisplaySuppressionController =
                mInjector.createAmbientDisplaySuppressionController(context);
                mInjector.createAmbientDisplaySuppressionController(
                        mAmbientSuppressionChangedCallback);
        mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock);
        mFaceDownDetector = new FaceDownDetector(this::onFlip);
        mScreenUndimDetector = new ScreenUndimDetector();
@@ -1403,6 +1408,8 @@ public final class PowerManagerService extends SystemService
                com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered);
        mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
                com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
        mDreamsDisabledByAmbientModeSuppressionConfig = resources.getBoolean(
                com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig);
        mDozeAfterScreenOff = resources.getBoolean(
                com.android.internal.R.bool.config_dozeAfterScreenOffByDefault);
        mMinimumScreenOffTimeoutConfig = resources.getInteger(
@@ -3340,12 +3347,32 @@ public final class PowerManagerService extends SystemService
        }
    }

    @GuardedBy("mLock")
    private void onDreamSuppressionChangedLocked(final boolean isSuppressed) {
        if (!mDreamsDisabledByAmbientModeSuppressionConfig) {
            return;
        }
        if (!isSuppressed && mIsPowered && mDreamsSupportedConfig && mDreamsEnabledSetting
                && shouldNapAtBedTimeLocked() && isItBedTimeYetLocked(
                mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP))) {
            napInternal(SystemClock.uptimeMillis(), Process.SYSTEM_UID, /* allowWake= */ true);
        } else if (isSuppressed) {
            mDirty |= DIRTY_SETTINGS;
            updatePowerStateLocked();
        }
    }


    /**
     * Returns true if the {@code groupId} is allowed to dream in its current state.
     */
    @GuardedBy("mLock")
    private boolean canDreamLocked(final PowerGroup powerGroup) {
        final boolean dreamsSuppressed = mDreamsDisabledByAmbientModeSuppressionConfig
                && mAmbientDisplaySuppressionController.isSuppressed();

        if (!mBootCompleted
                || dreamsSuppressed
                || getGlobalWakefulnessLocked() != WAKEFULNESS_DREAMING
                || !mDreamsSupportedConfig
                || !mDreamsEnabledSetting
@@ -5037,6 +5064,16 @@ public final class PowerManagerService extends SystemService
        }
    };

    private final AmbientDisplaySuppressionChangedCallback mAmbientSuppressionChangedCallback =
            new AmbientDisplaySuppressionChangedCallback() {
                @Override
                public void onSuppressionChanged(boolean isSuppressed) {
                    synchronized (mLock) {
                        onDreamSuppressionChangedLocked(isSuppressed);
                    }
                }
            };

    /**
     * Callback for asynchronous operations performed by the power manager.
     */
+91 −0
Original line number Diff line number Diff line
@@ -393,6 +393,12 @@ public class PowerManagerServiceTest {
                .thenReturn(minimumScreenOffTimeoutConfigMillis);
    }

    private void setDreamsDisabledByAmbientModeSuppressionConfig(boolean disable) {
        when(mResourcesSpy.getBoolean(
                com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig))
                .thenReturn(disable);
    }

    private void advanceTime(long timeMs) {
        mClock.fastForward(timeMs);
        mTestLooper.dispatchAll();
@@ -790,6 +796,91 @@ public class PowerManagerServiceTest {
        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
    }

    @SuppressWarnings("GuardedBy")
    @Test
    public void testAmbientSuppression_disablesDreamingAndWakesDevice() {
        Settings.Secure.putInt(mContextSpy.getContentResolver(),
                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
        Settings.Secure.putInt(mContextSpy.getContentResolver(),
                Settings.Secure.SCREENSAVER_ENABLED, 1);

        setDreamsDisabledByAmbientModeSuppressionConfig(true);
        setMinimumScreenOffTimeoutConfig(10000);
        createService();
        startSystem();

        doAnswer(inv -> {
            when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
            return null;
        }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());

        setPluggedIn(true);
        // Allow asynchronous sandman calls to execute.
        advanceTime(10000);

        forceDream();
        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
        mService.getBinderServiceInstance().suppressAmbientDisplay("test", true);
        advanceTime(50);
        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
    }

    @SuppressWarnings("GuardedBy")
    @Test
    public void testAmbientSuppressionDisabled_shouldNotWakeDevice() {
        Settings.Secure.putInt(mContextSpy.getContentResolver(),
                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
        Settings.Secure.putInt(mContextSpy.getContentResolver(),
                Settings.Secure.SCREENSAVER_ENABLED, 1);

        setDreamsDisabledByAmbientModeSuppressionConfig(false);
        setMinimumScreenOffTimeoutConfig(10000);
        createService();
        startSystem();

        doAnswer(inv -> {
            when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
            return null;
        }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());

        setPluggedIn(true);
        // Allow asynchronous sandman calls to execute.
        advanceTime(10000);

        forceDream();
        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
        mService.getBinderServiceInstance().suppressAmbientDisplay("test", true);
        advanceTime(50);
        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
    }

    @Test
    public void testAmbientSuppression_doesNotAffectDreamForcing() {
        Settings.Secure.putInt(mContextSpy.getContentResolver(),
                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
        Settings.Secure.putInt(mContextSpy.getContentResolver(),
                Settings.Secure.SCREENSAVER_ENABLED, 1);

        setDreamsDisabledByAmbientModeSuppressionConfig(true);
        setMinimumScreenOffTimeoutConfig(10000);
        createService();
        startSystem();

        doAnswer(inv -> {
            when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
            return null;
        }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());

        mService.getBinderServiceInstance().suppressAmbientDisplay("test", true);
        setPluggedIn(true);
        // Allow asynchronous sandman calls to execute.
        advanceTime(10000);

        // Verify that forcing dream still works even though ambient display is suppressed
        forceDream();
        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
    }

    @Test
    public void testSetDozeOverrideFromDreamManager_triggersSuspendBlocker() {
        final String suspendBlockerName = "PowerManagerService.Display";