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

Commit 36e9a5ff authored by YUKAI HUNG's avatar YUKAI HUNG Committed by Android (Google) Code Review
Browse files

Merge "Add app usage preferencee item into the history preference" into sc-dev

parents aeaad6bd bcf0a411
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++) {