Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45be6bae authored by Kuan Wang's avatar Kuan Wang
Browse files

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
parent 7ef1fb7e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2978,7 +2978,7 @@
        <receiver android:name=".fuelgauge.batteryusage.BatteryUsageBroadcastReceiver"
                  android:exported="true">
            <intent-filter>
                <action android:name="com.android.settings.battery.action.FETCH_BATTERY_USAGE_DATA"/>
                <action android:name="android.intent.action.BATTERY_LEVEL_CHANGED"/>
                <action android:name="com.android.settings.battery.action.CLEAR_BATTERY_CACHE_DATA"/>
            </intent-filter>
        </receiver>
+28 −6
Original line number Diff line number Diff line
@@ -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);
    }
}
+6 −6
Original line number Diff line number Diff line
@@ -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<ContentValues> sendBatteryEntryData(
            Context context,
            List<BatteryEntry> 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);
+49 −5
Original line number Diff line number Diff line
@@ -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;
@@ -50,20 +54,53 @@ public final class BatteryUsageBroadcastReceiverTest {
    }

    @Test
    public void onReceive_fetchUsageDataIntent_startService() {
    public void onReceive_invalidIntent_notStartService() {
        mBatteryUsageBroadcastReceiver.onReceive(mContext, new Intent("invalid intent"));

        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(BatteryUsageBroadcastReceiver.ACTION_FETCH_BATTERY_USAGE_DATA));
                new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED));

        assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isTrue();
        assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse();
    }

    @Test
    public void onReceive_invalidIntent_notStartService() {
        mBatteryUsageBroadcastReceiver.onReceive(mContext, new Intent("invalid intent"));
    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;
    }
}