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

Commit bcf0a411 authored by ykhung's avatar ykhung Committed by YUKAI HUNG
Browse files

Add app usage preferencee item into the history preference

Bug: 177406865
Test: make SettingsRoboTests
Test: make SettingsGoogleRoboTests
Change-Id: I7d9a14eca0b8d3b054e040cb13135ef15390e512
parent 770ad5cb
Loading
Loading
Loading
Loading
+106 −3
Original line number Diff line number Diff line
@@ -18,6 +18,10 @@
package com.android.settings.fuelgauge;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.VisibleForTesting;
@@ -38,6 +42,7 @@ import com.android.settingslib.core.lifecycle.events.OnPause;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@@ -63,6 +68,11 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
    private final String mPreferenceKey;
    private final SettingsActivity mActivity;
    private final InstrumentedPreferenceFragment mFragment;
    private final Handler mHandler = new Handler(Looper.getMainLooper());

    // Preference cache to avoid create new instance each time.
    @VisibleForTesting
    final Map<String, Preference> mPreferenceCache = new HashMap<>();

    public BatteryChartPreferenceController(
            Context context, String preferenceKey,
@@ -86,6 +96,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
        if (mActivity.isChangingConfigurations()) {
            BatteryDiffEntry.clearCache();
        }
        mHandler.removeCallbacksAndMessages(/*token=*/ null);
        mPreferenceCache.clear();
    }

    @Override
@@ -93,6 +105,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
        super.displayPreference(screen);
        mPrefContext = screen.getContext();
        mAppListPrefGroup = screen.findPreference(mPreferenceKey);
        mAppListPrefGroup.setOrderingAsAdded(false);
    }

    @Override
@@ -116,7 +129,13 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
        refreshUi(trapezoidIndex, /*isForce=*/ false);
    }

    void setBatteryHistoryMap(Map<Long, List<BatteryHistEntry>> batteryHistoryMap) {
    void setBatteryHistoryMap(
            final Map<Long, List<BatteryHistEntry>> batteryHistoryMap) {
        mHandler.post(() -> setBatteryHistoryMapInner(batteryHistoryMap));
    }

    private void setBatteryHistoryMapInner(
            final Map<Long, List<BatteryHistEntry>> batteryHistoryMap) {
        // Resets all battery history data relative variables.
        if (batteryHistoryMap == null) {
            mBatteryIndexedMap = null;
@@ -163,7 +182,11 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
            Arrays.toString(mBatteryHistoryLevels)));
    }

    void setBatteryChartView(BatteryChartView batteryChartView) {
    void setBatteryChartView(final BatteryChartView batteryChartView) {
        mHandler.post(() -> setBatteryChartViewInner(batteryChartView));
    }

    private void setBatteryChartViewInner(final BatteryChartView batteryChartView) {
        mBatteryChartView = batteryChartView;
        mBatteryChartView.setOnSelectListener(this);
        forceRefreshUi();
@@ -174,6 +197,9 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
            mTrapezoidIndex == BatteryChartView.SELECTED_INDEX_INVALID
                ? BatteryChartView.SELECTED_INDEX_ALL
                : mTrapezoidIndex;
        if (mBatteryChartView != null) {
            mBatteryChartView.setLevels(mBatteryHistoryLevels);
        }
        refreshUi(refreshIndex, /*isForce=*/ true);
    }

@@ -185,12 +211,89 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
                || (mTrapezoidIndex == trapezoidIndex && !isForce)) {
            return false;
        }
        mTrapezoidIndex = trapezoidIndex;
        Log.d(TAG, String.format("refreshUi: index=%d batteryIndexedMap.size=%d",
            mTrapezoidIndex, mBatteryIndexedMap.size()));

        mTrapezoidIndex = trapezoidIndex;
        mHandler.post(() -> {
            removeAndCacheAllPrefs();
            addAllPreferences();
        });
        return true;
    }

    private void addAllPreferences() {
        final List<BatteryDiffEntry> entries =
            mBatteryIndexedMap.get(Integer.valueOf(mTrapezoidIndex));
        if (entries == null) {
            Log.w(TAG, "cannot find BatteryDiffEntry for:" + mTrapezoidIndex);
            return;
        }
        // Separates data into two groups and sort them individually.
        final List<BatteryDiffEntry> appEntries = new ArrayList<>();
        final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
        entries.forEach(entry -> {
            if (entry.isSystemEntry()) {
                systemEntries.add(entry);
            } else {
                appEntries.add(entry);
            }
        });
        Collections.sort(appEntries, BatteryDiffEntry.COMPARATOR);
        Collections.sort(systemEntries, BatteryDiffEntry.COMPARATOR);
        Log.d(TAG, String.format("addAllPreferences() app=%d system=%d",
            appEntries.size(), systemEntries.size()));
        addPreferenceToScreen(appEntries);
        addPreferenceToScreen(systemEntries);
    }

    @VisibleForTesting
    void addPreferenceToScreen(List<BatteryDiffEntry> entries) {
        if (mAppListPrefGroup == null || entries.isEmpty()) {
            return;
        }
        int prefIndex = mAppListPrefGroup.getPreferenceCount();
        for (BatteryDiffEntry entry : entries) {
            final String appLabel = entry.getAppLabel();
            final Drawable appIcon = entry.getAppIcon();
            if (TextUtils.isEmpty(appLabel) || appIcon == null) {
                Log.w(TAG, "cannot find app resource:" + entry.mBatteryHistEntry);
                continue;
            }
            final String prefKey = entry.mBatteryHistEntry.getKey();
            PowerGaugePreference pref =
                (PowerGaugePreference) mPreferenceCache.get(prefKey);
            // Creates new innstance if cached preference is not found.
            if (pref == null) {
                pref = new PowerGaugePreference(mPrefContext);
                pref.setKey(prefKey);
                mPreferenceCache.put(prefKey, pref);
            }
            pref.setIcon(appIcon);
            pref.setTitle(appLabel);
            pref.setOrder(prefIndex);
            pref.setPercent(entry.getPercentOfTotal());
            mAppListPrefGroup.addPreference(pref);
            prefIndex++;
        }
    }

    private void removeAndCacheAllPrefs() {
        if (mAppListPrefGroup == null
                || mAppListPrefGroup.getPreferenceCount() == 0) {
            return;
        }
        final int prefsCount = mAppListPrefGroup.getPreferenceCount();
        for (int index = 0; index < prefsCount; index++) {
            final Preference pref = mAppListPrefGroup.getPreference(index);
            if (TextUtils.isEmpty(pref.getKey())) {
                continue;
            }
            mPreferenceCache.put(pref.getKey(), pref);
        }
        mAppListPrefGroup.removeAll();
    }

    private static String utcToLocalTime(long[] timestamps) {
        final StringBuilder builder = new StringBuilder();
        for (int index = 0; index < timestamps.length; index++) {
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ import java.util.Locale;
import java.util.Map;

/** A container class to carry battery data in a specific time slot. */
public final class BatteryDiffEntry {
public class BatteryDiffEntry {
    private static final String TAG = "BatteryDiffEntry";

    static Locale sCurrentLocale = null;
+1 −1
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ import java.time.Duration;
import java.util.TimeZone;

/** A container class to carry data from {@link ContentValues}. */
public final class BatteryHistEntry {
public class BatteryHistEntry {
    private static final String TAG = "BatteryHistEntry";

    /** Keys for accessing {@link ContentValues} or {@link Cursor}. */
+5 −3
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
    final BatteryHistoryLoaderCallbacks mBatteryHistoryLoaderCallbacks =
            new BatteryHistoryLoaderCallbacks();

    private boolean mIsChartDataLoaded = false;
    private boolean mIsChartGraphEnabled = false;
    private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
    private BatteryChartPreferenceController mBatteryChartPreferenceController;
@@ -145,10 +146,11 @@ public class PowerUsageAdvanced extends PowerUsageBase {
        final Bundle bundle = new Bundle();
        bundle.putInt(KEY_REFRESH_TYPE, refreshType);
        // Uses customized battery history loader if chart design is enabled.
        if (mIsChartGraphEnabled) {
        if (mIsChartGraphEnabled && !mIsChartDataLoaded) {
            mIsChartDataLoaded = true;
            getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle,
                mBatteryHistoryLoaderCallbacks);
        } else {
        } else if (!mIsChartGraphEnabled) {
            super.restartBatteryStatsLoader(refreshType);
        }
    }
+88 −1
Original line number Diff line number Diff line
@@ -18,14 +18,18 @@ package com.android.settings.fuelgauge;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;

import androidx.preference.PreferenceGroup;

@@ -55,9 +59,13 @@ public final class BatteryChartPreferenceControllerTest {
    @Mock private SettingsActivity mSettingsActivity;
    @Mock private PreferenceGroup mAppListGroup;
    @Mock private PackageManager mPackageManager;
    @Mock private Drawable mDrawable;
    @Mock private BatteryHistEntry mBatteryHistEntry;
    @Mock private BatteryChartView mBatteryChartView;
    @Mock private PowerGaugePreference mPowerGaugePreference;

    private Context mContext;
    private BatteryDiffEntry mBatteryDiffEntry;
    private BatteryChartPreferenceController mBatteryChartPreferenceController;

    @Before
@@ -71,6 +79,13 @@ public final class BatteryChartPreferenceControllerTest {
        mBatteryChartPreferenceController.mPrefContext = mContext;
        mBatteryChartPreferenceController.mAppListPrefGroup = mAppListGroup;
        mBatteryChartPreferenceController.mBatteryChartView = mBatteryChartView;
        mBatteryDiffEntry = new BatteryDiffEntry(
            mContext,
            /*foregroundUsageTimeInMs=*/ 1,
            /*backgroundUsageTimeInMs=*/ 2,
            /*consumePower=*/ 3,
            mBatteryHistEntry);
        mBatteryDiffEntry = spy(mBatteryDiffEntry);
        // Adds fake testing data.
        BatteryDiffEntry.sResourceCache.put(
            "fakeBatteryDiffEntryKey",
@@ -99,6 +114,19 @@ public final class BatteryChartPreferenceControllerTest {
        assertThat(BatteryDiffEntry.sResourceCache).isNotEmpty();
    }

    @Test
    public void testOnDestroy_clearPreferenceCache() {
        final String prefKey = "preference fake key";
        // Ensures the testing environment is correct.
        mBatteryChartPreferenceController.mPreferenceCache.put(
            prefKey, mPowerGaugePreference);
        assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);

        mBatteryChartPreferenceController.onDestroy();
        // Verifies the result after onDestroy.
        assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
    }

    @Test
    public void testSetBatteryHistoryMap_createExpectedKeysAndLevels() {
        mBatteryChartPreferenceController.setBatteryHistoryMap(
@@ -176,11 +204,70 @@ public final class BatteryChartPreferenceControllerTest {
        mBatteryChartPreferenceController.setBatteryHistoryMap(
            createBatteryHistoryMap(/*size=*/ 25));


        assertThat(mBatteryChartPreferenceController.mTrapezoidIndex)
            .isEqualTo(BatteryChartView.SELECTED_INDEX_ALL);
    }

    @Test
    public void testRemoveAndCacheAllPrefs_emptyContent_ignoreRemoveAll() {
        final int trapezoidIndex = 1;
        doReturn(0).when(mAppListGroup).getPreferenceCount();

        mBatteryChartPreferenceController.refreshUi(
            trapezoidIndex, /*isForce=*/ true);
        verify(mAppListGroup, never()).removeAll();
    }

    @Test
    public void testRemoveAndCacheAllPrefs_buildCacheAndRemoveAllPreference() {
        final int trapezoidIndex = 1;
        final String prefKey = "preference fake key";
        doReturn(1).when(mAppListGroup).getPreferenceCount();
        doReturn(mPowerGaugePreference).when(mAppListGroup).getPreference(0);
        doReturn(prefKey).when(mPowerGaugePreference).getKey();
        // Ensures the testing data is correct.
        assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();

        mBatteryChartPreferenceController.refreshUi(
            trapezoidIndex, /*isForce=*/ true);

        assertThat(mBatteryChartPreferenceController.mPreferenceCache.get(prefKey))
            .isEqualTo(mPowerGaugePreference);
        verify(mAppListGroup).removeAll();
    }

    @Test
    public void testAddPreferenceToScreen_emptyContent_ignoreAddPreference() {
        mBatteryChartPreferenceController.addPreferenceToScreen(
            new ArrayList<BatteryDiffEntry>());
        verify(mAppListGroup, never()).addPreference(any());
    }

    @Test
    public void testAddPreferenceToScreen_addPreferenceIntoScreen() {
        final String prefKey = "preference fake key";
        final String appLabel = "fake app label";
        doReturn(1).when(mAppListGroup).getPreferenceCount();
        doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
        doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
        doReturn(prefKey).when(mBatteryHistEntry).getKey();

        mBatteryChartPreferenceController.addPreferenceToScreen(
            Arrays.asList(mBatteryDiffEntry));

        // Verifies the preference cache.
        final PowerGaugePreference pref =
            (PowerGaugePreference) mBatteryChartPreferenceController.mPreferenceCache
                .get(prefKey);
        assertThat(pref).isNotNull();
        // Verifies the added preference configuration.
        verify(mAppListGroup).addPreference(pref);
        assertThat(pref.getKey()).isEqualTo(prefKey);
        assertThat(pref.getTitle()).isEqualTo(appLabel);
        assertThat(pref.getIcon()).isEqualTo(mDrawable);
        assertThat(pref.getOrder()).isEqualTo(1);
    }

    private Map<Long, List<BatteryHistEntry>> createBatteryHistoryMap(int size) {
        final Map<Long, List<BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
        for (int index = 0; index < size; index++) {