diff --git a/AndroidManifest.xml b/AndroidManifest.xml index eed87ed49ef..0fb6dc81334 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3051,11 +3051,12 @@ android:exported="false" android:authorities="${applicationId}.battery.usage.bugreport"/> - + diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index c151517d6b4..66e09a9cc3b 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -133,10 +133,15 @@ public interface PowerUsageFeatureProvider { boolean delayHourlyJobWhenBooting(); /** - * Gets a intent for one time bypass charge limited to resume charging. + * Gets an intent for one time bypass charge limited to resume charging. */ Intent getResumeChargeIntent(boolean isDockDefender); + /** + * Returns the intent action used to mark as the full charge start event. + */ + String getFullChargeIntentAction(); + /** * Returns {@link Set} for the system component ids which are combined into others */ diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index 657e5c6018b..e0af88a694e 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -147,6 +147,11 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider return null; } + @Override + public String getFullChargeIntentAction() { + return Intent.ACTION_BATTERY_LEVEL_CHANGED; + } + @Override public boolean isExtraDefend() { return false; diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java index 817d367ca11..9c7ec35fb4a 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java @@ -26,6 +26,7 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.fuelgauge.BatteryUtils; +import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.fuelgauge.BatteryStatus; import java.time.Duration; @@ -36,6 +37,9 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver { /** 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"; + /** An intent action to request Settings to clear cache data. */ + public static final String ACTION_BATTERY_UNPLUGGING = + "com.android.settings.battery.action.ACTION_BATTERY_UNPLUGGING"; @VisibleForTesting static long sBroadcastDelayFromBoot = Duration.ofMinutes(40).toMillis(); @@ -51,9 +55,27 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver { return; } Log.d(TAG, "onReceive:" + intent.getAction()); + final String fullChargeIntentAction = FeatureFactory.getFactory(context) + .getPowerUsageFeatureProvider(context) + .getFullChargeIntentAction(); switch (intent.getAction()) { case Intent.ACTION_BATTERY_LEVEL_CHANGED: - tryToFetchUsageData(context); + // Only when fullChargeIntentAction is ACTION_BATTERY_LEVEL_CHANGED, + // ACTION_BATTERY_LEVEL_CHANGED will be considered as the full charge event and then + // start usage events fetching. + if (Intent.ACTION_BATTERY_LEVEL_CHANGED.equals(fullChargeIntentAction)) { + Log.d(TAG, "fetch data because of event: ACTION_BATTERY_LEVEL_CHANGED"); + tryToFetchUsageData(context); + } + break; + case ACTION_BATTERY_UNPLUGGING: + // Only when fullChargeIntentAction is ACTION_POWER_DISCONNECTED, + // ACTION_BATTERY_UNPLUGGING will be considered as the full charge event and then + // start usage events fetching. + if (Intent.ACTION_POWER_DISCONNECTED.equals(fullChargeIntentAction)) { + Log.d(TAG, "fetch data because of event: ACTION_POWER_DISCONNECTED"); + tryToFetchUsageData(context); + } break; case ACTION_CLEAR_BATTERY_CACHE_DATA: if (sIsDebugMode) { @@ -74,7 +96,7 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver { 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" + Log.d(TAG, "cancel sendBroadcastToFetchUsageData when broadcastDelay is " + broadcastDelay + "ms."); return; } 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 addfd9bfdb9..60481975429 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java @@ -21,6 +21,7 @@ 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 static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; @@ -29,6 +30,8 @@ import android.os.BatteryManager; import android.os.SystemClock; import android.text.format.DateUtils; +import com.android.settings.testutils.FakeFeatureFactory; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,6 +45,8 @@ public final class BatteryUsageBroadcastReceiverTest { private Context mContext; private BatteryUsageBroadcastReceiver mBatteryUsageBroadcastReceiver; + private FakeFeatureFactory mFakeFeatureFactory; + @Mock private PackageManager mPackageManager; @@ -49,6 +54,7 @@ public final class BatteryUsageBroadcastReceiverTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); + mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mBatteryUsageBroadcastReceiver = new BatteryUsageBroadcastReceiver(); doReturn(mPackageManager).when(mContext).getPackageManager(); } @@ -62,6 +68,8 @@ public final class BatteryUsageBroadcastReceiverTest { @Test public void onReceive_actionBatteryLevelChanged_notFetchUsageData_notFullCharged() { + when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction()) + .thenReturn(Intent.ACTION_BATTERY_LEVEL_CHANGED); doReturn(getBatteryIntent(/*level=*/ 20, BatteryManager.BATTERY_STATUS_UNKNOWN)) .when(mContext).registerReceiver(any(), any()); @@ -72,7 +80,9 @@ public final class BatteryUsageBroadcastReceiverTest { } @Test - public void onReceive_actionBatteryLevelChanged_cancelFetchUsageData() { + public void onReceive_actionBatteryLevelChanged_notFetchUsageData_nearBooting() { + when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction()) + .thenReturn(Intent.ACTION_BATTERY_LEVEL_CHANGED); // Make sure isCharged returns true. doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_FULL)) .when(mContext).registerReceiver(any(), any()); @@ -87,7 +97,25 @@ public final class BatteryUsageBroadcastReceiverTest { } @Test - public void onReceive_actionBatteryLevelChanged_notFetchUsageData() { + public void onReceive_actionBatteryLevelChanged_notFetchUsageData_wrongAction() { + when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction()) + .thenReturn(Intent.ACTION_POWER_DISCONNECTED); + // 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).isFalse(); + } + + @Test + public void onReceive_actionBatteryLevelChanged_fetchUsageData() { + when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction()) + .thenReturn(Intent.ACTION_BATTERY_LEVEL_CHANGED); // Make sure isCharged returns true. doReturn(getBatteryIntent(/*level=*/ 100, BatteryManager.BATTERY_STATUS_UNKNOWN)) .when(mContext).registerReceiver(any(), any()); @@ -100,6 +128,67 @@ public final class BatteryUsageBroadcastReceiverTest { assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isTrue(); } + @Test + public void onReceive_actionBatteryUnplugging_notFetchUsageData_notFullCharged() { + when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction()) + .thenReturn(Intent.ACTION_POWER_DISCONNECTED); + doReturn(getBatteryIntent(/*level=*/ 20, BatteryManager.BATTERY_STATUS_UNKNOWN)) + .when(mContext).registerReceiver(any(), any()); + + mBatteryUsageBroadcastReceiver.onReceive(mContext, + new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING)); + + assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + } + + @Test + public void onReceive_actionBatteryUnplugging_notFetchUsageData_nearBooting() { + when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction()) + .thenReturn(Intent.ACTION_POWER_DISCONNECTED); + // 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(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING)); + + assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + } + + @Test + public void onReceive_actionBatteryUnplugging_notFetchUsageData_wrongAction() { + when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction()) + .thenReturn(Intent.ACTION_BATTERY_LEVEL_CHANGED); + // 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(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING)); + + assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + } + + @Test + public void onReceive_actionBatteryUnplugging_fetchUsageData() { + when(mFakeFeatureFactory.powerUsageFeatureProvider.getFullChargeIntentAction()) + .thenReturn(Intent.ACTION_POWER_DISCONNECTED); + // 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(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING)); + + assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isTrue(); + } @Test public void onReceive_clearCacheIntentInDebugMode_clearBatteryCacheData() {