From 45be6bae05f1e20d207a761f03ce67a37653afa5 Mon Sep 17 00:00:00 2001 From: Kuan Wang Date: Thu, 20 Oct 2022 17:07:01 +0800 Subject: [PATCH] Listen ACTION_BATTERY_LEVEL_CHANGED in Settings and fetch usage data when battery is full charged. Bug: 253395332 Test: make RunSettingsRoboTests + manually Change-Id: Ie83e5f319074ff404a600c4eb375fbecad651b6d --- AndroidManifest.xml | 2 +- .../BatteryUsageBroadcastReceiver.java | 34 +++++++++-- .../fuelgauge/batteryusage/DatabaseUtils.java | 12 ++-- .../BatteryUsageBroadcastReceiverTest.java | 60 ++++++++++++++++--- 4 files changed, 87 insertions(+), 21 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d89f05c7991..5d713b02126 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2978,7 +2978,7 @@ - + diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java index 5d8757d7134..a9e3c1d4a1a 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java @@ -20,20 +20,24 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Build; +import android.os.SystemClock; import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.android.settingslib.fuelgauge.BatteryStatus; + +import java.time.Duration; + /** A {@link BatteryUsageBroadcastReceiver} for battery usage data requesting. */ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "BatteryUsageBroadcastReceiver"; - /** An intent action to request Settings to fetch usage data. */ - public static final String ACTION_FETCH_BATTERY_USAGE_DATA = - "com.android.settings.battery.action.FETCH_BATTERY_USAGE_DATA"; /** An intent action to request Settings to clear cache data. */ public static final String ACTION_CLEAR_BATTERY_CACHE_DATA = "com.android.settings.battery.action.CLEAR_BATTERY_CACHE_DATA"; + @VisibleForTesting + static long sBroadcastDelayFromBoot = Duration.ofMinutes(40).toMillis(); @VisibleForTesting static boolean sIsDebugMode = Build.TYPE.equals("userdebug"); @@ -47,9 +51,8 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver { } Log.d(TAG, "onReceive:" + intent.getAction()); switch (intent.getAction()) { - case ACTION_FETCH_BATTERY_USAGE_DATA: - mFetchBatteryUsageData = true; - BatteryUsageDataLoader.enqueueWork(context); + case Intent.ACTION_BATTERY_LEVEL_CHANGED: + tryToFetchUsageData(context); break; case ACTION_CLEAR_BATTERY_CACHE_DATA: if (sIsDebugMode) { @@ -59,4 +62,23 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver { break; } } + + private void tryToFetchUsageData(Context context) { + final Intent batteryIntent = DatabaseUtils.getBatteryIntent(context); + // Returns when battery is not fully charged. + if (!BatteryStatus.isCharged(batteryIntent)) { + return; + } + + final long broadcastDelay = sBroadcastDelayFromBoot - SystemClock.elapsedRealtime(); + // If current boot time is smaller than expected delay, cancel sending the broadcast. + if (broadcastDelay > 0) { + Log.d(TAG, "cancel sendBroadcastToFetchUsageData when broadcastDelay is" + + broadcastDelay + "ms."); + return; + } + + mFetchBatteryUsageData = true; + BatteryUsageDataLoader.enqueueWork(context); + } } diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java index 394c154dc2b..29e0b0e70d4 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java +++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java @@ -141,6 +141,12 @@ public final class DatabaseUtils { }); } + /** Gets the latest sticky battery intent from framework. */ + static Intent getBatteryIntent(Context context) { + return context.registerReceiver( + /*receiver=*/ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + } + static List sendBatteryEntryData( Context context, List batteryEntryList, @@ -300,12 +306,6 @@ public final class DatabaseUtils { return resultMap; } - /** Gets the latest sticky battery intent from framework. */ - private static Intent getBatteryIntent(Context context) { - return context.registerReceiver( - /*receiver=*/ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - } - private static int getBatteryLevel(Intent intent) { final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); final int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java index 51b22124561..513dfdfed83 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java @@ -18,12 +18,16 @@ package com.android.settings.fuelgauge.batteryusage; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.os.BatteryManager; +import android.os.SystemClock; +import android.text.format.DateUtils; import org.junit.Before; import org.junit.Test; @@ -49,14 +53,6 @@ public final class BatteryUsageBroadcastReceiverTest { doReturn(mPackageManager).when(mContext).getPackageManager(); } - @Test - public void onReceive_fetchUsageDataIntent_startService() { - mBatteryUsageBroadcastReceiver.onReceive(mContext, - new Intent(BatteryUsageBroadcastReceiver.ACTION_FETCH_BATTERY_USAGE_DATA)); - - assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isTrue(); - } - @Test public void onReceive_invalidIntent_notStartService() { mBatteryUsageBroadcastReceiver.onReceive(mContext, new Intent("invalid intent")); @@ -64,6 +60,47 @@ public final class BatteryUsageBroadcastReceiverTest { assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); } + @Test + public void onReceive_actionBatteryLevelChanged_notFetchUsageData_notFullCharged() { + doReturn(getBatteryIntent(/*level=*/ 20, BatteryManager.BATTERY_STATUS_UNKNOWN)) + .when(mContext).registerReceiver(any(), any()); + + mBatteryUsageBroadcastReceiver.onReceive(mContext, + new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED)); + + assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + } + + @Test + public void onReceive_actionBatteryLevelChanged_cancelFetchUsageData() { + // Make sure isCharged returns true. + doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_FULL)) + .when(mContext).registerReceiver(any(), any()); + // Make sure broadcast will be sent with delay. + BatteryUsageBroadcastReceiver.sBroadcastDelayFromBoot = + SystemClock.elapsedRealtime() + 5 * DateUtils.MINUTE_IN_MILLIS; + + mBatteryUsageBroadcastReceiver.onReceive(mContext, + new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED)); + + assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + } + + @Test + public void onReceive_actionBatteryLevelChanged_notFetchUsageData() { + // Make sure isCharged returns true. + doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_UNKNOWN)) + .when(mContext).registerReceiver(any(), any()); + BatteryUsageBroadcastReceiver.sBroadcastDelayFromBoot = + SystemClock.elapsedRealtime() - 5 * DateUtils.MINUTE_IN_MILLIS; + + mBatteryUsageBroadcastReceiver.onReceive(mContext, + new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED)); + + assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isTrue(); + } + + @Test public void onReceive_clearCacheIntentInDebugMode_clearBatteryCacheData() { BatteryUsageBroadcastReceiver.sIsDebugMode = true; @@ -91,4 +128,11 @@ public final class BatteryUsageBroadcastReceiverTest { assertThat(BatteryDiffEntry.sValidForRestriction).isNotEmpty(); } + + private static Intent getBatteryIntent(int level, int status) { + final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); + intent.putExtra(BatteryManager.EXTRA_LEVEL, level); + intent.putExtra(BatteryManager.EXTRA_STATUS, status); + return intent; + } }