TwilightService v2.0

- Switched to using CalendarAstronomer for more accurate sunrise/sunset
  times.
- Exposed sunrise/sunset times via TwilightState so that clients can
  track the current twilight period and perform their own
  interpolations.
- Adopted LocationRequest API for fused location updates:
  (low power, min 1h, max 10m).
- TwilightService is now only activated when a listener is registered,
  minimizing impact to system health on platforms / configurations
  where twilight state is not needed.

Bug: 28588307
Bug: 30190450
Bug: 30282370
Bug: 30650316
Change-Id: Ic5c94d8608e8bb3a3d895e623676a1468d4abdcd
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index 39498a6..d9af7cb 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.TypeEvaluator;
 import android.animation.ValueAnimator;
+import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -217,12 +218,12 @@
         if (mIsActivated == null || mIsActivated != activated) {
             Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
 
-            mIsActivated = activated;
-
             if (mAutoMode != null) {
                 mAutoMode.onActivated(activated);
             }
 
+            mIsActivated = activated;
+
             // Cancel the old animator if still running.
             if (mColorMatrixAnimator != null) {
                 mColorMatrixAnimator.cancel();
@@ -395,7 +396,9 @@
 
         @Override
         public void onActivated(boolean activated) {
-            mLastActivatedTime = Calendar.getInstance();
+            if (mIsActivated != null) {
+                mLastActivatedTime = Calendar.getInstance();
+            }
             updateNextAlarm();
         }
 
@@ -424,22 +427,30 @@
 
         private final TwilightManager mTwilightManager;
 
-        private boolean mIsNight;
+        private Calendar mLastActivatedTime;
 
         public TwilightAutoMode() {
             mTwilightManager = getLocalService(TwilightManager.class);
         }
 
-        private void updateActivated() {
-            final TwilightState state = mTwilightManager.getCurrentState();
+        private void updateActivated(TwilightState state) {
             final boolean isNight = state != null && state.isNight();
-            if (mIsNight != isNight) {
-                mIsNight = isNight;
-
-                if (mIsActivated == null || mIsActivated != isNight) {
-                    mController.setActivated(isNight);
+            boolean setActivated = mIsActivated == null || mIsActivated != isNight;
+            if (setActivated && state != null && mLastActivatedTime != null) {
+                final Calendar sunrise = state.sunrise();
+                final Calendar sunset = state.sunset();
+                if (sunrise.before(sunset)) {
+                    setActivated = mLastActivatedTime.before(sunrise)
+                            || mLastActivatedTime.after(sunset);
+                } else {
+                    setActivated = mLastActivatedTime.before(sunset)
+                            || mLastActivatedTime.after(sunrise);
                 }
             }
+
+            if (setActivated) {
+                mController.setActivated(isNight);
+            }
         }
 
         @Override
@@ -447,18 +458,26 @@
             mTwilightManager.registerListener(this, mHandler);
 
             // Force an update to initialize state.
-            updateActivated();
+            updateActivated(mTwilightManager.getLastTwilightState());
         }
 
         @Override
         public void onStop() {
             mTwilightManager.unregisterListener(this);
+            mLastActivatedTime = null;
         }
 
         @Override
-        public void onTwilightStateChanged() {
+        public void onActivated(boolean activated) {
+            if (mIsActivated != null) {
+                mLastActivatedTime = Calendar.getInstance();
+            }
+        }
+
+        @Override
+        public void onTwilightStateChanged(@Nullable TwilightState state) {
             if (DEBUG) Slog.d(TAG, "onTwilightStateChanged");
-            updateActivated();
+            updateActivated(state);
         }
     }