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

Commit d2f03eaa authored by Marcelo Arteiro's avatar Marcelo Arteiro Committed by Android (Google) Code Review
Browse files

Merge "Fixes Auto and Custom Dark Modes" into main

parents beb30485 e644a779
Loading
Loading
Loading
Loading
+34 −26
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.app.UiModeManager.ContrastUtils.CONTRAST_DEFAULT_VALUE;
import static android.app.UiModeManager.DEFAULT_PRIORITY;
import static android.app.UiModeManager.FORCE_INVERT_TYPE_DARK;
import static android.app.UiModeManager.FORCE_INVERT_TYPE_OFF;
import static android.app.UiModeManager.MODE_ATTENTION_THEME_OVERLAY_NIGHT;
import static android.app.UiModeManager.MODE_ATTENTION_THEME_OVERLAY_OFF;
import static android.app.UiModeManager.MODE_NIGHT_AUTO;
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
@@ -98,9 +99,10 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;

import androidx.annotation.VisibleForTesting;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.DisableCarModeActivity;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -482,6 +484,11 @@ final class UiModeManagerService extends SystemService {
        mCurrentUser = currentUserId;
    }

    @VisibleForTesting
    Boolean[] getNightModeOverrides() {
        return new Boolean[]{mOverrideNightModeOn, mOverrideNightModeOff};
    }

    @Override
    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
        mCurrentUser = to.getUserIdentifier();
@@ -1590,6 +1597,9 @@ final class UiModeManagerService extends SystemService {
    private void onCustomTimeUpdated(int user) {
        persistNightMode(user);
        if (mNightMode.get() != MODE_NIGHT_CUSTOM) return;

        synchronized (mLock) {
            resetNightModeOverrideLocked();
            if (shouldApplyAutomaticChangesImmediately()) {
                unregisterDeviceInactiveListenerLocked();
                updateLocked(0, 0);
@@ -1597,6 +1607,7 @@ final class UiModeManagerService extends SystemService {
                registerDeviceInactiveListenerLocked();
            }
        }
    }

    void dumpImpl(PrintWriter pw) {
        synchronized (mLock) {
@@ -1865,6 +1876,8 @@ final class UiModeManagerService extends SystemService {
            unregisterTimeChangeEvent();
        }

        updateForceInvertStates();

        // Override night mode in power save mode if not in car mode
        if (mPowerSave && !mCarModeEnabled && !mCar) {
            uiMode &= ~Configuration.UI_MODE_NIGHT_NO;
@@ -2192,26 +2205,21 @@ final class UiModeManagerService extends SystemService {
    }

    private void updateComputedNightModeLocked(boolean activate) {
        boolean newComputedValue = activate;
        boolean appliedOverrides = false;
        if (mNightMode.get() != MODE_NIGHT_YES && mNightMode.get() != UiModeManager.MODE_NIGHT_NO) {
            if (mOverrideNightModeOn && !newComputedValue) {
                newComputedValue = true;
            } else if (mOverrideNightModeOff && newComputedValue) {
                newComputedValue = false;
            }
            appliedOverrides = true;
        }

        // Computes final night mode values based on Attention Mode.
        mComputedNightMode = switch (mAttentionModeThemeOverlay) {
            case (UiModeManager.MODE_ATTENTION_THEME_OVERLAY_NIGHT) -> true;
            case (UiModeManager.MODE_ATTENTION_THEME_OVERLAY_DAY) -> false;
            default -> newComputedValue; // case OFF
        };
        updateForceInvertStates();
        mComputedNightMode = activate;

        if (appliedOverrides) {
        if (mAttentionModeThemeOverlay != MODE_ATTENTION_THEME_OVERLAY_OFF) {
            mComputedNightMode = mAttentionModeThemeOverlay == MODE_ATTENTION_THEME_OVERLAY_NIGHT;
            return;
        }
        if (mNightMode.get() == MODE_NIGHT_YES || mNightMode.get() == UiModeManager.MODE_NIGHT_NO) {
            return;
        }
        if (mOverrideNightModeOn && !mComputedNightMode) {
            mComputedNightMode = true;
            return;
        }
        if (mOverrideNightModeOff && mComputedNightMode) {
            mComputedNightMode = false;
            return;
        }

@@ -2455,7 +2463,7 @@ final class UiModeManagerService extends SystemService {
        }
    }

    @VisibleForTesting
    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
    public static class Injector {
        public int getCallingUid() {
            return Binder.getCallingUid();
+56 −0
Original line number Diff line number Diff line
@@ -913,6 +913,62 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
                .setExact(anyInt(), anyLong(), anyString(), any(), any());
    }

    @Test
    public void customTime_clearsOverrides_whenOverrideOnIsSet() throws RemoteException {
        when(mPowerManager.isInteractive()).thenReturn(false);

        mService.setNightMode(MODE_NIGHT_CUSTOM);
        LocalTime scheduleStart = LocalTime.now().plusHours(2);
        LocalTime scheduleEnd = LocalTime.now().plusHours(3);
        mService.setCustomNightModeStart(scheduleStart.toNanoOfDay() / 1000);
        mService.setCustomNightModeEnd(scheduleEnd.toNanoOfDay() / 1000);
        assertThat(isNightModeActivated()).isFalse();

        mService.setNightModeActivated(true);

        //Verify override is set and night mode is ON due to override
        Boolean[] overrides = mUiManagerService.getNightModeOverrides();
        assertThat(overrides[0]).isTrue();  // mOverrideNightModeOn
        assertThat(overrides[1]).isFalse(); // mOverrideNightModeOff
        assertThat(isNightModeActivated()).isTrue(); // Night mode is ON due to override

        LocalTime newStartTime = LocalTime.now().plusHours(1);
        mService.setCustomNightModeStart(newStartTime.toNanoOfDay() / 1000);

        // Verify overrides are cleared
        overrides = mUiManagerService.getNightModeOverrides();
        assertThat(overrides[0]).isFalse(); // mOverrideNightModeOn should be cleared
        assertThat(overrides[1]).isFalse(); // mOverrideNightModeOff should be cleared
    }

    @Test
    public void customTime_clearsOverrides_whenOverrideOffIsSet() throws RemoteException {
        when(mPowerManager.isInteractive()).thenReturn(false);

        mService.setNightMode(MODE_NIGHT_CUSTOM);
        LocalTime scheduleStart = LocalTime.now().minusHours(2);
        LocalTime scheduleEnd = LocalTime.now().plusHours(3);
        mService.setCustomNightModeStart(scheduleStart.toNanoOfDay() / 1000);
        mService.setCustomNightModeEnd(scheduleEnd.toNanoOfDay() / 1000);
        assertThat(isNightModeActivated()).isTrue();

        mService.setNightModeActivated(false);

        //Verify override is set and night mode is OFF due to override
        Boolean[] overrides = mUiManagerService.getNightModeOverrides();
        assertThat(overrides[0]).isFalse();  // mOverrideNightModeOn
        assertThat(overrides[1]).isTrue(); // mOverrideNightModeOff
        assertThat(isNightModeActivated()).isFalse(); // Night mode is ON due to override

        LocalTime newEndTime = LocalTime.now().plusHours(1);
        mService.setCustomNightModeStart(newEndTime.toNanoOfDay() / 1000);

        // Verify overrides are cleared
        overrides = mUiManagerService.getNightModeOverrides();
        assertThat(overrides[0]).isFalse(); // mOverrideNightModeOn should be cleared
        assertThat(overrides[1]).isFalse(); // mOverrideNightModeOff should be cleared
    }

    @Test
    public void customTime_alarmSetInTheFutureWhenOn() throws RemoteException {
        LocalDateTime now = LocalDateTime.now();