diff options
| author | 2017-08-25 13:57:26 -0700 | |
|---|---|---|
| committer | 2017-09-20 03:35:49 +0000 | |
| commit | 0321346f38839a332e7c097a1cc80251a13b97c3 (patch) | |
| tree | 318fe2e8248584716ef170b1328c5fff38244b68 | |
| parent | 4b02111abac743e150d07c6ec5d7526dc23032de (diff) | |
Handle night display state when timezone changes
Bug: 64458884
Test: runtest -c com.android.server.NightDisplayServiceTest \
frameworks-services and manually tested Hawaii and London
Change-Id: I052034a4c64eb73c42672215e8847c11e00efeb5
(cherry picked from commit 2ce862c3ed3739c4bb794794fb57e00fe233a3d5)
7 files changed, 132 insertions, 188 deletions
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone index c8297286b784..c1cbb648aae6 100644 --- a/config/compiled-classes-phone +++ b/config/compiled-classes-phone @@ -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 diff --git a/config/preloaded-classes b/config/preloaded-classes index cb3cbe196230..2844efb302de 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -2786,7 +2786,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 diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 40ced6ce4815..a5c55ba74a70 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6966,8 +6966,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 = diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java index 860c5c4c3d3b..7a1383c7a01c 100644 --- a/core/java/com/android/internal/app/NightDisplayController.java +++ b/core/java/com/android/internal/app/NightDisplayController.java @@ -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); } /** @@ -379,106 +391,6 @@ public final class NightDisplayController { } /** - * 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. */ public interface Callback { diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java index aafc6317bfae..9cf136720881 100644 --- a/services/core/java/com/android/server/display/NightDisplayService.java +++ b/services/core/java/com/android/server/display/NightDisplayService.java @@ -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 static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; @@ -306,7 +308,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) { @@ -315,7 +317,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) { @@ -414,6 +416,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(); @@ -425,10 +457,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); @@ -441,31 +473,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(); } } @@ -473,14 +489,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); } } @@ -510,18 +528,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(); @@ -550,15 +568,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(); } } diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java index 30a8cccb6ad5..71304a7a4701 100644 --- a/services/core/java/com/android/server/twilight/TwilightState.java +++ b/services/core/java/com/android/server/twilight/TwilightState.java @@ -18,7 +18,10 @@ package com.android.server.twilight; import android.text.format.DateFormat; -import java.util.Calendar; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.TimeZone; /** * The twilight state, consisting of the sunrise and sunset times (in millis) for the current @@ -45,12 +48,11 @@ public final class TwilightState { } /** - * Returns a new {@link Calendar} instance initialized to {@link #sunriseTimeMillis()}. + * Returns a new {@link LocalDateTime} instance initialized to {@link #sunriseTimeMillis()}. */ - public Calendar sunrise() { - final Calendar sunrise = Calendar.getInstance(); - sunrise.setTimeInMillis(mSunriseTimeMillis); - return sunrise; + public LocalDateTime sunrise() { + final ZoneId zoneId = TimeZone.getDefault().toZoneId(); + return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunriseTimeMillis), zoneId); } /** @@ -62,12 +64,11 @@ public final class TwilightState { } /** - * Returns a new {@link Calendar} instance initialized to {@link #sunsetTimeMillis()}. + * Returns a new {@link LocalDateTime} instance initialized to {@link #sunsetTimeMillis()}. */ - public Calendar sunset() { - final Calendar sunset = Calendar.getInstance(); - sunset.setTimeInMillis(mSunsetTimeMillis); - return sunset; + public LocalDateTime sunset() { + final ZoneId zoneId = TimeZone.getDefault().toZoneId(); + return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunsetTimeMillis), zoneId); } /** diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java index 58a4456ff4d7..3a92d638fb02 100644 --- a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java @@ -30,13 +30,14 @@ import android.support.test.runner.AndroidJUnit4; import android.test.mock.MockContentResolver; import com.android.internal.app.NightDisplayController; -import com.android.internal.app.NightDisplayController.LocalTime; import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.display.DisplayTransformManager; import com.android.server.display.NightDisplayService; 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.ZoneId; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -45,6 +46,7 @@ import org.mockito.Mockito; import java.util.Calendar; import java.util.HashMap; +import java.time.LocalTime; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -926,11 +928,10 @@ public class NightDisplayServiceTest { */ private void setActivated(boolean activated, int lastActivatedTimeOffset) { mNightDisplayController.setActivated(activated); - - final Calendar c = Calendar.getInstance(); - c.add(Calendar.MINUTE, lastActivatedTimeOffset); - Secure.putLongForUser(mContext.getContentResolver(), - Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, c.getTimeInMillis(), mUserId); + Secure.putStringForUser(mContext.getContentResolver(), + Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, + LocalDateTime.now().plusMinutes(lastActivatedTimeOffset).toString(), + mUserId); } /** @@ -969,7 +970,7 @@ public class NightDisplayServiceTest { private static LocalTime getLocalTimeRelativeToNow(int offsetMinutes) { final Calendar c = Calendar.getInstance(); c.add(Calendar.MINUTE, offsetMinutes); - return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)); + return LocalTime.of(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)); } /** @@ -984,13 +985,27 @@ public class NightDisplayServiceTest { final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset); final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset); - final Calendar now = Calendar.getInstance(); - long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis(); - long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis(); + final LocalDateTime now = LocalDateTime.now(); + final ZoneId zoneId = ZoneId.systemDefault(); + + long sunsetMillis = NightDisplayService.getDateTimeBefore(sunset, now) + .atZone(zoneId) + .toInstant() + .toEpochMilli(); + long sunriseMillis = NightDisplayService.getDateTimeBefore(sunrise, now) + .atZone(zoneId) + .toInstant() + .toEpochMilli(); if (sunsetMillis < sunriseMillis) { - sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis(); + sunsetMillis = NightDisplayService.getDateTimeAfter(sunset, now) + .atZone(zoneId) + .toInstant() + .toEpochMilli(); } else { - sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis(); + sunriseMillis = NightDisplayService.getDateTimeAfter(sunrise, now) + .atZone(zoneId) + .toInstant() + .toEpochMilli(); } return new TwilightState(sunriseMillis, sunsetMillis); |