Make Settings and SysUI estimates use same data class

This moves everything over to using a shared data class
for Estimates in SettingsLib which will facilitate a cl
that will help ensure greater consistency across
surfaces where battery estimates are shown.

Test: Tests pass
Bug: 124030091
Change-Id: I0b7f1f3a806255ff4804a00e6d90a7846c484484
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 83dc39e..8581920 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12666,6 +12666,45 @@
         public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
 
         /**
+         * A long value indicating how much longer the system battery is estimated to last in
+         * millis. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value
+         * was updated.
+         *
+         * @hide
+         */
+        public static final String TIME_REMAINING_ESTIMATE_MILLIS =
+                "time_remaining_estimate_millis";
+
+        /**
+         * A boolean indicating whether {@link #TIME_REMAINING_ESTIMATE_MILLIS} is based customized
+         * to the devices usage or using global models. See
+         * {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME} for the last time this value was updated.
+         *
+         * @hide
+         */
+        public static final String TIME_REMAINING_ESTIMATE_BASED_ON_USAGE =
+                "time_remaining_estimate_based_on_usage";
+
+        /**
+         * A long value indicating how long the system battery takes to deplete from 100% to 0% on
+         * average based on historical drain rates. See {@link #BATTERY_ESTIMATES_LAST_UPDATE_TIME}
+         * for the last time this value was updated.
+         *
+         * @hide
+         */
+        public static final String AVERAGE_TIME_TO_DISCHARGE = "average_time_to_discharge";
+
+        /**
+         * A long indicating the epoch time in milliseconds when
+         * {@link #TIME_REMAINING_ESTIMATE_MILLIS}, {@link #TIME_REMAINING_ESTIMATE_BASED_ON_USAGE},
+         * and {@link #AVERAGE_TIME_TO_DISCHARGE} were last updated.
+         *
+         * @hide
+         */
+        public static final String BATTERY_ESTIMATES_LAST_UPDATE_TIME =
+                "battery_estimates_last_update_time";
+
+        /**
          * The max value for {@link #LOW_POWER_MODE_TRIGGER_LEVEL}. If this setting is not set
          * or the value is 0, the default max will be used.
          *
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0e94abc0..cf9a7fc 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -130,8 +130,10 @@
                     Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
                     Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
                     Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
+                    Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
                     Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
                     Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
+                    Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
                     Settings.Global.BROADCAST_BG_CONSTANTS,
                     Settings.Global.BROADCAST_FG_CONSTANTS,
                     Settings.Global.BROADCAST_OFFLOAD_CONSTANTS,
@@ -462,6 +464,8 @@
                     Settings.Global.TEXT_CLASSIFIER_ACTION_MODEL_PARAMS,
                     Settings.Global.THEATER_MODE_ON,
                     Settings.Global.TIME_ONLY_MODE_CONSTANTS,
+                    Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS,
+                    Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE,
                     Settings.Global.TRANSITION_ANIMATION_SCALE,
                     Settings.Global.TRUSTED_SOUND,
                     Settings.Global.TZINFO_UPDATE_CONTENT_URL,
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index fb5c16b..e19ac81 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -37,7 +37,8 @@
     /**
      * When set to "true" the notification will be a generic confirm message instead of asking the
      * user if they want to turn on battery saver. If set to false the dialog will specifically
-     * talk about turning on battery saver and provide a button for taking the action.
+     * talk about battery saver without giving the option of turning it on. The only button visible
+     * will be a generic confirmation button to acknowledge the dialog.
      */
     public static final String EXTRA_CONFIRM_TEXT_ONLY = "extra_confirm_only";
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
new file mode 100644
index 0000000..ae8e1e2
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settingslib.fuelgauge
+
+import android.content.Context
+import android.provider.Settings
+import java.time.Duration
+import java.time.Instant
+
+const val AVERAGE_TIME_TO_DISCHARGE_UNKNOWN = -1
+const val ESTIMATE_MILLIS_UNKNOWN = -1
+
+class Estimate(
+    val estimateMillis: Long,
+    val isBasedOnUsage: Boolean,
+    val averageDischargeTime: Long
+) {
+    companion object {
+        /**
+         * Returns the cached estimate if it is available and fresh. Will return null if estimate is
+         * unavailable or older than 2 minutes.
+         *
+         * @param context A valid context
+         * @return An [Estimate] object with the latest battery estimates.
+         */
+        @JvmStatic
+        fun getCachedEstimateIfAvailable(context: Context): Estimate? {
+            // if time > 2 min return null or the estimate otherwise
+            val resolver = context.contentResolver
+            val lastUpdateTime = Instant.ofEpochMilli(
+                    Settings.Global.getLong(
+                            resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, -1))
+            return if (Duration.between(lastUpdateTime,
+                            Instant.now()).compareTo(Duration.ofMinutes(2)) > 0) {
+                null
+            } else Estimate(
+                    Settings.Global.getLong(resolver,
+                            Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS,
+                            ESTIMATE_MILLIS_UNKNOWN.toLong()),
+                    Settings.Global.getInt(resolver,
+                            Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE, 0) == 1,
+                    Settings.Global.getLong(resolver, Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
+                            AVERAGE_TIME_TO_DISCHARGE_UNKNOWN.toLong()))
+        }
+
+        /**
+         * Stores an estimate to the cache along with a timestamp. Can be obtained via
+         * [.getCachedEstimateIfAvailable].
+         *
+         * @param context A valid context
+         * @param estimate the [Estimate] object to store
+         */
+        @JvmStatic
+        fun storeCachedEstimate(context: Context, estimate: Estimate) {
+            // store the estimate and update the timestamp
+            val resolver = context.contentResolver
+            Settings.Global.putLong(resolver, Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS,
+                    estimate.estimateMillis)
+            Settings.Global.putInt(resolver, Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE,
+                    if (estimate.isBasedOnUsage) 1 else 0)
+            Settings.Global.putLong(resolver, Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
+                    estimate.averageDischargeTime)
+            Settings.Global.putLong(resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
+                    System.currentTimeMillis())
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
index 02ad0f1..f73bc93 100644
--- a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
@@ -15,6 +15,7 @@
     val severeLevelThreshold: Int,
     val lowLevelThreshold: Int,
     val timeRemainingMillis: Long,
+    val averageTimeToDischargeMillis: Long,
     val severeThresholdMillis: Long,
     val lowThresholdMillis: Long,
     val isBasedOnUsage: Boolean,
@@ -39,18 +40,19 @@
         severeLevelThreshold: Int,
         lowLevelThreshold: Int
     ) : this(
-        batteryLevel,
-        isPowerSaver,
-        plugged,
-        bucket,
-        batteryStatus,
-        severeLevelThreshold,
-        lowLevelThreshold,
-        NO_ESTIMATE_AVAILABLE.toLong(),
-        NO_ESTIMATE_AVAILABLE.toLong(),
-        NO_ESTIMATE_AVAILABLE.toLong(),
-        false,
-        true
+            batteryLevel,
+            isPowerSaver,
+            plugged,
+            bucket,
+            batteryStatus,
+            severeLevelThreshold,
+            lowLevelThreshold,
+            NO_ESTIMATE_AVAILABLE.toLong(),
+            NO_ESTIMATE_AVAILABLE.toLong(),
+            NO_ESTIMATE_AVAILABLE.toLong(),
+            NO_ESTIMATE_AVAILABLE.toLong(),
+            false,
+            true
     ) {
         this.isHybrid = false
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
index a879227..3b46478 100644
--- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
@@ -1,5 +1,7 @@
 package com.android.systemui.power;
 
+import com.android.settingslib.fuelgauge.Estimate;
+
 public interface EnhancedEstimates {
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
index bfb809e..9b1f23a 100644
--- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
@@ -1,5 +1,7 @@
 package com.android.systemui.power;
 
+import com.android.settingslib.fuelgauge.Estimate;
+
 public class EnhancedEstimatesImpl implements EnhancedEstimates {
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/power/Estimate.kt b/packages/SystemUI/src/com/android/systemui/power/Estimate.kt
deleted file mode 100644
index dca0d45..0000000
--- a/packages/SystemUI/src/com/android/systemui/power/Estimate.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.android.systemui.power
-
-data class Estimate(val estimateMillis: Long, val isBasedOnUsage: Boolean)
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 25d6d94..b57c053 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -42,6 +42,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -283,6 +284,7 @@
             mCurrentBatteryStateSnapshot = new BatteryStateSnapshot(mBatteryLevel, isPowerSaverMode,
                     plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1],
                     mLowBatteryReminderLevels[0], estimate.getEstimateMillis(),
+                    estimate.getAverageDischargeTime(),
                     mEnhancedEstimates.getSevereWarningThreshold(),
                     mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage(),
                     mEnhancedEstimates.getLowWarningEnabled());
@@ -316,7 +318,8 @@
             return estimate;
         }
         return new Estimate(mLastBatteryStateSnapshot.getTimeRemainingMillis(),
-                mLastBatteryStateSnapshot.isBasedOnUsage());
+                mLastBatteryStateSnapshot.isBasedOnUsage(),
+                mLastBatteryStateSnapshot.getAverageTimeToDischargeMillis());
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 273fa55..fde1455 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -31,10 +31,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.fuelgauge.BatterySaverUtils;
+import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.utils.PowerUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.power.EnhancedEstimates;
-import com.android.systemui.power.Estimate;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 5928a07..161b409 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -40,6 +40,7 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.testing.TestableResources;
 
+import com.android.settingslib.fuelgauge.Estimate;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.power.PowerUI.WarningsUI;
@@ -358,7 +359,7 @@
     @Test
     public void testRefreshEstimateIfNeeded_onlyQueriesEstimateOnBatteryLevelChangeOrNull() {
         mPowerUI.start();
-        Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true);
+        Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true, 0);
         when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
         when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
         when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
@@ -371,21 +372,21 @@
         assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD);
         BatteryStateSnapshot snapshot = new BatteryStateSnapshot(
                 BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD,
-                0, 0, -1, 0, 0, false, true);
+                0, 0, -1, 0, 0, 0, false, true);
         mPowerUI.mLastBatteryStateSnapshot = snapshot;
 
         // query again since the estimate was -1
-        estimate = new Estimate(BELOW_SEVERE_HYBRID_THRESHOLD, true);
+        estimate = new Estimate(BELOW_SEVERE_HYBRID_THRESHOLD, true, 0);
         when(mEnhancedEstimates.getEstimate()).thenReturn(estimate);
         refreshedEstimate = mPowerUI.refreshEstimateIfNeeded();
         assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD);
         snapshot = new BatteryStateSnapshot(
                 BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD, 0,
-                0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, false, true);
+                0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, 0, false, true);
         mPowerUI.mLastBatteryStateSnapshot = snapshot;
 
         // Battery level hasn't changed, so we don't query again
-        estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true);
+        estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true, 0);
         when(mEnhancedEstimates.getEstimate()).thenReturn(estimate);
         refreshedEstimate = mPowerUI.refreshEstimateIfNeeded();
         assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD);
@@ -543,13 +544,14 @@
         public boolean mIsBasedOnUsage = true;
         public boolean mIsHybrid = true;
         public boolean mIsLowLevelWarningEnabled = true;
+        private long mAverageTimeToDischargeMillis = Duration.ofHours(24).toMillis();
 
         public BatteryStateSnapshot get() {
             if (mIsHybrid) {
                 return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
                         mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold,
-                        mTimeRemainingMillis, mSevereThresholdMillis, mLowThresholdMillis,
-                        mIsBasedOnUsage, mIsLowLevelWarningEnabled);
+                        mTimeRemainingMillis, mAverageTimeToDischargeMillis, mSevereThresholdMillis,
+                        mLowThresholdMillis, mIsBasedOnUsage, mIsLowLevelWarningEnabled);
             } else {
                 return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
                         mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold);