Loading core/java/android/widget/AnalogClock.java +47 −23 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import java.time.Duration; import java.time.Instant; import java.time.LocalTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Formatter; import java.util.Locale; Loading Loading @@ -451,7 +452,9 @@ public class AnalogClock extends View { if (mSecondHandTintInfo.mHasTintList || mSecondHandTintInfo.mHasTintBlendMode) { mSecondHand = mSecondHandTintInfo.apply(mSecondHand); } mSecondsTick.run(); // Re-run the tick runnable immediately as the presence or absence of a seconds hand affects // the next time we need to tick the clock. mTick.run(); mChanged = true; invalidate(); Loading Loading @@ -583,10 +586,10 @@ public class AnalogClock extends View { filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); // OK, this is gross but needed. This class is supported by the // remote views machanism and as a part of that the remote views // remote views mechanism and as a part of that the remote views // can be inflated by a context for another user without the app // having interact users permission - just for loading resources. // For exmaple, when adding widgets from a user profile to the // For example, when adding widgets from a user profile to the // home screen. Therefore, we register the receiver as the current // user not the one the context is for. getContext().registerReceiverAsUser(mIntentReceiver, Loading Loading @@ -616,14 +619,14 @@ public class AnalogClock extends View { private void onVisible() { if (!mVisible) { mVisible = true; mSecondsTick.run(); mTick.run(); } } private void onInvisible() { if (mVisible) { removeCallbacks(mSecondsTick); removeCallbacks(mTick); mVisible = false; } } Loading Loading @@ -760,6 +763,7 @@ public class AnalogClock extends View { } } /** Intent receiver for the time or time zone changing. */ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -767,23 +771,40 @@ public class AnalogClock extends View { createClock(); } onTimeChanged(); invalidate(); mTick.run(); } }; private boolean mReceiverAttached; private final Runnable mSecondsTick = new Runnable() { private final Runnable mTick = new Runnable() { @Override public void run() { removeCallbacks(this); if (!mVisible || mSecondHand == null) { if (!mVisible) { return; } Instant now = mClock.instant(); LocalTime localTime = now.atZone(mClock.getZone()).toLocalTime(); ZonedDateTime zonedDateTime = now.atZone(mClock.getZone()); LocalTime localTime = zonedDateTime.toLocalTime(); long millisUntilNextTick; if (mSecondHand == null) { // If there's no second hand, then tick at the start of the next minute. // // This must be done with ZonedDateTime as opposed to LocalDateTime to ensure proper // handling of DST. Also note that because of leap seconds, it should not be assumed // that one minute == 60 seconds. Instant startOfNextMinute = zonedDateTime.plusMinutes(1).withSecond(0).toInstant(); millisUntilNextTick = Duration.between(now, startOfNextMinute).toMillis(); if (millisUntilNextTick <= 0) { // This should never occur, but if it does, then just check the tick again in // one minute to ensure we're always moving forward. millisUntilNextTick = Duration.ofMinutes(1).toMillis(); } } else { // If there is a seconds hand, then determine the next tick point based on the fps. // // How many milliseconds through the second we currently are. long millisOfSecond = Duration.ofNanos(localTime.getNano()).toMillis(); // How many milliseconds there are between tick positions for the seconds hand. Loading @@ -791,12 +812,15 @@ public class AnalogClock extends View { // How many milliseconds we are past the last tick position. long millisPastLastTick = Math.round(millisOfSecond % millisPerTick); // How many milliseconds there are until the next tick position. long millisUntilNextTick = Math.round(millisPerTick - millisPastLastTick); // If we are exactly at the tick position, this could be 0 milliseconds due to rounding. // In this case, advance by the full amount of millis to the next position. millisUntilNextTick = Math.round(millisPerTick - millisPastLastTick); // If we are exactly at the tick position, this could be 0 milliseconds due to // rounding. In this case, advance by the full amount of millis to the next // position. if (millisUntilNextTick <= 0) { millisUntilNextTick = Math.round(millisPerTick); } } // Schedule a callback for when the next tick should occur. postDelayed(this, millisUntilNextTick); Loading Loading
core/java/android/widget/AnalogClock.java +47 −23 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import java.time.Duration; import java.time.Instant; import java.time.LocalTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Formatter; import java.util.Locale; Loading Loading @@ -451,7 +452,9 @@ public class AnalogClock extends View { if (mSecondHandTintInfo.mHasTintList || mSecondHandTintInfo.mHasTintBlendMode) { mSecondHand = mSecondHandTintInfo.apply(mSecondHand); } mSecondsTick.run(); // Re-run the tick runnable immediately as the presence or absence of a seconds hand affects // the next time we need to tick the clock. mTick.run(); mChanged = true; invalidate(); Loading Loading @@ -583,10 +586,10 @@ public class AnalogClock extends View { filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); // OK, this is gross but needed. This class is supported by the // remote views machanism and as a part of that the remote views // remote views mechanism and as a part of that the remote views // can be inflated by a context for another user without the app // having interact users permission - just for loading resources. // For exmaple, when adding widgets from a user profile to the // For example, when adding widgets from a user profile to the // home screen. Therefore, we register the receiver as the current // user not the one the context is for. getContext().registerReceiverAsUser(mIntentReceiver, Loading Loading @@ -616,14 +619,14 @@ public class AnalogClock extends View { private void onVisible() { if (!mVisible) { mVisible = true; mSecondsTick.run(); mTick.run(); } } private void onInvisible() { if (mVisible) { removeCallbacks(mSecondsTick); removeCallbacks(mTick); mVisible = false; } } Loading Loading @@ -760,6 +763,7 @@ public class AnalogClock extends View { } } /** Intent receiver for the time or time zone changing. */ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -767,23 +771,40 @@ public class AnalogClock extends View { createClock(); } onTimeChanged(); invalidate(); mTick.run(); } }; private boolean mReceiverAttached; private final Runnable mSecondsTick = new Runnable() { private final Runnable mTick = new Runnable() { @Override public void run() { removeCallbacks(this); if (!mVisible || mSecondHand == null) { if (!mVisible) { return; } Instant now = mClock.instant(); LocalTime localTime = now.atZone(mClock.getZone()).toLocalTime(); ZonedDateTime zonedDateTime = now.atZone(mClock.getZone()); LocalTime localTime = zonedDateTime.toLocalTime(); long millisUntilNextTick; if (mSecondHand == null) { // If there's no second hand, then tick at the start of the next minute. // // This must be done with ZonedDateTime as opposed to LocalDateTime to ensure proper // handling of DST. Also note that because of leap seconds, it should not be assumed // that one minute == 60 seconds. Instant startOfNextMinute = zonedDateTime.plusMinutes(1).withSecond(0).toInstant(); millisUntilNextTick = Duration.between(now, startOfNextMinute).toMillis(); if (millisUntilNextTick <= 0) { // This should never occur, but if it does, then just check the tick again in // one minute to ensure we're always moving forward. millisUntilNextTick = Duration.ofMinutes(1).toMillis(); } } else { // If there is a seconds hand, then determine the next tick point based on the fps. // // How many milliseconds through the second we currently are. long millisOfSecond = Duration.ofNanos(localTime.getNano()).toMillis(); // How many milliseconds there are between tick positions for the seconds hand. Loading @@ -791,12 +812,15 @@ public class AnalogClock extends View { // How many milliseconds we are past the last tick position. long millisPastLastTick = Math.round(millisOfSecond % millisPerTick); // How many milliseconds there are until the next tick position. long millisUntilNextTick = Math.round(millisPerTick - millisPastLastTick); // If we are exactly at the tick position, this could be 0 milliseconds due to rounding. // In this case, advance by the full amount of millis to the next position. millisUntilNextTick = Math.round(millisPerTick - millisPastLastTick); // If we are exactly at the tick position, this could be 0 milliseconds due to // rounding. In this case, advance by the full amount of millis to the next // position. if (millisUntilNextTick <= 0) { millisUntilNextTick = Math.round(millisPerTick); } } // Schedule a callback for when the next tick should occur. postDelayed(this, millisUntilNextTick); Loading