Support App and System tabs for battery usage breakdown.

design_doc: go/usage-frontend-dd

screen_record: https://drive.google.com/file/d/1I8dnoMf7y9KUg0eVeqLJpHqGGOtaX6_0/view?usp=share_link&resourcekey=0-Mte0-LKN1LULRssg9t7zGg

Bug b/260786962 is also fixed in this cl.

Bug: 258123381
Bug: 260786962
Fix: 258123381
Fix: 260786962
Test: manual
Change-Id: Ifd337331d02dc10c3234c594b2e142bcd459c00f
This commit is contained in:
Zaiyue Xue
2022-11-29 13:46:23 +08:00
parent ec1c9d94f2
commit 00fb008e9c
13 changed files with 1013 additions and 916 deletions

View File

@@ -24,16 +24,13 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.settings.SettingsEnums;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.LocaleList;
import android.text.format.DateUtils;
@@ -41,27 +38,17 @@ import android.view.View;
import android.view.ViewPropertyAnimator;
import android.widget.LinearLayout;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -70,18 +57,9 @@ import java.util.TimeZone;
@RunWith(RobolectricTestRunner.class)
public final class BatteryChartPreferenceControllerTest {
private static final String PREF_KEY = "pref_key";
private static final String PREF_SUMMARY = "fake preference summary";
@Mock
private InstrumentedPreferenceFragment mFragment;
@Mock
private SettingsActivity mSettingsActivity;
@Mock
private PreferenceGroup mAppListGroup;
@Mock
private Drawable mDrawable;
@Mock
private BatteryHistEntry mBatteryHistEntry;
@Mock
private BatteryChartView mDailyChartView;
@@ -90,16 +68,11 @@ public final class BatteryChartPreferenceControllerTest {
@Mock
private ViewPropertyAnimator mViewPropertyAnimator;
@Mock
private PowerGaugePreference mPowerGaugePreference;
@Mock
private BatteryUtils mBatteryUtils;
@Mock
private LinearLayout.LayoutParams mLayoutParams;
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
private BatteryDiffEntry mBatteryDiffEntry;
private MetricsFeatureProvider mMetricsFeatureProvider;
private BatteryChartPreferenceController mBatteryChartPreferenceController;
@Before
@@ -109,7 +82,6 @@ public final class BatteryChartPreferenceControllerTest {
org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
mFeatureFactory = FakeFeatureFactory.setupForTest();
mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
mContext = spy(RuntimeEnvironment.application);
final Resources resources = spy(mContext.getResources());
resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
@@ -121,7 +93,6 @@ public final class BatteryChartPreferenceControllerTest {
setupHourlyChartViewAnimationMock();
mBatteryChartPreferenceController = createController();
mBatteryChartPreferenceController.mPrefContext = mContext;
mBatteryChartPreferenceController.mAppListPrefGroup = mAppListGroup;
mBatteryChartPreferenceController.mDailyChartView = mDailyChartView;
mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView;
mBatteryDiffEntry = new BatteryDiffEntry(
@@ -161,24 +132,6 @@ public final class BatteryChartPreferenceControllerTest {
assertThat(BatteryDiffEntry.sResourceCache).isNotEmpty();
}
@Test
public void onDestroy_clearPreferenceCache() {
// Ensures the testing environment is correct.
mBatteryChartPreferenceController.mPreferenceCache.put(
PREF_KEY, mPowerGaugePreference);
assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
mBatteryChartPreferenceController.onDestroy();
// Verifies the result after onDestroy.
assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
}
@Test
public void onDestroy_removeAllPreferenceFromPreferenceGroup() {
mBatteryChartPreferenceController.onDestroy();
verify(mAppListGroup).removeAll();
}
@Test
public void setBatteryChartViewModel_6Hours() {
reset(mDailyChartView);
@@ -313,9 +266,9 @@ public final class BatteryChartPreferenceControllerTest {
}
@Test
public void refreshUi_batteryIndexedMapIsNull_ignoreRefresh() {
public void refreshUi_batteryIndexedMapIsNull_returnTrue() {
mBatteryChartPreferenceController.setBatteryHistoryMap(null);
assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
}
@Test
@@ -330,261 +283,6 @@ public final class BatteryChartPreferenceControllerTest {
assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
}
@Test
public void removeAndCacheAllPrefs_emptyContent_ignoreRemoveAll() {
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
doReturn(0).when(mAppListGroup).getPreferenceCount();
mBatteryChartPreferenceController.refreshUi();
verify(mAppListGroup, never()).removeAll();
}
@Test
public void removeAndCacheAllPrefs_buildCacheAndRemoveAllPreference() {
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
doReturn(1).when(mAppListGroup).getPreferenceCount();
doReturn(mPowerGaugePreference).when(mAppListGroup).getPreference(0);
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
// Ensures the testing data is correct.
assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
mBatteryChartPreferenceController.refreshUi();
assertThat(mBatteryChartPreferenceController.mPreferenceCache.get(PREF_KEY))
.isEqualTo(mPowerGaugePreference);
verify(mAppListGroup).removeAll();
}
@Test
public void addPreferenceToScreen_emptyContent_ignoreAddPreference() {
mBatteryChartPreferenceController.addPreferenceToScreen(
new ArrayList<BatteryDiffEntry>());
verify(mAppListGroup, never()).addPreference(any());
}
@Test
public void addPreferenceToScreen_addPreferenceIntoScreen() {
final String appLabel = "fake app label";
doReturn(1).when(mAppListGroup).getPreferenceCount();
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
doReturn(null).when(mAppListGroup).findPreference(PREF_KEY);
doReturn(false).when(mBatteryDiffEntry).validForRestriction();
mBatteryChartPreferenceController.addPreferenceToScreen(
Arrays.asList(mBatteryDiffEntry));
// Verifies the preference cache.
final PowerGaugePreference pref =
(PowerGaugePreference) mBatteryChartPreferenceController.mPreferenceCache
.get(PREF_KEY);
assertThat(pref).isNotNull();
// Verifies the added preference configuration.
verify(mAppListGroup).addPreference(pref);
assertThat(pref.getKey()).isEqualTo(PREF_KEY);
assertThat(pref.getTitle()).isEqualTo(appLabel);
assertThat(pref.getIcon()).isEqualTo(mDrawable);
assertThat(pref.getOrder()).isEqualTo(1);
assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry);
assertThat(pref.isSingleLineTitle()).isTrue();
assertThat(pref.isEnabled()).isFalse();
}
@Test
public void addPreferenceToScreen_alreadyInScreen_notAddPreferenceAgain() {
final String appLabel = "fake app label";
doReturn(1).when(mAppListGroup).getPreferenceCount();
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
mBatteryChartPreferenceController.addPreferenceToScreen(
Arrays.asList(mBatteryDiffEntry));
verify(mAppListGroup, never()).addPreference(any());
}
@Test
public void handlePreferenceTreeClick_notPowerGaugePreference_returnFalse() {
assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(mAppListGroup))
.isFalse();
verify(mMetricsFeatureProvider, never())
.action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM);
verify(mMetricsFeatureProvider, never())
.action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM);
}
@Test
public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
doReturn(false).when(mBatteryHistEntry).isAppEntry();
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
mPowerGaugePreference)).isTrue();
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_BATTERY_USAGE,
SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
SettingsEnums.OPEN_BATTERY_USAGE,
/* package name */ "none",
/* percentage of total */ 0);
}
@Test
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
mBatteryChartPreferenceController.mBatteryUtils = mBatteryUtils;
doReturn(true).when(mBatteryHistEntry).isAppEntry();
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
mPowerGaugePreference)).isTrue();
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_BATTERY_USAGE,
SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
SettingsEnums.OPEN_BATTERY_USAGE,
/* package name */ "none",
/* percentage of total */ 0);
}
@Test
public void setPreferenceSummary_setNullContentIfTotalUsageTimeIsZero() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0));
assertThat(pref.getSummary()).isNull();
}
@Test
public void setPreferenceSummary_setBackgroundUsageTimeOnly() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
assertThat(pref.getSummary()).isEqualTo("Background: 1 min");
}
@Test
public void setPreferenceSummary_setTotalUsageTimeLessThanAMinute() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ 100,
/*backgroundUsageTimeInMs=*/ 200));
assertThat(pref.getSummary()).isEqualTo("Total: less than a min");
}
@Test
public void setPreferenceSummary_setTotalTimeIfBackgroundTimeLessThanAMinute() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
/*backgroundUsageTimeInMs=*/ 200));
assertThat(pref.getSummary())
.isEqualTo("Total: 1 min\nBackground: less than a min");
}
@Test
public void setPreferenceSummary_setTotalAndBackgroundUsageTime() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryChartPreferenceController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
/*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
assertThat(pref.getSummary()).isEqualTo("Total: 2 min\nBackground: 1 min");
}
@Test
public void onExpand_expandedIsTrue_addSystemEntriesToPreferenceGroup() {
doReturn(1).when(mAppListGroup).getPreferenceCount();
mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
doReturn("label").when(mBatteryDiffEntry).getAppLabel();
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ true);
final ArgumentCaptor<Preference> captor = ArgumentCaptor.forClass(Preference.class);
verify(mAppListGroup).addPreference(captor.capture());
// Verifies the added preference.
assertThat(captor.getValue().getKey()).isEqualTo(PREF_KEY);
verify(mMetricsFeatureProvider)
.action(
mContext,
SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
true /*isExpanded*/);
}
@Test
public void onExpand_expandedIsFalse_removeSystemEntriesFromPreferenceGroup() {
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
// Verifies the cache is empty first.
assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ false);
verify(mAppListGroup).findPreference(PREF_KEY);
verify(mAppListGroup).removePreference(mPowerGaugePreference);
assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
verify(mMetricsFeatureProvider)
.action(
mContext,
SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
false /*isExpanded*/);
}
@Test
public void refreshCategoryTitle_setLastFullChargeIntoBothTitleTextView() {
mBatteryChartPreferenceController = createController();
mBatteryChartPreferenceController.mAppListPrefGroup =
spy(new PreferenceCategory(mContext));
mBatteryChartPreferenceController.mExpandDividerPreference =
spy(new ExpandDividerPreference(mContext));
// Simulates select all condition.
mBatteryChartPreferenceController.mDailyChartIndex =
BatteryChartViewModel.SELECTED_INDEX_ALL;
mBatteryChartPreferenceController.mHourlyChartIndex =
BatteryChartViewModel.SELECTED_INDEX_ALL;
mBatteryChartPreferenceController.refreshCategoryTitle();
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
// Verifies the title in the preference group.
verify(mBatteryChartPreferenceController.mAppListPrefGroup)
.setTitle(captor.capture());
assertThat(captor.getValue())
.isEqualTo("App usage since last full charge");
// Verifies the title in the expandable divider.
captor = ArgumentCaptor.forClass(String.class);
verify(mBatteryChartPreferenceController.mExpandDividerPreference)
.setTitle(captor.capture());
assertThat(captor.getValue())
.isEqualTo("System usage since last full charge");
}
@Test
public void selectedSlotText_selectAllDaysAllHours_returnNull() {
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
@@ -640,16 +338,13 @@ public final class BatteryChartPreferenceControllerTest {
public void onSaveInstanceState_restoreSelectedIndexAndExpandState() {
final int expectedDailyIndex = 1;
final int expectedHourlyIndex = 2;
final boolean isExpanded = true;
final Bundle bundle = new Bundle();
mBatteryChartPreferenceController.mDailyChartIndex = expectedDailyIndex;
mBatteryChartPreferenceController.mHourlyChartIndex = expectedHourlyIndex;
mBatteryChartPreferenceController.mIsExpanded = isExpanded;
mBatteryChartPreferenceController.onSaveInstanceState(bundle);
// Replaces the original controller with other values.
mBatteryChartPreferenceController.mDailyChartIndex = -1;
mBatteryChartPreferenceController.mHourlyChartIndex = -1;
mBatteryChartPreferenceController.mIsExpanded = false;
mBatteryChartPreferenceController.onCreate(bundle);
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(25));
@@ -658,7 +353,6 @@ public final class BatteryChartPreferenceControllerTest {
.isEqualTo(expectedDailyIndex);
assertThat(mBatteryChartPreferenceController.mHourlyChartIndex)
.isEqualTo(expectedHourlyIndex);
assertThat(mBatteryChartPreferenceController.mIsExpanded).isTrue();
}
@Test
@@ -704,36 +398,10 @@ public final class BatteryChartPreferenceControllerTest {
return batteryHistoryMap;
}
private Map<Integer, Map<Integer, BatteryDiffData>> createBatteryUsageMap() {
final int selectedAll = BatteryChartViewModel.SELECTED_INDEX_ALL;
return Map.of(
selectedAll, Map.of(
selectedAll, new BatteryDiffData(
Arrays.asList(mBatteryDiffEntry),
Arrays.asList(mBatteryDiffEntry))),
0, Map.of(
selectedAll, new BatteryDiffData(
Arrays.asList(mBatteryDiffEntry),
Arrays.asList(mBatteryDiffEntry)),
0, new BatteryDiffData(
Arrays.asList(mBatteryDiffEntry),
Arrays.asList(mBatteryDiffEntry))));
}
private BatteryDiffEntry createBatteryDiffEntry(
long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
return new BatteryDiffEntry(
mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs, /*consumePower=*/ 0,
/*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
mBatteryHistEntry);
}
private BatteryChartPreferenceController createController() {
final BatteryChartPreferenceController controller =
new BatteryChartPreferenceController(
mContext, "app_list", /*lifecycle=*/ null,
mSettingsActivity, mFragment);
mContext, /*lifecycle=*/ null, mSettingsActivity);
controller.mPrefContext = mContext;
return controller;
}

View File

@@ -0,0 +1,310 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
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 android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.LocaleList;
import android.text.format.DateUtils;
import androidx.preference.PreferenceGroup;
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.Arrays;
import java.util.Locale;
import java.util.TimeZone;
@RunWith(RobolectricTestRunner.class)
public final class BatteryUsageBreakdownControllerTest {
private static final String PREF_KEY = "pref_key";
private static final String PREF_SUMMARY = "fake preference summary";
@Mock
private InstrumentedPreferenceFragment mFragment;
@Mock
private SettingsActivity mSettingsActivity;
@Mock
private PreferenceGroup mAppListPreferenceGroup;
@Mock
private Drawable mDrawable;
@Mock
private BatteryHistEntry mBatteryHistEntry;
@Mock
private PowerGaugePreference mPowerGaugePreference;
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
private BatteryDiffEntry mBatteryDiffEntry;
private MetricsFeatureProvider mMetricsFeatureProvider;
private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Locale.setDefault(new Locale("en_US"));
org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
mFeatureFactory = FakeFeatureFactory.setupForTest();
mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
mContext = spy(RuntimeEnvironment.application);
final Resources resources = spy(mContext.getResources());
resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
doReturn(resources).when(mContext).getResources();
doReturn(new String[]{"com.android.gms.persistent"})
.when(mFeatureFactory.powerUsageFeatureProvider)
.getHideApplicationEntries(mContext);
mBatteryUsageBreakdownController = createController();
mBatteryUsageBreakdownController.mAppListPreferenceGroup = mAppListPreferenceGroup;
mBatteryDiffEntry = new BatteryDiffEntry(
mContext,
/*foregroundUsageTimeInMs=*/ 1,
/*backgroundUsageTimeInMs=*/ 2,
/*consumePower=*/ 3,
/*foregroundUsageConsumePower=*/ 0,
/*foregroundServiceUsageConsumePower=*/ 1,
/*backgroundUsageConsumePower=*/ 2,
/*cachedUsageConsumePower=*/ 0,
mBatteryHistEntry);
mBatteryDiffEntry = spy(mBatteryDiffEntry);
mBatteryUsageBreakdownController.mBatteryDiffData =
new BatteryDiffData(Arrays.asList(mBatteryDiffEntry), Arrays.asList());
// Adds fake testing data.
BatteryDiffEntry.sResourceCache.put(
"fakeBatteryDiffEntryKey",
new BatteryEntry.NameAndIcon("fakeName", /*icon=*/ null, /*iconId=*/ 1));
}
@Test
public void onDestroy_clearPreferenceCacheAndPreferenceGroupRemoveAll() {
// Ensures the testing environment is correct.
mBatteryUsageBreakdownController.mPreferenceCache.put(
PREF_KEY, mPowerGaugePreference);
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).hasSize(1);
mBatteryUsageBreakdownController.onDestroy();
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
}
@Test
public void onDestroy_removeAllPreferenceFromPreferenceGroup() {
mBatteryUsageBreakdownController.onDestroy();
verify(mAppListPreferenceGroup).removeAll();
}
@Test
public void addAllPreferences_addAllPreferences() {
final String appLabel = "fake app label";
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
doReturn(null).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
doReturn(false).when(mBatteryDiffEntry).validForRestriction();
mBatteryUsageBreakdownController.addAllPreferences();
// Verifies the preference cache.
final PowerGaugePreference pref =
(PowerGaugePreference) mBatteryUsageBreakdownController.mPreferenceCache
.get(PREF_KEY);
assertThat(pref).isNotNull();
// Verifies the added preference configuration.
verify(mAppListPreferenceGroup).addPreference(pref);
assertThat(pref.getKey()).isEqualTo(PREF_KEY);
assertThat(pref.getTitle().toString()).isEqualTo(appLabel);
assertThat(pref.getIcon()).isEqualTo(mDrawable);
assertThat(pref.getOrder()).isEqualTo(1);
assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry);
assertThat(pref.isSingleLineTitle()).isTrue();
assertThat(pref.isEnabled()).isFalse();
}
@Test
public void addPreferenceToScreen_alreadyInScreen_notAddPreferenceAgain() {
final String appLabel = "fake app label";
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
mBatteryUsageBreakdownController.addAllPreferences();
verify(mAppListPreferenceGroup, never()).addPreference(any());
}
@Test
public void removeAndCacheAllPreferences_buildCacheAndRemoveAllPreference() {
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
// Ensures the testing data is correct.
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
mBatteryUsageBreakdownController.removeAndCacheAllPreferences();
assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY))
.isEqualTo(mPowerGaugePreference);
verify(mAppListPreferenceGroup).removeAll();
}
@Test
public void handlePreferenceTreeClick_notPowerGaugePreference_returnFalse() {
assertThat(mBatteryUsageBreakdownController
.handlePreferenceTreeClick(mAppListPreferenceGroup)).isFalse();
verify(mMetricsFeatureProvider, never())
.action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM);
verify(mMetricsFeatureProvider, never())
.action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM);
}
@Test
public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
doReturn(false).when(mBatteryHistEntry).isAppEntry();
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
mPowerGaugePreference)).isTrue();
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_BATTERY_USAGE,
SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
SettingsEnums.OPEN_BATTERY_USAGE,
/* package name */ "none",
/* percentage of total */ 0);
}
@Test
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
doReturn(true).when(mBatteryHistEntry).isAppEntry();
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
mPowerGaugePreference)).isTrue();
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_BATTERY_USAGE,
SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
SettingsEnums.OPEN_BATTERY_USAGE,
/* package name */ "none",
/* percentage of total */ 0);
}
@Test
public void setPreferenceSummary_setNullContentIfTotalUsageTimeIsZero() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryUsageBreakdownController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0));
assertThat(pref.getSummary()).isNull();
}
@Test
public void setPreferenceSummary_setBackgroundUsageTimeOnly() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryUsageBreakdownController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
assertThat(pref.getSummary().toString()).isEqualTo("Background: 1 min");
}
@Test
public void setPreferenceSummary_setTotalUsageTimeLessThanAMinute() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryUsageBreakdownController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ 100,
/*backgroundUsageTimeInMs=*/ 200));
assertThat(pref.getSummary().toString()).isEqualTo("Total: less than a min");
}
@Test
public void setPreferenceSummary_setTotalTimeIfBackgroundTimeLessThanAMinute() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryUsageBreakdownController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
/*backgroundUsageTimeInMs=*/ 200));
assertThat(pref.getSummary().toString())
.isEqualTo("Total: 1 min\nBackground: less than a min");
}
@Test
public void setPreferenceSummary_setTotalAndBackgroundUsageTime() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
pref.setSummary(PREF_SUMMARY);
mBatteryUsageBreakdownController.setPreferenceSummary(
pref, createBatteryDiffEntry(
/*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
/*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
assertThat(pref.getSummary().toString()).isEqualTo("Total: 2 min\nBackground: 1 min");
}
private BatteryDiffEntry createBatteryDiffEntry(
long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
return new BatteryDiffEntry(
mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs, /*consumePower=*/ 0,
/*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
mBatteryHistEntry);
}
private BatteryUsageBreakdownController createController() {
final BatteryUsageBreakdownController controller =
new BatteryUsageBreakdownController(
mContext, /*lifecycle=*/ null, mSettingsActivity, mFragment);
controller.mPrefContext = mContext;
return controller;
}
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public final class ExpandDividerPreferenceTest {
private Context mContext;
private ExpandDividerPreference mExpandDividerPreference;
private ImageView mImageView;
private TextView mTextView;
@Before
public void setUp() {
mContext = spy(RuntimeEnvironment.application);
mImageView = spy(new ImageView(mContext));
mTextView = spy(new TextView(mContext));
mExpandDividerPreference = new ExpandDividerPreference(mContext);
doReturn(R.id.expand_title).when(mTextView).getId();
doReturn(R.id.expand_icon).when(mImageView).getId();
}
@Test
public void testConstructor_returnExpectedResult() {
assertThat(mExpandDividerPreference.getKey())
.isEqualTo(ExpandDividerPreference.PREFERENCE_KEY);
assertThat(mExpandDividerPreference.getLayoutResource())
.isEqualTo(R.layout.preference_expand_divider);
}
@Test
public void testSetTitle_setTitleContentIntoTextView() {
final String titleContent = "title content";
mExpandDividerPreference.mTextView = mTextView;
mExpandDividerPreference.setTitle(titleContent);
verify(mTextView).setText(titleContent);
}
@Test
public void testOnClick_switchExpandStateAndInvokeCallback() {
final boolean[] isExpandedArray = new boolean[]{false};
mExpandDividerPreference.mImageView = mImageView;
mExpandDividerPreference.setOnExpandListener(
isExpanded -> isExpandedArray[0] = isExpanded);
// Click the item first time from false -> true.
mExpandDividerPreference.onClick();
// Verifies the first time click result.
verify(mImageView).setImageResource(R.drawable.ic_settings_expand_less);
assertThat(isExpandedArray[0]).isTrue();
// Clicks the item second time from true -> false.
mExpandDividerPreference.onClick();
// Verifies the second time click result.
verify(mImageView).setImageResource(R.drawable.ic_settings_expand_more);
assertThat(isExpandedArray[0]).isFalse();
}
@Test
public void testSetIsExpanded_updateStateButNotInvokeCallback() {
final boolean[] isExpandedArray = new boolean[]{false};
mExpandDividerPreference.mImageView = mImageView;
mExpandDividerPreference.setOnExpandListener(
isExpanded -> isExpandedArray[0] = isExpanded);
mExpandDividerPreference.setIsExpanded(true);
verify(mImageView).setImageResource(R.drawable.ic_settings_expand_less);
assertThat(isExpandedArray[0]).isFalse();
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.content.Context;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import com.android.settings.R;
import com.google.android.material.tabs.TabLayout;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public final class TabPreferenceTest {
private Context mContext;
private TabPreference mTabPreference;
@Mock
private Fragment mMockFragment;
@Mock
private TabLayout mMockTabLayout;
private final String[] mTabTitles = new String[]{"tab1", "tab2"};
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mTabPreference = new TabPreference(mContext, /*attrs=*/ null);
}
@Test
public void constructor_returnExpectedResult() {
assertThat(mTabPreference.getLayoutResource()).isEqualTo(R.layout.preference_tab);
}
@Test
public void initializeTabs_returnExpectedResult() {
mTabPreference.initializeTabs(mMockFragment, mTabTitles);
assertThat(mTabPreference.mTabTitles).isEqualTo(mTabTitles);
}
@Test
public void onSaveInstanceState_returnExpectedResult() {
doReturn(1).when(mMockTabLayout).getSelectedTabPosition();
mTabPreference.mTabLayout = mMockTabLayout;
TabPreference.SavedState savedState =
(TabPreference.SavedState) mTabPreference.onSaveInstanceState();
assertThat(savedState.getTabPosition()).isEqualTo(1);
}
@Test
public void onRestoreInstanceState_returnExpectedResult() {
TabPreference.SavedState savedState =
new TabPreference.SavedState(Preference.BaseSavedState.EMPTY_STATE, 2);
mTabPreference.onRestoreInstanceState(savedState);
assertThat(mTabPreference.mSavedTabPosition).isEqualTo(2);
}
}