diff options
-rw-r--r-- | core/java/android/widget/AnalogClock.java | 38 | ||||
-rw-r--r-- | core/java/android/widget/DateTimeView.java | 125 |
2 files changed, 92 insertions, 71 deletions
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 339947ac8d5a..67a70b48b534 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -26,12 +26,14 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.text.format.DateUtils; -import android.text.format.Time; import android.util.AttributeSet; import android.view.View; import android.widget.RemoteViews.RemoteView; -import java.util.TimeZone; +import java.time.Clock; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; /** * This widget display an analogic clock with two hands for hours and @@ -45,7 +47,7 @@ import java.util.TimeZone; @RemoteView @Deprecated public class AnalogClock extends View { - private Time mCalendar; + private Clock mClock; @UnsupportedAppUsage private Drawable mHourHand; @@ -99,7 +101,7 @@ public class AnalogClock extends View { mMinuteHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_minute); } - mCalendar = new Time(); + mClock = Clock.systemDefaultZone(); mDialWidth = mDial.getIntrinsicWidth(); mDialHeight = mDial.getIntrinsicHeight(); @@ -132,7 +134,7 @@ public class AnalogClock extends View { // in the main thread, therefore the receiver can't run before this method returns. // The time zone may have changed while the receiver wasn't registered, so update the Time - mCalendar = new Time(); + mClock = Clock.systemDefaultZone(); // Make sure we update to the current time onTimeChanged(); @@ -241,17 +243,18 @@ public class AnalogClock extends View { } private void onTimeChanged() { - mCalendar.setToNow(); + long nowMillis = mClock.millis(); + LocalDateTime localDateTime = toLocalDateTime(nowMillis, mClock.getZone()); - int hour = mCalendar.hour; - int minute = mCalendar.minute; - int second = mCalendar.second; + int hour = localDateTime.getHour(); + int minute = localDateTime.getMinute(); + int second = localDateTime.getSecond(); mMinutes = minute + second / 60.0f; mHour = hour + mMinutes / 60.0f; mChanged = true; - updateContentDescription(mCalendar); + updateContentDescription(nowMillis); } private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @@ -259,7 +262,7 @@ public class AnalogClock extends View { public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) { String tz = intent.getStringExtra("time-zone"); - mCalendar = new Time(TimeZone.getTimeZone(tz).getID()); + mClock = Clock.system(ZoneId.of(tz)); } onTimeChanged(); @@ -268,10 +271,17 @@ public class AnalogClock extends View { } }; - private void updateContentDescription(Time time) { + private void updateContentDescription(long timeMillis) { final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR; - String contentDescription = DateUtils.formatDateTime(mContext, - time.toMillis(false), flags); + String contentDescription = DateUtils.formatDateTime(mContext, timeMillis, flags); setContentDescription(contentDescription); } + + private static LocalDateTime toLocalDateTime(long timeMillis, ZoneId zoneId) { + // java.time types like LocalDateTime / Instant can support the full range of "long millis" + // with room to spare so we do not need to worry about overflow / underflow and the + // resulting exceptions while the input to this class is a long. + Instant instant = Instant.ofEpochMilli(timeMillis); + return LocalDateTime.ofInstant(instant, zoneId); + } } diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java index 0469dbd00dc9..2864ad0b7932 100644 --- a/core/java/android/widget/DateTimeView.java +++ b/core/java/android/widget/DateTimeView.java @@ -20,7 +20,6 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.YEAR_IN_MILLIS; -import static android.text.format.Time.getJulianDay; import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; @@ -32,7 +31,6 @@ import android.content.res.Configuration; import android.content.res.TypedArray; import android.database.ContentObserver; import android.os.Handler; -import android.text.format.Time; import android.util.AttributeSet; import android.view.accessibility.AccessibilityNodeInfo; import android.view.inspector.InspectableProperty; @@ -41,10 +39,14 @@ import android.widget.RemoteViews.RemoteView; import com.android.internal.R; import java.text.DateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.temporal.JulianFields; import java.util.ArrayList; -import java.util.Calendar; import java.util.Date; -import java.util.TimeZone; // // TODO @@ -63,8 +65,9 @@ public class DateTimeView extends TextView { private static final int SHOW_TIME = 0; private static final int SHOW_MONTH_DAY_YEAR = 1; - Date mTime; - long mTimeMillis; + private long mTimeMillis; + // The LocalDateTime equivalent of mTimeMillis but truncated to minute, i.e. no seconds / nanos. + private LocalDateTime mLocalTime; int mLastDisplay = -1; DateFormat mLastFormat; @@ -128,11 +131,10 @@ public class DateTimeView extends TextView { @android.view.RemotableViewMethod @UnsupportedAppUsage - public void setTime(long time) { - Time t = new Time(); - t.set(time); - mTimeMillis = t.toMillis(false); - mTime = new Date(t.year-1900, t.month, t.monthDay, t.hour, t.minute, 0); + public void setTime(long timeMillis) { + mTimeMillis = timeMillis; + LocalDateTime dateTime = toLocalDateTime(timeMillis, ZoneId.systemDefault()); + mLocalTime = dateTime.withSecond(0); update(); } @@ -165,7 +167,7 @@ public class DateTimeView extends TextView { @UnsupportedAppUsage void update() { - if (mTime == null || getVisibility() == GONE) { + if (mLocalTime == null || getVisibility() == GONE) { return; } if (mShowRelativeTime) { @@ -174,31 +176,27 @@ public class DateTimeView extends TextView { } int display; - Date time = mTime; - - Time t = new Time(); - t.set(mTimeMillis); - t.second = 0; - - t.hour -= 12; - long twelveHoursBefore = t.toMillis(false); - t.hour += 12; - long twelveHoursAfter = t.toMillis(false); - t.hour = 0; - t.minute = 0; - long midnightBefore = t.toMillis(false); - t.monthDay++; - long midnightAfter = t.toMillis(false); - - long nowMillis = System.currentTimeMillis(); - t.set(nowMillis); - t.second = 0; - nowMillis = t.normalize(false); + ZoneId zoneId = ZoneId.systemDefault(); + + // localTime is the local time for mTimeMillis but at zero seconds past the minute. + LocalDateTime localTime = mLocalTime; + LocalDateTime localStartOfDay = + LocalDateTime.of(localTime.toLocalDate(), LocalTime.MIDNIGHT); + LocalDateTime localTomorrowStartOfDay = localStartOfDay.plusDays(1); + // now is current local time but at zero seconds past the minute. + LocalDateTime localNow = LocalDateTime.now(zoneId).withSecond(0); + + long twelveHoursBefore = toEpochMillis(localTime.minusHours(12), zoneId); + long twelveHoursAfter = toEpochMillis(localTime.plusHours(12), zoneId); + long midnightBefore = toEpochMillis(localStartOfDay, zoneId); + long midnightAfter = toEpochMillis(localTomorrowStartOfDay, zoneId); + long time = toEpochMillis(localTime, zoneId); + long now = toEpochMillis(localNow, zoneId); // Choose the display mode choose_display: { - if ((nowMillis >= midnightBefore && nowMillis < midnightAfter) - || (nowMillis >= twelveHoursBefore && nowMillis < twelveHoursAfter)) { + if ((now >= midnightBefore && now < midnightAfter) + || (now >= twelveHoursBefore && now < twelveHoursAfter)) { display = SHOW_TIME; break choose_display; } @@ -227,7 +225,7 @@ public class DateTimeView extends TextView { } // Set the text - String text = format.format(mTime); + String text = format.format(new Date(time)); setText(text); // Schedule the next update @@ -236,7 +234,7 @@ public class DateTimeView extends TextView { mUpdateTimeMillis = twelveHoursAfter > midnightAfter ? twelveHoursAfter : midnightAfter; } else { // Currently showing the date - if (mTimeMillis < nowMillis) { + if (mTimeMillis < now) { // If the time is in the past, don't schedule an update mUpdateTimeMillis = 0; } else { @@ -277,15 +275,18 @@ public class DateTimeView extends TextView { millisIncrease = HOUR_IN_MILLIS; } else if (duration < YEAR_IN_MILLIS) { // In weird cases it can become 0 because of daylight savings - TimeZone timeZone = TimeZone.getDefault(); - count = Math.max(Math.abs(dayDistance(timeZone, mTimeMillis, now)), 1); + LocalDateTime localDateTime = mLocalTime; + ZoneId zoneId = ZoneId.systemDefault(); + LocalDateTime localNow = toLocalDateTime(now, zoneId); + + count = Math.max(Math.abs(dayDistance(localDateTime, localNow)), 1); result = String.format(getContext().getResources().getQuantityString(past ? com.android.internal.R.plurals.duration_days_shortest : com.android.internal.R.plurals.duration_days_shortest_future, count), count); if (past || count != 1) { - mUpdateTimeMillis = computeNextMidnight(timeZone); + mUpdateTimeMillis = computeNextMidnight(localNow, zoneId); millisIncrease = -1; } else { millisIncrease = DAY_IN_MILLIS; @@ -311,18 +312,13 @@ public class DateTimeView extends TextView { } /** - * @param timeZone the timezone we are in - * @return the timepoint in millis at UTC at midnight in the current timezone + * Returns the epoch millis for the next midnight in the specified timezone. */ - private long computeNextMidnight(TimeZone timeZone) { - Calendar c = Calendar.getInstance(); - c.setTimeZone(timeZone); - c.add(Calendar.DAY_OF_MONTH, 1); - c.set(Calendar.HOUR_OF_DAY, 0); - c.set(Calendar.MINUTE, 0); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - return c.getTimeInMillis(); + private static long computeNextMidnight(LocalDateTime time, ZoneId zoneId) { + // This ignores the chance of overflow: it should never happen. + LocalDate tomorrow = time.toLocalDate().plusDays(1); + LocalDateTime nextMidnight = LocalDateTime.of(tomorrow, LocalTime.MIDNIGHT); + return toEpochMillis(nextMidnight, zoneId); } @Override @@ -340,11 +336,10 @@ public class DateTimeView extends TextView { com.android.internal.R.string.now_string_shortest); } - // Return the date difference for the two times in a given timezone. - private static int dayDistance(TimeZone timeZone, long startTime, - long endTime) { - return getJulianDay(endTime, timeZone.getOffset(endTime) / 1000) - - getJulianDay(startTime, timeZone.getOffset(startTime) / 1000); + // Return the number of days between the two dates. + private static int dayDistance(LocalDateTime start, LocalDateTime end) { + return (int) (end.getLong(JulianFields.JULIAN_DAY) + - start.getLong(JulianFields.JULIAN_DAY)); } private DateFormat getTimeFormat() { @@ -389,8 +384,11 @@ public class DateTimeView extends TextView { count); } else if (duration < YEAR_IN_MILLIS) { // In weird cases it can become 0 because of daylight savings - TimeZone timeZone = TimeZone.getDefault(); - count = Math.max(Math.abs(dayDistance(timeZone, mTimeMillis, now)), 1); + LocalDateTime localDateTime = mLocalTime; + ZoneId zoneId = ZoneId.systemDefault(); + LocalDateTime localNow = toLocalDateTime(now, zoneId); + + count = Math.max(Math.abs(dayDistance(localDateTime, localNow)), 1); result = String.format(getContext().getResources().getQuantityString(past ? com.android.internal. R.plurals.duration_days_relative @@ -526,4 +524,17 @@ public class DateTimeView extends TextView { } } } + + private static LocalDateTime toLocalDateTime(long timeMillis, ZoneId zoneId) { + // java.time types like LocalDateTime / Instant can support the full range of "long millis" + // with room to spare so we do not need to worry about overflow / underflow and the rsulting + // exceptions while the input to this class is a long. + Instant instant = Instant.ofEpochMilli(timeMillis); + return LocalDateTime.ofInstant(instant, zoneId); + } + + private static long toEpochMillis(LocalDateTime time, ZoneId zoneId) { + Instant instant = time.toInstant(zoneId.getRules().getOffset(time)); + return instant.toEpochMilli(); + } } |