From 580098fe44d651fbd81f5aaf14eef4083634406a Mon Sep 17 00:00:00 2001 From: Salvador Martinez Date: Thu, 11 Apr 2019 10:42:15 -0700 Subject: [PATCH] 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 --- core/java/android/provider/Settings.java | 39 +++++++++++ .../src/android/provider/SettingsBackupTest.java | 4 ++ .../settingslib/fuelgauge/BatterySaverUtils.java | 3 +- .../com/android/settingslib/fuelgauge/Estimate.kt | 81 ++++++++++++++++++++++ .../android/systemui/power/BatteryStateSnapshot.kt | 26 +++---- .../android/systemui/power/EnhancedEstimates.java | 2 + .../systemui/power/EnhancedEstimatesImpl.java | 2 + .../src/com/android/systemui/power/Estimate.kt | 3 - .../src/com/android/systemui/power/PowerUI.java | 5 +- .../statusbar/policy/BatteryControllerImpl.java | 2 +- .../com/android/systemui/power/PowerUITest.java | 16 +++-- 11 files changed, 158 insertions(+), 25 deletions(-) create mode 100644 packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/power/Estimate.kt diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 83dc39e94d7a..858192078740 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -12666,6 +12666,45 @@ public final class Settings { 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 0e94abc0dcac..cf9a7fc763a4 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -130,8 +130,10 @@ public class SettingsBackupTest { 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 @@ public class SettingsBackupTest { 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 fb5c16b92930..e19ac815b939 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 @@ public class BatterySaverUtils { /** * 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 000000000000..ae8e1e2a60c0 --- /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 02ad0f1766bd..f73bc93ff313 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 @@ data class BatteryStateSnapshot( 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 @@ data class BatteryStateSnapshot( 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 a87922792616..3b464783d009 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 bfb809ecbf34..9b1f23aa0d0c 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 dca0d45c1c9f..000000000000 --- 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 25d6d940d92e..b57c053964ca 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.Log; 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 @@ public class PowerUI extends SystemUI { 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 @@ public class PowerUI extends SystemUI { 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 273fa55ee9d8..fde1455b0af0 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 androidx.annotation.Nullable; 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 5928a07487d9..161b40979e11 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; 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 @@ public class PowerUITest extends SysuiTestCase { @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 @@ public class PowerUITest extends SysuiTestCase { 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 class PowerUITest extends SysuiTestCase { 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); -- 2.11.0