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

Commit e923b479 authored by Lei Yu's avatar Lei Yu Committed by Android (Google) Code Review
Browse files

Merge "Add battery stats perference in battery settings page."

parents 4cf650b6 39347224
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -4285,8 +4285,17 @@
    <!-- Display time remaining until battery is charged [CHAR_LIMIT=60] -->
    <string name="power_charge_remaining"><xliff:g id="until_charged">%1$s</xliff:g> to charge</string>
    <!-- [CHAR_LIMIT=40] Label for list of apps using battery in power use UI -->
    <string name="power_usage_list_summary">Use since last full charge</string>
    <!-- Title for the screen usage in power use UI [CHAR_LIMIT=40] -->
    <string name="device_screen_usage">Screen usage</string>
    <!-- Title for the screen consumption in power use UI(i.e. Screen consumption: 30% of battery usage) [CHAR_LIMIT=40] -->
    <string name="device_screen_consumption">Screen consumption</string>
    <!-- Title for the cellular network in power use UI(i.e. Mobile network scanning: 30% of battery usage) [CHAR_LIMIT=40] -->
    <string name="device_cellular_network">Mobile network scanning</string>
    <!-- Label for list of apps using battery in power use UI [CHAR_LIMIT=60] -->
    <string name="power_usage_list_summary">App usage since last full charge</string>
    <!-- Label for list of different types using battery in power use UI [CHAR_LIMIT=60] -->
    <string name="device_usage_list_summary">Device usage since last full charge</string>
    <!-- Battery usage since unplugged -->
    <string name="battery_since_unplugged">Battery use since unplugged</string>
    <!-- Battery usage since user reset the stats -->
@@ -4483,6 +4492,8 @@
    <!-- Description for battery usage time for an app, i.e. Used for 30min. [CHAR LIMIT=60] -->
    <string name="battery_used_for">Used for %1$s</string>
    <!-- Description for percentage of battery usage for an app, i.e. Screen: 30% of overall battery. [CHAR LIMIT=60] -->
    <string name="battery_overall_usage">%1$s of overall battery</string>
    <!-- Description for battery usage detail information since last full charge. [CHAR LIMIT=120] -->
    <string name="battery_detail_since_full_charge">Usage breakdown since last full charge</string>
+18 −0
Original line number Diff line number Diff line
@@ -55,4 +55,22 @@
        android:key="app_list"
        android:title="@string/power_usage_list_summary"/>

    <PreferenceCategory
        android:key="device_usage_list"
        android:title="@string/device_usage_list_summary">

        <Preference
            android:key="screen_usage"
            android:title="@string/device_screen_usage"/>

        <Preference
            android:key="screen_consumption"
            android:title="@string/device_screen_consumption"/>

        <Preference
            android:key="cellular_network"
            android:title="@string/device_cellular_network"/>

    </PreferenceCategory>

</PreferenceScreen>
+1 −1
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ public class PowerGaugePreference extends TintablePreference {
    }

    public void setPercent(double percentOfTotal) {
        mProgress = Utils.formatPercentage((int) (percentOfTotal + 0.5));
        mProgress = Utils.formatPercentage(percentOfTotal, true);
        notifyChanged();
    }

+59 −2
Original line number Diff line number Diff line
@@ -78,11 +78,17 @@ public class PowerUsageSummary extends PowerUsageBase {
    private static final boolean USE_FAKE_DATA = false;
    private static final String KEY_APP_LIST = "app_list";
    private static final String KEY_BATTERY_HEADER = "battery_header";

    private static final int MIN_POWER_THRESHOLD_MILLI_AMP = 5;
    private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10;
    private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
    private static final int SECONDS_IN_HOUR = 60 * 60;

    private static final String KEY_SCREEN_USAGE = "screen_usage";
    private static final String KEY_SCREEN_CONSUMPTION = "screen_consumption";
    private static final String KEY_CELLULAR_NETWORK = "cellular_network";


    private static final int MENU_STATS_TYPE = Menu.FIRST;
    private static final int MENU_HIGH_POWER_APPS = Menu.FIRST + 3;
    @VisibleForTesting
@@ -93,6 +99,13 @@ public class PowerUsageSummary extends PowerUsageBase {

    @VisibleForTesting
    boolean mShowAllApps = false;

    Preference mScreenUsagePref;
    @VisibleForTesting
    Preference mScreenConsumptionPref;
    @VisibleForTesting
    Preference mCellularNetworkPref;

    private LayoutPreference mBatteryLayoutPref;
    private PreferenceGroup mAppListGroup;

@@ -105,6 +118,9 @@ public class PowerUsageSummary extends PowerUsageBase {

        mBatteryLayoutPref = (LayoutPreference) findPreference(KEY_BATTERY_HEADER);
        mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
        mScreenUsagePref = findPreference(KEY_SCREEN_USAGE);
        mScreenConsumptionPref = findPreference(KEY_SCREEN_CONSUMPTION);
        mCellularNetworkPref = findPreference(KEY_CELLULAR_NETWORK);
    }

    @Override
@@ -384,6 +400,11 @@ public class PowerUsageSummary extends PowerUsageBase {
        context.getTheme().resolveAttribute(android.R.attr.colorControlNormal, value, true);
        final int colorControl = context.getColor(value.resourceId);
        final String usedTime = context.getString(R.string.battery_used_for);
        final int dischargeAmount = USE_FAKE_DATA ? 5000
                : stats != null ? stats.getDischargeAmount(mStatsType) : 0;

        updateScreenPreference(dischargeAmount);
        updateCellularPreference(dischargeAmount);

        if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP || USE_FAKE_DATA) {
            final List<BatterySipper> usageList = getCoalescedUsageList(
@@ -391,8 +412,6 @@ public class PowerUsageSummary extends PowerUsageBase {

            double hiddenPowerMah = mShowAllApps ? 0 : removeHiddenBatterySippers(usageList);

            final int dischargeAmount = USE_FAKE_DATA ? 5000
                    : stats != null ? stats.getDischargeAmount(mStatsType) : 0;
            final int numSippers = usageList.size();
            for (int i = 0; i < numSippers; i++) {
                final BatterySipper sipper = usageList.get(i);
@@ -478,6 +497,39 @@ public class PowerUsageSummary extends PowerUsageBase {
        BatteryEntry.startRequestQueue();
    }

    @VisibleForTesting
    BatterySipper findBatterySipperByType(List<BatterySipper> usageList, DrainType type) {
        for (int i = 0, size = usageList.size(); i < size; i++) {
            final BatterySipper sipper = usageList.get(i);
            if (sipper.drainType == type) {
                return sipper;
            }
        }
        return null;
    }

    @VisibleForTesting
    void updateScreenPreference(final int dischargeAmount) {
        final BatterySipper sipper = findBatterySipperByType(
                mStatsHelper.getUsageList(), DrainType.SCREEN);
        final Context context = getContext();
        final double percentOfTotal = calculatePercentage(sipper.totalPowerMah, dischargeAmount);

        mScreenUsagePref.setSummary(getString(R.string.battery_used_for,
                Utils.formatElapsedTime(context, sipper.usageTimeMs, false)));
        mScreenConsumptionPref.setSummary(getString(R.string.battery_overall_usage,
                Utils.formatPercentage(percentOfTotal, true)));
    }

    @VisibleForTesting
    void updateCellularPreference(final int dischargeAmount) {
        final BatterySipper sipper = findBatterySipperByType(
                mStatsHelper.getUsageList(), DrainType.CELL);
        final double percentOfTotal = calculatePercentage(sipper.totalPowerMah, dischargeAmount);
        mCellularNetworkPref.setSummary(getString(R.string.battery_overall_usage,
                Utils.formatPercentage(percentOfTotal, true)));
    }

    @VisibleForTesting
    void updateHeaderPreference(BatteryInfo info) {
        final BatteryMeterView batteryView = (BatteryMeterView) mBatteryLayoutPref
@@ -502,6 +554,11 @@ public class PowerUsageSummary extends PowerUsageBase {
        batteryView.setBatteryInfo(info.mBatteryLevel);
    }

    @VisibleForTesting
    double calculatePercentage(double powerUsage, double dischargeAmount) {
        return ((powerUsage / mStatsHelper.getTotalPower()) * dischargeAmount);
    }

    @VisibleForTesting
    void setUsageSummary(Preference preference, String usedTimePrefix, long usageTimeMs) {
        // Only show summary when usage time is longer than one minute
+99 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
import android.content.Context;
import android.content.Intent;
import android.os.Process;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.Menu;
@@ -26,9 +27,12 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.Utils;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.BatteryInfo;
@@ -38,9 +42,8 @@ import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;

import java.util.ArrayList;
import java.util.List;
@@ -49,7 +52,10 @@ import static com.android.settings.fuelgauge.PowerUsageBase.MENU_STATS_REFRESH;
import static com.android.settings.fuelgauge.PowerUsageSummary.MENU_ADDITIONAL_BATTERY_INFO;
import static com.android.settings.fuelgauge.PowerUsageSummary.MENU_TOGGLE_APPS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -59,7 +65,7 @@ import static org.mockito.Mockito.when;
 * Unit tests for {@link PowerUsageSummary}.
 */
// TODO: Improve this test class so that it starts up the real activity and fragment.
@RunWith(RobolectricTestRunner.class)
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class PowerUsageSummaryTest {
    private static final String[] PACKAGE_NAMES = {"com.app1", "com.app2"};
@@ -67,9 +73,13 @@ public class PowerUsageSummaryTest {
    private static final int UID = 123;
    private static final int POWER_MAH = 100;
    private static final long REMAINING_TIME_US = 100000;
    private static final int DISCHARGE_AMOUNT = 100;
    private static final long USAGE_TIME_MS = 10000;
    private static final double TOTAL_POWER = 200;
    private static final double BATTERY_SCREEN_USAGE = 300;
    private static final double BATTERY_SYSTEM_USAGE = 600;
    private static final double PRECISION = 0.001;
    private static final double POWER_USAGE_PERCENTAGE = 50;
    private static final Intent ADDITIONAL_BATTERY_INFO_INTENT =
            new Intent("com.example.app.ADDITIONAL_BATTERY_INFO");

@@ -92,6 +102,8 @@ public class PowerUsageSummaryTest {
    @Mock
    private BatterySipper mSystemBatterySipper;
    @Mock
    private BatterySipper mCellBatterySipper;
    @Mock
    private PowerGaugePreference mPreference;
    @Mock
    private LayoutPreference mBatteryLayoutPref;
@@ -105,15 +117,26 @@ public class PowerUsageSummaryTest {
    private TextView mSummary2;
    @Mock
    private BatteryInfo mBatteryInfo;
    @Mock
    private Preference mScreenUsagePref;
    @Mock
    private Preference mScreenConsumptionPref;
    @Mock
    private Preference mCellularNetworkPref;
    @Mock
    private BatteryStatsHelper mBatteryHelper;

    private Context mRealContext;
    private TestFragment mFragment;
    private FakeFeatureFactory mFeatureFactory;
    private PowerUsageSummary mPowerUsageSummary;
    private List<BatterySipper> mUsageList;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        mRealContext = RuntimeEnvironment.application;
        FakeFeatureFactory.setupForTest(mContext);
        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);

@@ -129,13 +152,19 @@ public class PowerUsageSummaryTest {
        when(mToggleAppsMenu.getItemId()).thenReturn(MENU_TOGGLE_APPS);
        when(mFeatureFactory.powerUsageFeatureProvider.getAdditionalBatteryInfoIntent())
                .thenReturn(ADDITIONAL_BATTERY_INFO_INTENT);
        when(mBatteryHelper.getTotalPower()).thenReturn(TOTAL_POWER);

        mPowerUsageSummary = spy(new PowerUsageSummary());

        when(mPowerUsageSummary.getContext()).thenReturn(mContext);
        when(mPowerUsageSummary.getContext()).thenReturn(mRealContext);
        when(mNormalBatterySipper.getPackages()).thenReturn(PACKAGE_NAMES);
        when(mNormalBatterySipper.getUid()).thenReturn(UID);
        mNormalBatterySipper.totalPowerMah = POWER_MAH;
        mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;

        mCellBatterySipper.drainType = BatterySipper.DrainType.CELL;
        mCellBatterySipper.totalPowerMah = POWER_MAH;

        when(mBatteryLayoutPref.findViewById(R.id.summary1)).thenReturn(mSummary1);
        when(mBatteryLayoutPref.findViewById(R.id.summary2)).thenReturn(mSummary2);
        when(mBatteryLayoutPref.findViewById(R.id.time)).thenReturn(mTimeText);
@@ -145,9 +174,19 @@ public class PowerUsageSummaryTest {

        mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
        mScreenBatterySipper.totalPowerMah = BATTERY_SCREEN_USAGE;
        mScreenBatterySipper.usageTimeMs = USAGE_TIME_MS;

        mSystemBatterySipper.drainType = BatterySipper.DrainType.APP;
        mSystemBatterySipper.totalPowerMah = BATTERY_SYSTEM_USAGE;
        when(mSystemBatterySipper.getUid()).thenReturn(Process.SYSTEM_UID);

        mUsageList = new ArrayList<>();
        mUsageList.add(mNormalBatterySipper);
        mUsageList.add(mScreenBatterySipper);
        mUsageList.add(mCellBatterySipper);

        mPowerUsageSummary.mStatsHelper = mBatteryHelper;
        when(mBatteryHelper.getUsageList()).thenReturn(mUsageList);
    }

    @Test
@@ -326,6 +365,7 @@ public class PowerUsageSummaryTest {
        verify(mSummary1).setText(R.string.estimated_time_left);
    }


    private void testToggleAllApps(final boolean isShowApps) {
        mFragment.mShowAllApps = isShowApps;

@@ -333,6 +373,61 @@ public class PowerUsageSummaryTest {
        assertThat(mFragment.mShowAllApps).isEqualTo(!isShowApps);
    }

    @Test
    public void testFindBatterySipperByType_findTypeScreen() {
        BatterySipper sipper = mPowerUsageSummary.findBatterySipperByType(mUsageList,
                BatterySipper.DrainType.SCREEN);

        assertThat(sipper).isSameAs(mScreenBatterySipper);
    }

    @Test
    public void testFindBatterySipperByType_findTypeApp() {
        BatterySipper sipper = mPowerUsageSummary.findBatterySipperByType(mUsageList,
                BatterySipper.DrainType.APP);

        assertThat(sipper).isSameAs(mNormalBatterySipper);
    }

    @Test
    public void testUpdateCellularPreference_ShowCorrectSummary() {
        mPowerUsageSummary.mCellularNetworkPref = mCellularNetworkPref;
        final double percent = POWER_MAH / TOTAL_POWER * DISCHARGE_AMOUNT;
        final String expectedSummary = mRealContext.getString(R.string.battery_overall_usage,
                Utils.formatPercentage((int) percent));
        doReturn(expectedSummary).when(mPowerUsageSummary)
                .getString(eq(R.string.battery_overall_usage), anyInt());
        mPowerUsageSummary.updateCellularPreference(DISCHARGE_AMOUNT);

        verify(mCellularNetworkPref).setSummary(expectedSummary);
    }

    @Test
    public void testUpdateScreenPreference_ShowCorrectSummary() {
        mPowerUsageSummary.mScreenUsagePref = mScreenUsagePref;
        mPowerUsageSummary.mScreenConsumptionPref = mScreenConsumptionPref;
        final String expectedUsedTime = mRealContext.getString(R.string.battery_used_for,
                Utils.formatElapsedTime(mRealContext, USAGE_TIME_MS, false));
        final double percent = BATTERY_SCREEN_USAGE / TOTAL_POWER * DISCHARGE_AMOUNT;
        final String expectedOverallUsage = mRealContext.getString(R.string.battery_overall_usage,
                Utils.formatPercentage((int) percent));
        doReturn(expectedUsedTime).when(mPowerUsageSummary).getString(
                eq(R.string.battery_used_for), anyInt());
        doReturn(expectedOverallUsage).when(mPowerUsageSummary).getString(
                eq(R.string.battery_overall_usage), anyInt());

        mPowerUsageSummary.updateScreenPreference(DISCHARGE_AMOUNT);

        verify(mScreenUsagePref).setSummary(expectedUsedTime);
        verify(mScreenConsumptionPref).setSummary(expectedOverallUsage);
    }

    @Test
    public void testCalculatePercentage() {
        final double percent = mPowerUsageSummary.calculatePercentage(POWER_MAH, DISCHARGE_AMOUNT);
        assertThat(percent).isWithin(PRECISION).of(POWER_USAGE_PERCENTAGE);
    }

    public static class TestFragment extends PowerUsageSummary {

        private Context mContext;