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

Commit 1cdb151e authored by Christine Franks's avatar Christine Franks Committed by android-build-merger
Browse files

Merge "Handle night display state when timezone changes" into oc-mr1-dev

am: 1276f357

Change-Id: I96cc0161eb092f2a965efbff4a417bc992493625
parents 3ac60cbb 1276f357
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -5243,7 +5243,6 @@ com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
com.android.internal.app.NightDisplayController
com.android.internal.app.NightDisplayController$Callback
com.android.internal.app.NightDisplayController$LocalTime
com.android.internal.app.ProcessMap
com.android.internal.app.ResolverActivity
com.android.internal.app.ToolbarActionBar
+0 −1
Original line number Diff line number Diff line
@@ -2784,7 +2784,6 @@ com.android.internal.app.IVoiceInteractionManagerService$Stub
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
com.android.internal.app.NightDisplayController
com.android.internal.app.NightDisplayController$1
com.android.internal.appwidget.IAppWidgetService
com.android.internal.appwidget.IAppWidgetService$Stub
com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
+3 −2
Original line number Diff line number Diff line
@@ -6945,8 +6945,9 @@ public final class Settings {
        public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";

        /**
         * Time in milliseconds (since epoch) when Night display was last activated. Use to decide
         * whether to apply the current activated state after a reboot or user change.
         * A String representing the LocalDateTime when Night display was last activated. Use to
         * decide whether to apply the current activated state after a reboot or user change. In
         * legacy cases, this is represented by the time in milliseconds (since epoch).
         * @hide
         */
        public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME =
+31 −119
Original line number Diff line number Diff line
@@ -32,8 +32,12 @@ import com.android.internal.R;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Calendar;
import java.util.Locale;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeParseException;

/**
 * Controller for managing Night display settings.
@@ -116,8 +120,9 @@ public final class NightDisplayController {
     */
    public boolean setActivated(boolean activated) {
        if (isActivated() != activated) {
            Secure.putLongForUser(mContext.getContentResolver(),
                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, System.currentTimeMillis(),
            Secure.putStringForUser(mContext.getContentResolver(),
                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
                    LocalDateTime.now().toString(),
                    mUserId);
        }
        return Secure.putIntForUser(mContext.getContentResolver(),
@@ -128,17 +133,22 @@ public final class NightDisplayController {
     * Returns the time when Night display's activation state last changed, or {@code null} if it
     * has never been changed.
     */
    public Calendar getLastActivatedTime() {
    public LocalDateTime getLastActivatedTime() {
        final ContentResolver cr = mContext.getContentResolver();
        final long lastActivatedTimeMillis = Secure.getLongForUser(
                cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1, mUserId);
        if (lastActivatedTimeMillis < 0) {
            return null;
        final String lastActivatedTime = Secure.getStringForUser(
                cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, mUserId);
        if (lastActivatedTime != null) {
            try {
                return LocalDateTime.parse(lastActivatedTime);
            } catch (DateTimeParseException ignored) {}
            // Uses the old epoch time.
            try {
                return LocalDateTime.ofInstant(
                    Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
                    ZoneId.systemDefault());
            } catch (DateTimeException|NumberFormatException ignored) {}
        }

        final Calendar lastActivatedTime = Calendar.getInstance();
        lastActivatedTime.setTimeInMillis(lastActivatedTimeMillis);
        return lastActivatedTime;
        return null;
    }

    /**
@@ -183,8 +193,10 @@ public final class NightDisplayController {
        }

        if (getAutoMode() != autoMode) {
            Secure.putLongForUser(mContext.getContentResolver(),
                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1L, mUserId);
            Secure.putStringForUser(mContext.getContentResolver(),
                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
                    null,
                    mUserId);
        }
        return Secure.putIntForUser(mContext.getContentResolver(),
                Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
@@ -206,7 +218,7 @@ public final class NightDisplayController {
                    R.integer.config_defaultNightDisplayCustomStartTime);
        }

        return LocalTime.valueOf(startTimeValue);
        return LocalTime.ofSecondOfDay(startTimeValue / 1000);
    }

    /**
@@ -221,7 +233,7 @@ public final class NightDisplayController {
            throw new IllegalArgumentException("startTime cannot be null");
        }
        return Secure.putIntForUser(mContext.getContentResolver(),
                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toMillis(), mUserId);
                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toSecondOfDay() * 1000, mUserId);
    }

    /**
@@ -240,7 +252,7 @@ public final class NightDisplayController {
                    R.integer.config_defaultNightDisplayCustomEndTime);
        }

        return LocalTime.valueOf(endTimeValue);
        return LocalTime.ofSecondOfDay(endTimeValue / 1000);
    }

    /**
@@ -255,7 +267,7 @@ public final class NightDisplayController {
            throw new IllegalArgumentException("endTime cannot be null");
        }
        return Secure.putIntForUser(mContext.getContentResolver(),
                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toMillis(), mUserId);
                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toSecondOfDay() * 1000, mUserId);
    }

    /**
@@ -378,106 +390,6 @@ public final class NightDisplayController {
        return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
    }

    /**
     * A time without a time-zone or date.
     */
    public static class LocalTime {

        /**
         * The hour of the day from 0 - 23.
         */
        public final int hourOfDay;
        /**
         * The minute within the hour from 0 - 59.
         */
        public final int minute;

        public LocalTime(int hourOfDay, int minute) {
            if (hourOfDay < 0 || hourOfDay > 23) {
                throw new IllegalArgumentException("Invalid hourOfDay: " + hourOfDay);
            } else if (minute < 0 || minute > 59) {
                throw new IllegalArgumentException("Invalid minute: " + minute);
            }

            this.hourOfDay = hourOfDay;
            this.minute = minute;
        }

        /**
         * Returns the first date time corresponding to this local time that occurs before the
         * provided date time.
         *
         * @param time the date time to compare against
         * @return the prior date time corresponding to this local time
         */
        public Calendar getDateTimeBefore(Calendar time) {
            final Calendar c = Calendar.getInstance();
            c.set(Calendar.YEAR, time.get(Calendar.YEAR));
            c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));

            c.set(Calendar.HOUR_OF_DAY, hourOfDay);
            c.set(Calendar.MINUTE, minute);
            c.set(Calendar.SECOND, 0);
            c.set(Calendar.MILLISECOND, 0);

            // Check if the local time has past, if so return the same time tomorrow.
            if (c.after(time)) {
                c.add(Calendar.DATE, -1);
            }

            return c;
        }

        /**
         * Returns the first date time corresponding to this local time that occurs after the
         * provided date time.
         *
         * @param time the date time to compare against
         * @return the next date time corresponding to this local time
         */
        public Calendar getDateTimeAfter(Calendar time) {
            final Calendar c = Calendar.getInstance();
            c.set(Calendar.YEAR, time.get(Calendar.YEAR));
            c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));

            c.set(Calendar.HOUR_OF_DAY, hourOfDay);
            c.set(Calendar.MINUTE, minute);
            c.set(Calendar.SECOND, 0);
            c.set(Calendar.MILLISECOND, 0);

            // Check if the local time has past, if so return the same time tomorrow.
            if (c.before(time)) {
                c.add(Calendar.DATE, 1);
            }

            return c;
        }

        /**
         * Returns a local time corresponding the given number of milliseconds from midnight.
         *
         * @param millis the number of milliseconds from midnight
         * @return the corresponding local time
         */
        private static LocalTime valueOf(int millis) {
            final int hourOfDay = (millis / 3600000) % 24;
            final int minutes = (millis / 60000) % 60;
            return new LocalTime(hourOfDay, minutes);
        }

        /**
         * Returns the local time represented as milliseconds from midnight.
         */
        private int toMillis() {
            return hourOfDay * 3600000 + minute * 60000;
        }

        @Override
        public String toString() {
            return String.format(Locale.US, "%02d:%02d", hourOfDay, minute);
        }
    }

    /**
     * Callback invoked whenever the Night display settings are changed.
     */
+59 −42
Original line number Diff line number Diff line
@@ -48,8 +48,10 @@ import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.Calendar;
import java.util.TimeZone;

import com.android.internal.R;
@@ -308,7 +310,7 @@ public final class NightDisplayService extends SystemService
    }

    @Override
    public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
    public void onCustomStartTimeChanged(LocalTime startTime) {
        Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);

        if (mAutoMode != null) {
@@ -317,7 +319,7 @@ public final class NightDisplayService extends SystemService
    }

    @Override
    public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
    public void onCustomEndTimeChanged(LocalTime endTime) {
        Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);

        if (mAutoMode != null) {
@@ -416,6 +418,36 @@ public final class NightDisplayService extends SystemService
        outTemp[10] = blue;
    }

    /**
     * Returns the first date time corresponding to the local time that occurs before the
     * provided date time.
     *
     * @param compareTime the LocalDateTime to compare against
     * @return the prior LocalDateTime corresponding to this local time
     */
    public static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) {
        final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
                compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());

        // Check if the local time has passed, if so return the same time yesterday.
        return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt;
    }

    /**
     * Returns the first date time corresponding to this local time that occurs after the
     * provided date time.
     *
     * @param compareTime the LocalDateTime to compare against
     * @return the next LocalDateTime corresponding to this local time
     */
    public static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) {
        final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
                compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());

        // Check if the local time has passed, if so return the same time tomorrow.
        return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
    }

    private abstract class AutoMode implements NightDisplayController.Callback {
        public abstract void onStart();

@@ -427,10 +459,10 @@ public final class NightDisplayService extends SystemService
        private final AlarmManager mAlarmManager;
        private final BroadcastReceiver mTimeChangedReceiver;

        private NightDisplayController.LocalTime mStartTime;
        private NightDisplayController.LocalTime mEndTime;
        private LocalTime mStartTime;
        private LocalTime mEndTime;

        private Calendar mLastActivatedTime;
        private LocalDateTime mLastActivatedTime;

        CustomAutoMode() {
            mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
@@ -443,31 +475,15 @@ public final class NightDisplayService extends SystemService
        }

        private void updateActivated() {
            final Calendar now = Calendar.getInstance();
            final Calendar startTime = mStartTime.getDateTimeBefore(now);
            final Calendar endTime = mEndTime.getDateTimeAfter(startTime);
            final LocalDateTime now = LocalDateTime.now();
            final LocalDateTime start = getDateTimeBefore(mStartTime, now);
            final LocalDateTime end = getDateTimeAfter(mEndTime, start);
            boolean activate = now.isBefore(end);

            boolean activate = now.before(endTime);
            if (mLastActivatedTime != null) {
                // Convert mLastActivatedTime to the current timezone if needed.
                final TimeZone currentTimeZone = now.getTimeZone();
                if (!currentTimeZone.equals(mLastActivatedTime.getTimeZone())) {
                    final int year = mLastActivatedTime.get(Calendar.YEAR);
                    final int dayOfYear = mLastActivatedTime.get(Calendar.DAY_OF_YEAR);
                    final int hourOfDay = mLastActivatedTime.get(Calendar.HOUR_OF_DAY);
                    final int minute = mLastActivatedTime.get(Calendar.MINUTE);

                    mLastActivatedTime.setTimeZone(currentTimeZone);
                    mLastActivatedTime.set(Calendar.YEAR, year);
                    mLastActivatedTime.set(Calendar.DAY_OF_YEAR, dayOfYear);
                    mLastActivatedTime.set(Calendar.HOUR_OF_DAY, hourOfDay);
                    mLastActivatedTime.set(Calendar.MINUTE, minute);
                }

                // Maintain the existing activated state if within the current period.
                if (mLastActivatedTime.before(now)
                        && mLastActivatedTime.after(startTime)
                        && (mLastActivatedTime.after(endTime) || now.before(endTime))) {
                if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
                        && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
                    activate = mController.isActivated();
                }
            }
@@ -475,14 +491,16 @@ public final class NightDisplayService extends SystemService
            if (mIsActivated == null || mIsActivated != activate) {
                mController.setActivated(activate);
            }

            updateNextAlarm(mIsActivated, now);
        }

        private void updateNextAlarm(@Nullable Boolean activated, @NonNull Calendar now) {
        private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
            if (activated != null) {
                final Calendar next = activated ? mEndTime.getDateTimeAfter(now)
                        : mStartTime.getDateTimeAfter(now);
                mAlarmManager.setExact(AlarmManager.RTC, next.getTimeInMillis(), TAG, this, null);
                final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now)
                        : getDateTimeAfter(mStartTime, now);
                final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null);
            }
        }

@@ -512,18 +530,18 @@ public final class NightDisplayService extends SystemService
        @Override
        public void onActivated(boolean activated) {
            mLastActivatedTime = mController.getLastActivatedTime();
            updateNextAlarm(activated, Calendar.getInstance());
            updateNextAlarm(activated, LocalDateTime.now());
        }

        @Override
        public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
        public void onCustomStartTimeChanged(LocalTime startTime) {
            mStartTime = startTime;
            mLastActivatedTime = null;
            updateActivated();
        }

        @Override
        public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
        public void onCustomEndTimeChanged(LocalTime endTime) {
            mEndTime = endTime;
            mLastActivatedTime = null;
            updateActivated();
@@ -552,15 +570,14 @@ public final class NightDisplayService extends SystemService
            }

            boolean activate = state.isNight();
            final Calendar lastActivatedTime = mController.getLastActivatedTime();
            final LocalDateTime lastActivatedTime = mController.getLastActivatedTime();
            if (lastActivatedTime != null) {
                final Calendar now = Calendar.getInstance();
                final Calendar sunrise = state.sunrise();
                final Calendar sunset = state.sunset();

                final LocalDateTime now = LocalDateTime.now();
                final LocalDateTime sunrise = state.sunrise();
                final LocalDateTime sunset = state.sunset();
                // Maintain the existing activated state if within the current period.
                if (lastActivatedTime.before(now)
                        && (lastActivatedTime.after(sunrise) ^ lastActivatedTime.after(sunset))) {
                if (lastActivatedTime.isBefore(now) && (lastActivatedTime.isBefore(sunrise)
                        ^ lastActivatedTime.isBefore(sunset))) {
                    activate = mController.isActivated();
                }
            }
Loading