1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.fuelgauge;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.Matchers.anyInt;
23 import static org.mockito.Matchers.anyLong;
24 import static org.mockito.Mockito.doReturn;
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.spy;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.app.settings.SettingsEnums;
31 import android.content.Context;
32 import android.content.ContentValues;
33 import android.content.pm.PackageManager;
34 import android.content.res.Configuration;
35 import android.content.res.Resources;
36 import android.graphics.drawable.Drawable;
37 import android.os.Bundle;
38 import android.os.LocaleList;
39 import android.text.format.DateUtils;
40 import android.util.Pair;
41 
42 import androidx.preference.Preference;
43 import androidx.preference.PreferenceCategory;
44 import androidx.preference.PreferenceGroup;
45 
46 import com.android.settings.R;
47 import com.android.settings.SettingsActivity;
48 import com.android.settings.core.InstrumentedPreferenceFragment;
49 import com.android.settings.testutils.FakeFeatureFactory;
50 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
51 
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.ArgumentCaptor;
56 import org.mockito.Mock;
57 import org.mockito.MockitoAnnotations;
58 import org.robolectric.RobolectricTestRunner;
59 import org.robolectric.RuntimeEnvironment;
60 
61 import java.util.Arrays;
62 import java.util.ArrayList;
63 import java.util.HashMap;
64 import java.util.Locale;
65 import java.util.List;
66 import java.util.Map;
67 
68 @RunWith(RobolectricTestRunner.class)
69 public final class BatteryChartPreferenceControllerTest {
70     private static final String PREF_KEY = "pref_key";
71     private static final String PREF_SUMMARY = "fake preference summary";
72     private static final int DESIRED_HISTORY_SIZE =
73         BatteryChartPreferenceController.DESIRED_HISTORY_SIZE;
74 
75     @Mock private InstrumentedPreferenceFragment mFragment;
76     @Mock private SettingsActivity mSettingsActivity;
77     @Mock private PreferenceGroup mAppListGroup;
78     @Mock private PackageManager mPackageManager;
79     @Mock private Drawable mDrawable;
80     @Mock private BatteryHistEntry mBatteryHistEntry;
81     @Mock private BatteryChartView mBatteryChartView;
82     @Mock private PowerGaugePreference mPowerGaugePreference;
83     @Mock private ExpandDividerPreference mExpandDividerPreference;
84     @Mock private BatteryUtils mBatteryUtils;
85     @Mock private Configuration mConfiguration;
86     @Mock private Resources mResources;
87 
88     private Context mContext;
89     private FakeFeatureFactory mFeatureFactory;
90     private BatteryDiffEntry mBatteryDiffEntry;
91     private MetricsFeatureProvider mMetricsFeatureProvider;
92     private BatteryChartPreferenceController mBatteryChartPreferenceController;
93 
94     @Before
setUp()95     public void setUp() {
96         MockitoAnnotations.initMocks(this);
97         Locale.setDefault(new Locale("en_US"));
98         org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
99         mFeatureFactory = FakeFeatureFactory.setupForTest();
100         mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
101         mContext = spy(RuntimeEnvironment.application);
102         final Resources resources = spy(mContext.getResources());
103         resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
104         doReturn(resources).when(mContext).getResources();
105         doReturn(new String[] {"com.android.googlequicksearchbox"})
106             .when(mFeatureFactory.powerUsageFeatureProvider)
107             .getHideApplicationSummary(mContext);
108         doReturn(new String[] {"com.android.gms.persistent"})
109             .when(mFeatureFactory.powerUsageFeatureProvider)
110             .getHideApplicationEntries(mContext);
111         mBatteryChartPreferenceController = createController();
112         mBatteryChartPreferenceController.mPrefContext = mContext;
113         mBatteryChartPreferenceController.mAppListPrefGroup = mAppListGroup;
114         mBatteryChartPreferenceController.mBatteryChartView = mBatteryChartView;
115         mBatteryDiffEntry = new BatteryDiffEntry(
116             mContext,
117             /*foregroundUsageTimeInMs=*/ 1,
118             /*backgroundUsageTimeInMs=*/ 2,
119             /*consumePower=*/ 3,
120             mBatteryHistEntry);
121         mBatteryDiffEntry = spy(mBatteryDiffEntry);
122         // Adds fake testing data.
123         BatteryDiffEntry.sResourceCache.put(
124             "fakeBatteryDiffEntryKey",
125             new BatteryEntry.NameAndIcon("fakeName", /*icon=*/ null, /*iconId=*/ 1));
126         mBatteryChartPreferenceController.setBatteryHistoryMap(
127             createBatteryHistoryMap());
128     }
129 
130     @Test
testOnDestroy_activityIsChanging_clearBatteryEntryCache()131     public void testOnDestroy_activityIsChanging_clearBatteryEntryCache() {
132         doReturn(true).when(mSettingsActivity).isChangingConfigurations();
133         // Ensures the testing environment is correct.
134         assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
135 
136         mBatteryChartPreferenceController.onDestroy();
137         assertThat(BatteryDiffEntry.sResourceCache).isEmpty();
138     }
139 
140     @Test
testOnDestroy_activityIsNotChanging_notClearBatteryEntryCache()141     public void testOnDestroy_activityIsNotChanging_notClearBatteryEntryCache() {
142         doReturn(false).when(mSettingsActivity).isChangingConfigurations();
143         // Ensures the testing environment is correct.
144         assertThat(BatteryDiffEntry.sResourceCache).hasSize(1);
145 
146         mBatteryChartPreferenceController.onDestroy();
147         assertThat(BatteryDiffEntry.sResourceCache).isNotEmpty();
148     }
149 
150     @Test
testOnDestroy_clearPreferenceCache()151     public void testOnDestroy_clearPreferenceCache() {
152         // Ensures the testing environment is correct.
153         mBatteryChartPreferenceController.mPreferenceCache.put(
154             PREF_KEY, mPowerGaugePreference);
155         assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
156 
157         mBatteryChartPreferenceController.onDestroy();
158         // Verifies the result after onDestroy.
159         assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
160     }
161 
162     @Test
testOnDestroy_removeAllPreferenceFromPreferenceGroup()163     public void testOnDestroy_removeAllPreferenceFromPreferenceGroup() {
164         mBatteryChartPreferenceController.onDestroy();
165         verify(mAppListGroup).removeAll();
166     }
167 
168     @Test
testSetBatteryHistoryMap_createExpectedKeysAndLevels()169     public void testSetBatteryHistoryMap_createExpectedKeysAndLevels() {
170         mBatteryChartPreferenceController.setBatteryHistoryMap(
171             createBatteryHistoryMap());
172 
173         // Verifies the created battery keys array.
174         for (int index = 0; index < DESIRED_HISTORY_SIZE; index++) {
175             assertThat(mBatteryChartPreferenceController.mBatteryHistoryKeys[index])
176                 // These values is are calculated by hand from createBatteryHistoryMap().
177                 .isEqualTo(index + 1);
178         }
179         // Verifies the created battery levels array.
180         for (int index = 0; index < 13; index++) {
181             assertThat(mBatteryChartPreferenceController.mBatteryHistoryLevels[index])
182                 // These values is are calculated by hand from createBatteryHistoryMap().
183                 .isEqualTo(100 - index * 2);
184         }
185         assertThat(mBatteryChartPreferenceController.mBatteryIndexedMap).hasSize(13);
186     }
187 
188     @Test
testSetBatteryHistoryMap_largeSize_createExpectedKeysAndLevels()189     public void testSetBatteryHistoryMap_largeSize_createExpectedKeysAndLevels() {
190         mBatteryChartPreferenceController.setBatteryHistoryMap(
191             createBatteryHistoryMap());
192 
193         // Verifies the created battery keys array.
194         for (int index = 0; index < DESIRED_HISTORY_SIZE; index++) {
195           assertThat(mBatteryChartPreferenceController.mBatteryHistoryKeys[index])
196               // These values is are calculated by hand from createBatteryHistoryMap().
197               .isEqualTo(index + 1);
198         }
199         // Verifies the created battery levels array.
200         for (int index = 0; index < 13; index++) {
201           assertThat(mBatteryChartPreferenceController.mBatteryHistoryLevels[index])
202               // These values is are calculated by hand from createBatteryHistoryMap().
203               .isEqualTo(100 - index * 2);
204         }
205         assertThat(mBatteryChartPreferenceController.mBatteryIndexedMap).hasSize(13);
206     }
207 
208     @Test
testRefreshUi_batteryIndexedMapIsNull_ignoreRefresh()209     public void testRefreshUi_batteryIndexedMapIsNull_ignoreRefresh() {
210         mBatteryChartPreferenceController.setBatteryHistoryMap(null);
211         assertThat(mBatteryChartPreferenceController.refreshUi(
212             /*trapezoidIndex=*/ 1, /*isForce=*/ false)).isFalse();
213     }
214 
215     @Test
testRefreshUi_batteryChartViewIsNull_ignoreRefresh()216     public void testRefreshUi_batteryChartViewIsNull_ignoreRefresh() {
217         mBatteryChartPreferenceController.mBatteryChartView = null;
218         assertThat(mBatteryChartPreferenceController.refreshUi(
219             /*trapezoidIndex=*/ 1, /*isForce=*/ false)).isFalse();
220     }
221 
222     @Test
testRefreshUi_trapezoidIndexIsNotChanged_ignoreRefresh()223     public void testRefreshUi_trapezoidIndexIsNotChanged_ignoreRefresh() {
224         final int trapezoidIndex = 1;
225         mBatteryChartPreferenceController.mTrapezoidIndex = trapezoidIndex;
226         assertThat(mBatteryChartPreferenceController.refreshUi(
227             trapezoidIndex, /*isForce=*/ false)).isFalse();
228     }
229 
230     @Test
testRefreshUi_forceUpdate_refreshUi()231     public void testRefreshUi_forceUpdate_refreshUi() {
232         final int trapezoidIndex = 1;
233         mBatteryChartPreferenceController.mTrapezoidIndex = trapezoidIndex;
234         assertThat(mBatteryChartPreferenceController.refreshUi(
235             trapezoidIndex, /*isForce=*/ true)).isTrue();
236     }
237 
238     @Test
testForceRefreshUi_updateTrapezoidIndexIntoSelectAll()239     public void testForceRefreshUi_updateTrapezoidIndexIntoSelectAll() {
240         mBatteryChartPreferenceController.mTrapezoidIndex =
241             BatteryChartView.SELECTED_INDEX_INVALID;
242         mBatteryChartPreferenceController.setBatteryHistoryMap(
243             createBatteryHistoryMap());
244 
245         assertThat(mBatteryChartPreferenceController.mTrapezoidIndex)
246             .isEqualTo(BatteryChartView.SELECTED_INDEX_ALL);
247     }
248 
249     @Test
testRemoveAndCacheAllPrefs_emptyContent_ignoreRemoveAll()250     public void testRemoveAndCacheAllPrefs_emptyContent_ignoreRemoveAll() {
251         final int trapezoidIndex = 1;
252         doReturn(0).when(mAppListGroup).getPreferenceCount();
253 
254         mBatteryChartPreferenceController.refreshUi(
255             trapezoidIndex, /*isForce=*/ true);
256         verify(mAppListGroup, never()).removeAll();
257     }
258 
259     @Test
testRemoveAndCacheAllPrefs_buildCacheAndRemoveAllPreference()260     public void testRemoveAndCacheAllPrefs_buildCacheAndRemoveAllPreference() {
261         final int trapezoidIndex = 1;
262         doReturn(1).when(mAppListGroup).getPreferenceCount();
263         doReturn(mPowerGaugePreference).when(mAppListGroup).getPreference(0);
264         doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
265         // Ensures the testing data is correct.
266         assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
267 
268         mBatteryChartPreferenceController.refreshUi(
269             trapezoidIndex, /*isForce=*/ true);
270 
271         assertThat(mBatteryChartPreferenceController.mPreferenceCache.get(PREF_KEY))
272             .isEqualTo(mPowerGaugePreference);
273         verify(mAppListGroup).removeAll();
274     }
275 
276     @Test
testAddPreferenceToScreen_emptyContent_ignoreAddPreference()277     public void testAddPreferenceToScreen_emptyContent_ignoreAddPreference() {
278         mBatteryChartPreferenceController.addPreferenceToScreen(
279             new ArrayList<BatteryDiffEntry>());
280         verify(mAppListGroup, never()).addPreference(any());
281     }
282 
283     @Test
testAddPreferenceToScreen_addPreferenceIntoScreen()284     public void testAddPreferenceToScreen_addPreferenceIntoScreen() {
285         final String appLabel = "fake app label";
286         doReturn(1).when(mAppListGroup).getPreferenceCount();
287         doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
288         doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
289         doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
290         doReturn(null).when(mAppListGroup).findPreference(PREF_KEY);
291         doReturn(false).when(mBatteryDiffEntry).validForRestriction();
292 
293         mBatteryChartPreferenceController.addPreferenceToScreen(
294             Arrays.asList(mBatteryDiffEntry));
295 
296         // Verifies the preference cache.
297         final PowerGaugePreference pref =
298             (PowerGaugePreference) mBatteryChartPreferenceController.mPreferenceCache
299                 .get(PREF_KEY);
300         assertThat(pref).isNotNull();
301         // Verifies the added preference configuration.
302         verify(mAppListGroup).addPreference(pref);
303         assertThat(pref.getKey()).isEqualTo(PREF_KEY);
304         assertThat(pref.getTitle()).isEqualTo(appLabel);
305         assertThat(pref.getIcon()).isEqualTo(mDrawable);
306         assertThat(pref.getOrder()).isEqualTo(1);
307         assertThat(pref.getBatteryDiffEntry()).isSameInstanceAs(mBatteryDiffEntry);
308         assertThat(pref.isSingleLineTitle()).isTrue();
309         assertThat(pref.isEnabled()).isFalse();
310     }
311 
312     @Test
testAddPreferenceToScreen_alreadyInScreen_notAddPreferenceAgain()313     public void testAddPreferenceToScreen_alreadyInScreen_notAddPreferenceAgain() {
314         final String appLabel = "fake app label";
315         doReturn(1).when(mAppListGroup).getPreferenceCount();
316         doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
317         doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
318         doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
319         doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
320 
321         mBatteryChartPreferenceController.addPreferenceToScreen(
322             Arrays.asList(mBatteryDiffEntry));
323 
324         verify(mAppListGroup, never()).addPreference(any());
325     }
326 
327     @Test
testHandlePreferenceTreeiClick_notPowerGaugePreference_returnFalse()328     public void testHandlePreferenceTreeiClick_notPowerGaugePreference_returnFalse() {
329         assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(mAppListGroup))
330             .isFalse();
331 
332         verify(mMetricsFeatureProvider, never())
333             .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM);
334         verify(mMetricsFeatureProvider, never())
335             .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM);
336     }
337 
338     @Test
testHandlePreferenceTreeClick_forAppEntry_returnTrue()339     public void testHandlePreferenceTreeClick_forAppEntry_returnTrue() {
340         doReturn(false).when(mBatteryHistEntry).isAppEntry();
341         doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
342 
343         assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
344             mPowerGaugePreference)).isTrue();
345         verify(mMetricsFeatureProvider)
346                 .action(
347                         SettingsEnums.OPEN_BATTERY_USAGE,
348                         SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
349                         SettingsEnums.OPEN_BATTERY_USAGE,
350                         /* package name */ "none",
351                         /* percentage of total */ 0);
352     }
353 
354     @Test
testHandlePreferenceTreeClick_forSystemEntry_returnTrue()355     public void testHandlePreferenceTreeClick_forSystemEntry_returnTrue() {
356         mBatteryChartPreferenceController.mBatteryUtils = mBatteryUtils;
357         doReturn(true).when(mBatteryHistEntry).isAppEntry();
358         doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
359 
360         assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(
361             mPowerGaugePreference)).isTrue();
362         verify(mMetricsFeatureProvider)
363                 .action(
364                         SettingsEnums.OPEN_BATTERY_USAGE,
365                         SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
366                         SettingsEnums.OPEN_BATTERY_USAGE,
367                         /* package name */ "none",
368                         /* percentage of total */ 0);
369     }
370 
371     @Test
testSetPreferenceSummary_setNullContentIfTotalUsageTimeIsZero()372     public void testSetPreferenceSummary_setNullContentIfTotalUsageTimeIsZero() {
373         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
374         pref.setSummary(PREF_SUMMARY);
375 
376         mBatteryChartPreferenceController.setPreferenceSummary(
377             pref, createBatteryDiffEntry(
378                 /*foregroundUsageTimeInMs=*/ 0,
379                 /*backgroundUsageTimeInMs=*/ 0));
380         assertThat(pref.getSummary()).isNull();
381     }
382 
383     @Test
testSetPreferenceSummary_setBackgroundUsageTimeOnly()384     public void testSetPreferenceSummary_setBackgroundUsageTimeOnly() {
385         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
386         pref.setSummary(PREF_SUMMARY);
387 
388         mBatteryChartPreferenceController.setPreferenceSummary(
389             pref, createBatteryDiffEntry(
390                 /*foregroundUsageTimeInMs=*/ 0,
391                 /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
392         assertThat(pref.getSummary()).isEqualTo("Background: 1 min");
393     }
394 
395     @Test
testSetPreferenceSummary_setTotalUsageTimeLessThanAMinute()396     public void testSetPreferenceSummary_setTotalUsageTimeLessThanAMinute() {
397         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
398         pref.setSummary(PREF_SUMMARY);
399 
400         mBatteryChartPreferenceController.setPreferenceSummary(
401             pref, createBatteryDiffEntry(
402                 /*foregroundUsageTimeInMs=*/ 100,
403                 /*backgroundUsageTimeInMs=*/ 200));
404         assertThat(pref.getSummary()).isEqualTo("Total: less than a min");
405     }
406 
407     @Test
testSetPreferenceSummary_setTotalTimeIfBackgroundTimeLessThanAMinute()408     public void testSetPreferenceSummary_setTotalTimeIfBackgroundTimeLessThanAMinute() {
409         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
410         pref.setSummary(PREF_SUMMARY);
411 
412         mBatteryChartPreferenceController.setPreferenceSummary(
413             pref, createBatteryDiffEntry(
414                 /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
415                 /*backgroundUsageTimeInMs=*/ 200));
416         assertThat(pref.getSummary())
417             .isEqualTo("Total: 1 min\nBackground: less than a min");
418     }
419 
420     @Test
testSetPreferenceSummary_setTotalAndBackgroundUsageTime()421     public void testSetPreferenceSummary_setTotalAndBackgroundUsageTime() {
422         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
423         pref.setSummary(PREF_SUMMARY);
424 
425         mBatteryChartPreferenceController.setPreferenceSummary(
426             pref, createBatteryDiffEntry(
427                 /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
428                 /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
429         assertThat(pref.getSummary()).isEqualTo("Total: 2 min\nBackground: 1 min");
430     }
431 
432     @Test
testSetPreferenceSummary_notAllowShownPackage_setSummayAsNull()433     public void testSetPreferenceSummary_notAllowShownPackage_setSummayAsNull() {
434         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
435         pref.setSummary(PREF_SUMMARY);
436         final BatteryDiffEntry batteryDiffEntry =
437             spy(createBatteryDiffEntry(
438                 /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
439                 /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
440         doReturn("com.android.googlequicksearchbox").when(batteryDiffEntry)
441             .getPackageName();
442 
443         mBatteryChartPreferenceController.setPreferenceSummary(pref, batteryDiffEntry);
444         assertThat(pref.getSummary()).isNull();
445     }
446 
447     @Test
testValidateUsageTime_returnTrueIfBatteryDiffEntryIsValid()448     public void testValidateUsageTime_returnTrueIfBatteryDiffEntryIsValid() {
449         assertThat(BatteryChartPreferenceController.validateUsageTime(
450             createBatteryDiffEntry(
451                 /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
452                 /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS)))
453             .isTrue();
454     }
455 
456     @Test
testValidateUsageTime_foregroundTimeExceedThreshold_returnFalse()457     public void testValidateUsageTime_foregroundTimeExceedThreshold_returnFalse() {
458         assertThat(BatteryChartPreferenceController.validateUsageTime(
459             createBatteryDiffEntry(
460                 /*foregroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3,
461                 /*backgroundUsageTimeInMs=*/ 0)))
462             .isFalse();
463     }
464 
465     @Test
testValidateUsageTime_backgroundTimeExceedThreshold_returnFalse()466     public void testValidateUsageTime_backgroundTimeExceedThreshold_returnFalse() {
467         assertThat(BatteryChartPreferenceController.validateUsageTime(
468             createBatteryDiffEntry(
469                 /*foregroundUsageTimeInMs=*/ 0,
470                 /*backgroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3)))
471             .isFalse();
472     }
473 
474     @Test
testOnExpand_expandedIsTrue_addSystemEntriesToPreferenceGroup()475     public void testOnExpand_expandedIsTrue_addSystemEntriesToPreferenceGroup() {
476         doReturn(1).when(mAppListGroup).getPreferenceCount();
477         mBatteryChartPreferenceController.mSystemEntries.add(mBatteryDiffEntry);
478         doReturn("label").when(mBatteryDiffEntry).getAppLabel();
479         doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
480         doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
481 
482         mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ true);
483 
484         final ArgumentCaptor<Preference> captor = ArgumentCaptor.forClass(Preference.class);
485         verify(mAppListGroup).addPreference(captor.capture());
486         // Verifies the added preference.
487         assertThat(captor.getValue().getKey()).isEqualTo(PREF_KEY);
488         verify(mMetricsFeatureProvider)
489             .action(
490                 mContext,
491                 SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
492                 true /*isExpanded*/);
493     }
494 
495     @Test
testOnExpand_expandedIsFalse_removeSystemEntriesFromPreferenceGroup()496     public void testOnExpand_expandedIsFalse_removeSystemEntriesFromPreferenceGroup() {
497         doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
498         doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
499         mBatteryChartPreferenceController.mSystemEntries.add(mBatteryDiffEntry);
500         // Verifies the cache is empty first.
501         assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
502 
503         mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ false);
504 
505         verify(mAppListGroup).findPreference(PREF_KEY);
506         verify(mAppListGroup).removePreference(mPowerGaugePreference);
507         assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
508         verify(mMetricsFeatureProvider)
509             .action(
510                 mContext,
511                 SettingsEnums.ACTION_BATTERY_USAGE_EXPAND_ITEM,
512                 false /*isExpanded*/);
513     }
514 
515     @Test
testOnSelect_selectSpecificTimeSlot_logMetric()516     public void testOnSelect_selectSpecificTimeSlot_logMetric() {
517         mBatteryChartPreferenceController.onSelect(1 /*slot index*/);
518 
519         verify(mMetricsFeatureProvider)
520             .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT);
521     }
522 
523     @Test
testOnSelect_selectAll_logMetric()524     public void testOnSelect_selectAll_logMetric() {
525         mBatteryChartPreferenceController.onSelect(
526             BatteryChartView.SELECTED_INDEX_ALL /*slot index*/);
527 
528         verify(mMetricsFeatureProvider)
529             .action(mContext, SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL);
530     }
531 
532     @Test
testRefreshCategoryTitle_setHourIntoBothTitleTextView()533     public void testRefreshCategoryTitle_setHourIntoBothTitleTextView() {
534         mBatteryChartPreferenceController = createController();
535         setUpBatteryHistoryKeys();
536         mBatteryChartPreferenceController.mAppListPrefGroup =
537             spy(new PreferenceCategory(mContext));
538         mBatteryChartPreferenceController.mExpandDividerPreference =
539             spy(new ExpandDividerPreference(mContext));
540         // Simulates select the first slot.
541         mBatteryChartPreferenceController.mTrapezoidIndex = 0;
542 
543         mBatteryChartPreferenceController.refreshCategoryTitle();
544 
545         ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
546         // Verifies the title in the preference group.
547         verify(mBatteryChartPreferenceController.mAppListPrefGroup)
548             .setTitle(captor.capture());
549         assertThat(captor.getValue()).isNotEqualTo("App usage for past 24 hr");
550         // Verifies the title in the expandable divider.
551         captor = ArgumentCaptor.forClass(String.class);
552         verify(mBatteryChartPreferenceController.mExpandDividerPreference)
553             .setTitle(captor.capture());
554         assertThat(captor.getValue()).isNotEqualTo("System usage for past 24 hr");
555     }
556 
557     @Test
testRefreshCategoryTitle_setLast24HrIntoBothTitleTextView()558     public void testRefreshCategoryTitle_setLast24HrIntoBothTitleTextView() {
559         mBatteryChartPreferenceController = createController();
560         mBatteryChartPreferenceController.mAppListPrefGroup =
561             spy(new PreferenceCategory(mContext));
562         mBatteryChartPreferenceController.mExpandDividerPreference =
563             spy(new ExpandDividerPreference(mContext));
564         // Simulates select all condition.
565         mBatteryChartPreferenceController.mTrapezoidIndex =
566             BatteryChartView.SELECTED_INDEX_ALL;
567 
568         mBatteryChartPreferenceController.refreshCategoryTitle();
569 
570         ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
571         // Verifies the title in the preference group.
572         verify(mBatteryChartPreferenceController.mAppListPrefGroup)
573             .setTitle(captor.capture());
574         assertThat(captor.getValue())
575             .isEqualTo("App usage for past 24 hr");
576         // Verifies the title in the expandable divider.
577         captor = ArgumentCaptor.forClass(String.class);
578         verify(mBatteryChartPreferenceController.mExpandDividerPreference)
579             .setTitle(captor.capture());
580         assertThat(captor.getValue())
581             .isEqualTo("System usage for past 24 hr");
582     }
583 
584     @Test
testSetTimestampLabel_nullBatteryHistoryKeys_ignore()585     public void testSetTimestampLabel_nullBatteryHistoryKeys_ignore() {
586         mBatteryChartPreferenceController = createController();
587         mBatteryChartPreferenceController.mBatteryHistoryKeys = null;
588         mBatteryChartPreferenceController.mBatteryChartView =
589             spy(new BatteryChartView(mContext));
590         mBatteryChartPreferenceController.setTimestampLabel();
591 
592         verify(mBatteryChartPreferenceController.mBatteryChartView, never())
593             .setLatestTimestamp(anyLong());
594     }
595 
596     @Test
testSetTimestampLabel_setExpectedTimestampData()597     public void testSetTimestampLabel_setExpectedTimestampData() {
598         mBatteryChartPreferenceController = createController();
599         mBatteryChartPreferenceController.mBatteryChartView =
600             spy(new BatteryChartView(mContext));
601         setUpBatteryHistoryKeys();
602 
603         mBatteryChartPreferenceController.setTimestampLabel();
604 
605         verify(mBatteryChartPreferenceController.mBatteryChartView)
606             .setLatestTimestamp(1619247636826L);
607     }
608 
609     @Test
testSetTimestampLabel_withoutValidTimestamp_setExpectedTimestampData()610     public void testSetTimestampLabel_withoutValidTimestamp_setExpectedTimestampData() {
611         mBatteryChartPreferenceController = createController();
612         mBatteryChartPreferenceController.mBatteryChartView =
613             spy(new BatteryChartView(mContext));
614         mBatteryChartPreferenceController.mBatteryHistoryKeys = new long[] {0L};
615 
616         mBatteryChartPreferenceController.setTimestampLabel();
617 
618         verify(mBatteryChartPreferenceController.mBatteryChartView)
619             .setLatestTimestamp(anyLong());
620     }
621 
622     @Test
testOnSaveInstanceState_restoreSelectedIndexAndExpandState()623     public void testOnSaveInstanceState_restoreSelectedIndexAndExpandState() {
624         final int expectedIndex = 1;
625         final boolean isExpanded = true;
626         final Bundle bundle = new Bundle();
627         mBatteryChartPreferenceController.mTrapezoidIndex = expectedIndex;
628         mBatteryChartPreferenceController.mIsExpanded = isExpanded;
629         mBatteryChartPreferenceController.onSaveInstanceState(bundle);
630         // Replaces the original controller with other values.
631         mBatteryChartPreferenceController.mTrapezoidIndex = -1;
632         mBatteryChartPreferenceController.mIsExpanded = false;
633 
634         mBatteryChartPreferenceController.onCreate(bundle);
635         mBatteryChartPreferenceController.setBatteryHistoryMap(
636              createBatteryHistoryMap());
637 
638         assertThat(mBatteryChartPreferenceController.mTrapezoidIndex)
639             .isEqualTo(expectedIndex);
640         assertThat(mBatteryChartPreferenceController.mIsExpanded).isTrue();
641     }
642 
643     @Test
testIsValidToShowSummary_returnExpectedResult()644     public void testIsValidToShowSummary_returnExpectedResult() {
645         assertThat(mBatteryChartPreferenceController
646                 .isValidToShowSummary("com.google.android.apps.scone"))
647             .isTrue();
648 
649         // Verifies the item which is defined in the array list.
650         assertThat(mBatteryChartPreferenceController
651                 .isValidToShowSummary("com.android.googlequicksearchbox"))
652             .isFalse();
653     }
654 
655     @Test
testIsValidToShowEntry_returnExpectedResult()656     public void testIsValidToShowEntry_returnExpectedResult() {
657         assertThat(mBatteryChartPreferenceController
658                 .isValidToShowEntry("com.google.android.apps.scone"))
659             .isTrue();
660 
661         // Verifies the items which are defined in the array list.
662         assertThat(mBatteryChartPreferenceController
663                 .isValidToShowEntry("com.android.gms.persistent"))
664             .isFalse();
665     }
666 
createBatteryHistoryMap()667     private static Map<Long, Map<String, BatteryHistEntry>> createBatteryHistoryMap() {
668         final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
669         for (int index = 0; index < DESIRED_HISTORY_SIZE; index++) {
670             final ContentValues values = new ContentValues();
671             values.put("batteryLevel", Integer.valueOf(100 - index));
672             final BatteryHistEntry entry = new BatteryHistEntry(values);
673             final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
674             entryMap.put("fake_entry_key" + index, entry);
675             batteryHistoryMap.put(Long.valueOf(index + 1), entryMap);
676         }
677         return batteryHistoryMap;
678     }
679 
createBatteryDiffEntry( long foregroundUsageTimeInMs, long backgroundUsageTimeInMs)680     private BatteryDiffEntry createBatteryDiffEntry(
681             long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
682         return new BatteryDiffEntry(
683             mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs,
684             /*consumePower=*/ 0, mBatteryHistEntry);
685     }
686 
setUpBatteryHistoryKeys()687     private void setUpBatteryHistoryKeys() {
688         mBatteryChartPreferenceController.mBatteryHistoryKeys =
689             new long[] {1619196786769L, 0L, 1619247636826L};
690         ConvertUtils.utcToLocalTimeHour(
691             mContext, /*timestamp=*/ 0, /*is24HourFormat=*/ false);
692     }
693 
createController()694     private BatteryChartPreferenceController createController() {
695         final BatteryChartPreferenceController controller =
696             new BatteryChartPreferenceController(
697                 mContext, "app_list", /*lifecycle=*/ null,
698                 mSettingsActivity, mFragment);
699         controller.mPrefContext = mContext;
700         return controller;
701     }
702 }
703