diff --git a/api/system-current.txt b/api/system-current.txt index b8852692a8e43..30d42a232c8d8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5042,6 +5042,7 @@ package android.nfc { package android.os { public class BatteryManager { + method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setChargingStateUpdateDelayMillis(int); field public static final String EXTRA_EVENTS = "android.os.extra.EVENTS"; field public static final String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP"; } diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 954071a0ee977..3fc5e41ad9903 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -16,6 +16,8 @@ package android.os; +import android.Manifest.permission; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; @@ -369,4 +371,26 @@ public class BatteryManager { throw e.rethrowFromSystemServer(); } } + + /** + * Sets the delay for reporting battery state as charging after device is plugged in. + * This allows machine-learning or heuristics to delay the reporting and the corresponding + * broadcast, based on battery level, charging rate, and/or other parameters. + * + * @param delayMillis the delay in milliseconds, negative value to reset. + * + * @return True if the delay was set successfully. + * + * @see ACTION_CHARGING + * @hide + */ + @RequiresPermission(permission.POWER_SAVER) + @SystemApi + public boolean setChargingStateUpdateDelayMillis(int delayMillis) { + try { + return mBatteryStats.setChargingStateUpdateDelayMillis(delayMillis); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5222fc36710fe..852b65a050343 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -14280,6 +14280,17 @@ public final class Settings { */ public static final String APPOP_HISTORY_PARAMETERS = "appop_history_parameters"; + + /** + * Delay for sending ACTION_CHARGING after device is plugged in. + * This is used as an override for constants defined in BatteryStatsImpl for + * ease of experimentation. + * + * @see com.android.internal.os.BatteryStatsImpl.Constants.KEY_BATTERY_CHARGED_DELAY_MS + * @hide + */ + public static final String BATTERY_CHARGING_STATE_UPDATE_DELAY = + "battery_charging_state_update_delay"; } /** diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 514ff76372a93..d7514d1fe26c2 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -154,4 +154,7 @@ interface IBatteryStats { oneway void noteBluetoothControllerActivity(in BluetoothActivityEnergyInfo info); oneway void noteModemControllerActivity(in ModemActivityInfo info); oneway void noteWifiControllerActivity(in WifiActivityEnergyInfo info); + + /** {@hide} */ + boolean setChargingStateUpdateDelayMillis(int delay); } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 534361e13c7d8..c6afee24cfb50 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -13395,11 +13395,22 @@ public class BatteryStatsImpl extends BatteryStats { mResolver.registerContentObserver( Settings.Global.getUriFor(Settings.Global.BATTERY_STATS_CONSTANTS), false /* notifyForDescendants */, this); + mResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY), + false /* notifyForDescendants */, this); updateConstants(); } @Override public void onChange(boolean selfChange, Uri uri) { + if (uri.equals( + Settings.Global.getUriFor( + Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY))) { + synchronized (BatteryStatsImpl.this) { + updateBatteryChargedDelayMsLocked(); + } + return; + } updateConstants(); } @@ -13443,12 +13454,21 @@ public class BatteryStatsImpl extends BatteryStats { DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB : DEFAULT_MAX_HISTORY_BUFFER_KB) * 1024; - BATTERY_CHARGED_DELAY_MS = mParser.getInt( - KEY_BATTERY_CHARGED_DELAY_MS, - DEFAULT_BATTERY_CHARGED_DELAY_MS); + updateBatteryChargedDelayMsLocked(); } } + private void updateBatteryChargedDelayMsLocked() { + // a negative value indicates that we should ignore this override + final int delay = Settings.Global.getInt(mResolver, + Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY, + -1); + + BATTERY_CHARGED_DELAY_MS = delay >= 0 ? delay : mParser.getInt( + KEY_BATTERY_CHARGED_DELAY_MS, + DEFAULT_BATTERY_CHARGED_DELAY_MS); + } + private void updateTrackCpuTimesByProcStateLocked(boolean wasEnabled, boolean isEnabled) { TRACK_CPU_TIMES_BY_PROC_STATE = isEnabled; if (isEnabled && !wasEnabled) { diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index a15dbc80d7db8..bd7f8527fc6f0 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -131,6 +131,7 @@ public class SettingsBackupTest { Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, Settings.Global.AUTOMATIC_POWER_SAVER_MODE, Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, + Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY, Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD, Settings.Global.BATTERY_DISCHARGE_THRESHOLD, Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS, diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index a376e7a15410e..08900328a200f 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -19,6 +19,7 @@ package com.android.server.am; import android.app.ActivityManager; import android.app.job.JobProtoEnums; import android.bluetooth.BluetoothActivityEnergyInfo; +import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -46,6 +47,7 @@ import android.os.connectivity.WifiBatteryStats; import android.os.health.HealthStatsParceler; import android.os.health.HealthStatsWriter; import android.os.health.UidHealthStats; +import android.provider.Settings; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.ModemActivityInfo; import android.telephony.SignalStrength; @@ -1651,4 +1653,23 @@ public final class BatteryStatsService extends IBatteryStats.Stub return new HealthStatsParceler(uidWriter); } + /** + * Delay for sending ACTION_CHARGING after device is plugged in. + * + * @hide + */ + public boolean setChargingStateUpdateDelayMillis(int delayMillis) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER, null); + final long ident = Binder.clearCallingIdentity(); + + try { + final ContentResolver contentResolver = mContext.getContentResolver(); + return Settings.Global.putLong(contentResolver, + Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY, + delayMillis); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + }