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

Commit 2b923ce4 authored by jackqdyulei's avatar jackqdyulei
Browse files

Smear screen power usage based on activity time.

Bug: 38328636
Test: RunSettingsRoboTests
Change-Id: I8e7baadcd88a8e9d674f5bc8d8e42e0f3953c98a
parent d6aa9f34
Loading
Loading
Loading
Loading
+56 −6
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@ import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.SparseLongArray;

import com.android.internal.os.BatterySipper;
import com.android.settings.overlay.FeatureFactory;
@@ -115,25 +117,63 @@ public class BatteryUtils {
    }

    /**
     * Remove the {@link BatterySipper} that we should hide.
     * Remove the {@link BatterySipper} that we should hide and smear the screen usage based on
     * foreground activity time.
     *
     * @param sippers sipper list that need to check and remove
     * @return the total power of the hidden items of {@link BatterySipper}
     * for proportional smearing
     */
    public double removeHiddenBatterySippers(List<BatterySipper> sippers) {
        double totalPowerMah = 0;
        double proportionalSmearPowerMah = 0;
        BatterySipper screenSipper = null;
        for (int i = sippers.size() - 1; i >= 0; i--) {
            final BatterySipper sipper = sippers.get(i);
            if (shouldHideSipper(sipper)) {
                sippers.remove(i);
                if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED) {
                    // Don't add it if it is overcounted
                    totalPowerMah += sipper.totalPowerMah;
                if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED
                        && sipper.drainType != BatterySipper.DrainType.SCREEN) {
                    // Don't add it if it is overcounted or screen
                    proportionalSmearPowerMah += sipper.totalPowerMah;
                }
            }

            if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
                screenSipper = sipper;
            }
        }

        return totalPowerMah;
        smearScreenBatterySipper(sippers, screenSipper);

        return proportionalSmearPowerMah;
    }

    /**
     * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
     * time.
     */
    @VisibleForTesting
    void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) {
        final long rawRealtimeMs = SystemClock.elapsedRealtime();
        long totalActivityTimeMs = 0;
        final SparseLongArray activityTimeArray = new SparseLongArray();
        for (int i = 0, size = sippers.size(); i < size; i++) {
            final BatteryStats.Uid uid = sippers.get(i).uidObj;
            if (uid != null) {
                final long timeMs = getForegroundActivityTotalTimeMs(uid, rawRealtimeMs);
                activityTimeArray.put(uid.getUid(), timeMs);
                totalActivityTimeMs += timeMs;
            }
        }

        if (totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) {
            final double screenPowerMah = screenSipper.totalPowerMah;
            for (int i = 0, size = sippers.size(); i < size; i++) {
                final BatterySipper sipper = sippers.get(i);
                sipper.totalPowerMah += screenPowerMah * activityTimeArray.get(sipper.getUid(), 0)
                        / totalActivityTimeMs;
            }
        }
    }

    /**
@@ -186,5 +226,15 @@ public class BatteryUtils {
        return mPackageManager == null;
    }

    @VisibleForTesting
    long getForegroundActivityTotalTimeMs(BatteryStats.Uid uid, long rawRealtimeMs) {
        final BatteryStats.Timer timer = uid.getForegroundActivityTimer();
        if (timer != null) {
            return timer.getTotalTimeLocked(rawRealtimeMs, BatteryStats.STATS_SINCE_CHARGED);
        }

        return 0;
    }

}
+5 −1
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ public abstract class PowerUsageBase extends DashboardFragment

        mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
        mBatteryBroadcastReceiver.setBatteryChangedListener(() -> {
            getLoaderManager().restartLoader(0, null, this);
            restartBatteryStatsLoader();
        });

        getLoaderManager().initLoader(0, icicle, this);
@@ -95,6 +95,10 @@ public abstract class PowerUsageBase extends DashboardFragment
        }
    }

    protected void restartBatteryStatsLoader() {
        getLoaderManager().restartLoader(0, Bundle.EMPTY, this);
    }

    protected abstract void refreshUi();

    protected void updatePreference(BatteryHistoryPreference historyPref) {
+1 −1
Original line number Diff line number Diff line
@@ -287,7 +287,7 @@ public class PowerUsageSummary extends PowerUsageBase {
                item.setTitle(mShowAllApps ? R.string.hide_extra_apps : R.string.show_all_apps);
                metricsFeatureProvider.action(context,
                        MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE, mShowAllApps);
                refreshUi();
                restartBatteryStatsLoader();
                return true;
            default:
                return super.onOptionsItemSelected(item);
+49 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
import android.content.Context;
import android.os.BatteryStats;
import android.os.Process;
import android.text.format.DateUtils;

import com.android.internal.os.BatterySipper;
import com.android.settings.SettingsRobolectricTestRunner;
@@ -47,8 +48,11 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.spy;

@@ -62,6 +66,8 @@ public class BatteryUtilsTest {
    private static final long TIME_STATE_TOP_SLEEPING = 2500 * UNIT;
    private static final long TIME_STATE_FOREGROUND = 3000 * UNIT;
    private static final long TIME_STATE_BACKGROUND = 6000 * UNIT;
    private static final long TIME_FOREGROUND_ACTIVITY_ZERO = 0;
    private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS;

    private static final int UID = 123;
    private static final long TIME_EXPECTED_FOREGROUND = 1500;
@@ -71,6 +77,7 @@ public class BatteryUtilsTest {
    private static final double BATTERY_SYSTEM_USAGE = 600;
    private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
    private static final double BATTERY_UNACCOUNTED_USAGE = 700;
    private static final double BATTERY_APP_USAGE = 100;
    private static final double TOTAL_BATTERY_USAGE = 1000;
    private static final double HIDDEN_USAGE = 200;
    private static final int DISCHARGE_AMOUNT = 80;
@@ -180,11 +187,13 @@ public class BatteryUtilsTest {
        sippers.add(mUnaccountedBatterySipper);
        when(mProvider.isTypeSystem(mSystemBatterySipper))
                .thenReturn(true);
        doNothing().when(mBatteryUtils).smearScreenBatterySipper(any(), any());

        final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers);

        assertThat(sippers).containsExactly(mNormalBatterySipper);
        assertThat(totalUsage).isWithin(PRECISION).of(
                BATTERY_SCREEN_USAGE + BATTERY_SYSTEM_USAGE + BATTERY_UNACCOUNTED_USAGE);
                BATTERY_SYSTEM_USAGE + BATTERY_UNACCOUNTED_USAGE);
    }

    @Test
@@ -259,4 +268,43 @@ public class BatteryUtilsTest {
                HIDDEN_USAGE, DISCHARGE_AMOUNT))
                .isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE);
    }

    @Test
    public void testSmearScreenBatterySipper() {
        final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
                BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */);
        final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
                BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */);
        final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY,
                BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);

        final List<BatterySipper> sippers = new ArrayList<>();
        sippers.add(sipperNull);
        sippers.add(sipperBg);
        sippers.add(sipperFg);

        mBatteryUtils.smearScreenBatterySipper(sippers, mScreenBatterySipper);

        assertThat(sipperNull.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
        assertThat(sipperBg.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
        assertThat(sipperFg.totalPowerMah).isWithin(PRECISION).of(
                BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE);
    }

    private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
            int uidCode, boolean isUidNull) {
        final BatterySipper sipper = mock(BatterySipper.class);
        sipper.drainType = BatterySipper.DrainType.APP;
        sipper.totalPowerMah = totalPowerMah;
        doReturn(uidCode).when(sipper).getUid();
        if (!isUidNull) {
            final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
            doReturn(activityTime).when(mBatteryUtils).getForegroundActivityTotalTimeMs(eq(uid),
                    anyLong());
            doReturn(uidCode).when(uid).getUid();
            sipper.uidObj = uid;
        }

        return sipper;
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -165,6 +166,7 @@ public class PowerUsageSummaryTest {
        mFragment.initFeatureProvider();
        mBatteryMeterView = spy(new BatteryMeterView(mRealContext));
        mBatteryMeterView.mDrawable = new BatteryMeterView.BatteryMeterDrawable(mRealContext, 0);
        doNothing().when(mFragment).restartBatteryStatsLoader();

        when(mFragment.getActivity()).thenReturn(mSettingsActivity);
        when(mAdditionalBatteryInfoMenu.getItemId())