1 /*
2  * Copyright (C) 2017 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.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.ArgumentMatchers.anyInt;
25 import static org.mockito.ArgumentMatchers.anyLong;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.ArgumentMatchers.nullable;
28 import static org.mockito.Mockito.doAnswer;
29 import static org.mockito.Mockito.doReturn;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.verifyZeroInteractions;
34 import static org.mockito.Mockito.when;
35 
36 import android.app.AppOpsManager;
37 import android.app.backup.BackupManager;
38 import android.app.settings.SettingsEnums;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.pm.ApplicationInfo;
42 import android.content.pm.PackageManager;
43 import android.graphics.drawable.Drawable;
44 import android.os.BatteryStats;
45 import android.os.Bundle;
46 import android.os.UserHandle;
47 import android.util.Pair;
48 
49 import androidx.fragment.app.FragmentActivity;
50 import androidx.loader.app.LoaderManager;
51 import androidx.preference.Preference;
52 import androidx.recyclerview.widget.RecyclerView;
53 
54 import com.android.settings.R;
55 import com.android.settings.SettingsActivity;
56 import com.android.settings.testutils.FakeFeatureFactory;
57 import com.android.settings.testutils.shadow.ShadowActivityManager;
58 import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
59 import com.android.settings.widget.EntityHeaderController;
60 import com.android.settingslib.applications.AppUtils;
61 import com.android.settingslib.applications.ApplicationsState;
62 import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
63 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
64 import com.android.settingslib.core.lifecycle.Lifecycle;
65 import com.android.settingslib.widget.FooterPreference;
66 import com.android.settingslib.widget.LayoutPreference;
67 import com.android.settingslib.widget.RadioButtonPreference;
68 
69 import org.junit.After;
70 import org.junit.Before;
71 import org.junit.Test;
72 import org.junit.runner.RunWith;
73 import org.mockito.Answers;
74 import org.mockito.ArgumentCaptor;
75 import org.mockito.Mock;
76 import org.mockito.MockitoAnnotations;
77 import org.mockito.stubbing.Answer;
78 import org.robolectric.RobolectricTestRunner;
79 import org.robolectric.RuntimeEnvironment;
80 import org.robolectric.annotation.Config;
81 import org.robolectric.util.ReflectionHelpers;
82 
83 @RunWith(RobolectricTestRunner.class)
84 @Config(shadows = {ShadowEntityHeaderController.class, ShadowActivityManager.class})
85 public class AdvancedPowerUsageDetailTest {
86     private static final String APP_LABEL = "app label";
87     private static final String SUMMARY = "summary";
88     private static final String[] PACKAGE_NAME = {"com.android.app"};
89     private static final String USAGE_PERCENT = "16%";
90     private static final String SLOT_TIME = "12 am-2 am";
91     private static final int ICON_ID = 123;
92     private static final int UID = 1;
93     private static final int POWER_MAH = 150;
94     private static final long BACKGROUND_TIME_MS = 100;
95     private static final long FOREGROUND_ACTIVITY_TIME_MS = 123;
96     private static final long FOREGROUND_SERVICE_TIME_MS = 444;
97     private static final long FOREGROUND_TIME_MS =
98             FOREGROUND_ACTIVITY_TIME_MS + FOREGROUND_SERVICE_TIME_MS;
99     private static final long FOREGROUND_SERVICE_TIME_US = FOREGROUND_SERVICE_TIME_MS * 1000;
100     private static final String KEY_PREF_UNRESTRICTED = "unrestricted_pref";
101     private static final String KEY_PREF_OPTIMIZED = "optimized_pref";
102     private static final String KEY_PREF_RESTRICTED = "restricted_pref";
103 
104     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
105     private FragmentActivity mActivity;
106     @Mock
107     private EntityHeaderController mEntityHeaderController;
108     @Mock
109     private LayoutPreference mHeaderPreference;
110     @Mock
111     private ApplicationsState mState;
112     @Mock
113     private ApplicationsState.AppEntry mAppEntry;
114     @Mock
115     private Bundle mBundle;
116     @Mock
117     private BatteryEntry mBatteryEntry;
118     @Mock
119     private PackageManager mPackageManager;
120     @Mock
121     private AppOpsManager mAppOpsManager;
122     @Mock
123     private LoaderManager mLoaderManager;
124     @Mock
125     private BatteryUtils mBatteryUtils;
126     @Mock
127     private BatteryOptimizeUtils mBatteryOptimizeUtils;
128     @Mock
129     private BackupManager mBackupManager;
130 
131     private Context mContext;
132     private Preference mForegroundPreference;
133     private Preference mBackgroundPreference;
134     private FooterPreference mFooterPreference;
135     private RadioButtonPreference mRestrictedPreference;
136     private RadioButtonPreference mOptimizePreference;
137     private RadioButtonPreference mUnrestrictedPreference;
138     private AdvancedPowerUsageDetail mFragment;
139     private SettingsActivity mTestActivity;
140     private FakeFeatureFactory mFeatureFactory;
141     private MetricsFeatureProvider mMetricsFeatureProvider;
142 
143     @Before
setUp()144     public void setUp() {
145         MockitoAnnotations.initMocks(this);
146 
147         mContext = spy(RuntimeEnvironment.application);
148         when(mContext.getPackageName()).thenReturn("foo");
149         mFeatureFactory = FakeFeatureFactory.setupForTest();
150         mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
151 
152         mFragment = spy(new AdvancedPowerUsageDetail());
153         doReturn(mContext).when(mFragment).getContext();
154         doReturn(mActivity).when(mFragment).getActivity();
155         doReturn(SUMMARY).when(mFragment).getString(anyInt());
156         doReturn(APP_LABEL).when(mBundle).getString(nullable(String.class));
157         when(mFragment.getArguments()).thenReturn(mBundle);
158         doReturn(mLoaderManager).when(mFragment).getLoaderManager();
159         when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
160                 .thenReturn(true);
161 
162         ShadowEntityHeaderController.setUseMock(mEntityHeaderController);
163         doReturn(mEntityHeaderController).when(mEntityHeaderController)
164                 .setRecyclerView(nullable(RecyclerView.class), nullable(Lifecycle.class));
165         doReturn(mEntityHeaderController).when(mEntityHeaderController)
166                 .setButtonActions(anyInt(), anyInt());
167         doReturn(mEntityHeaderController).when(mEntityHeaderController)
168                 .setIcon(nullable(Drawable.class));
169         doReturn(mEntityHeaderController).when(mEntityHeaderController).setIcon(nullable(
170                 ApplicationsState.AppEntry.class));
171         doReturn(mEntityHeaderController).when(mEntityHeaderController)
172                 .setLabel(nullable(String.class));
173         doReturn(mEntityHeaderController).when(mEntityHeaderController)
174                 .setLabel(nullable(String.class));
175         doReturn(mEntityHeaderController).when(mEntityHeaderController)
176                 .setLabel(nullable(ApplicationsState.AppEntry.class));
177         doReturn(mEntityHeaderController).when(mEntityHeaderController)
178                 .setSummary(nullable(String.class));
179 
180         when(mBatteryEntry.getUid()).thenReturn(UID);
181         when(mBatteryEntry.getLabel()).thenReturn(APP_LABEL);
182         when(mBatteryEntry.getTimeInBackgroundMs()).thenReturn(BACKGROUND_TIME_MS);
183         when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(FOREGROUND_TIME_MS);
184         mBatteryEntry.iconId = ICON_ID;
185 
186         mFragment.mHeaderPreference = mHeaderPreference;
187         mFragment.mState = mState;
188         mFragment.mEnableTriState = true;
189         mFragment.mBatteryUtils = new BatteryUtils(RuntimeEnvironment.application);
190         mFragment.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
191         mFragment.mBackupManager = mBackupManager;
192         mAppEntry.info = mock(ApplicationInfo.class);
193 
194         mTestActivity = spy(new SettingsActivity());
195         doReturn(mPackageManager).when(mTestActivity).getPackageManager();
196         doReturn(mPackageManager).when(mActivity).getPackageManager();
197         doReturn(mAppOpsManager).when(mTestActivity).getSystemService(Context.APP_OPS_SERVICE);
198 
199         mBatteryUtils = spy(new BatteryUtils(mContext));
200         doReturn(FOREGROUND_SERVICE_TIME_US).when(mBatteryUtils).getForegroundServiceTotalTimeUs(
201                 any(BatteryStats.Uid.class), anyLong());
202 
203         final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
204 
205         Answer<Void> callable = invocation -> {
206             mBundle = captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
207             System.out.println("mBundle = " + mBundle);
208             return null;
209         };
210         doAnswer(callable).when(mActivity).startActivityAsUser(captor.capture(),
211                 nullable(UserHandle.class));
212         doAnswer(callable).when(mActivity).startActivity(captor.capture());
213 
214         mForegroundPreference = new Preference(mContext);
215         mBackgroundPreference = new Preference(mContext);
216         mFooterPreference = new FooterPreference(mContext);
217         mRestrictedPreference = new RadioButtonPreference(mContext);
218         mOptimizePreference = new RadioButtonPreference(mContext);
219         mUnrestrictedPreference = new RadioButtonPreference(mContext);
220         mFragment.mForegroundPreference = mForegroundPreference;
221         mFragment.mBackgroundPreference = mBackgroundPreference;
222         mFragment.mFooterPreference = mFooterPreference;
223         mFragment.mRestrictedPreference = mRestrictedPreference;
224         mFragment.mOptimizePreference = mOptimizePreference;
225         mFragment.mUnrestrictedPreference = mUnrestrictedPreference;
226     }
227 
228     @After
reset()229     public void reset() {
230         ShadowEntityHeaderController.reset();
231     }
232 
233     @Test
testGetPreferenceScreenResId_returnNewLayout()234     public void testGetPreferenceScreenResId_returnNewLayout() {
235         assertThat(mFragment.getPreferenceScreenResId()).isEqualTo(R.xml.power_usage_detail);
236     }
237 
238     @Test
testGetPreferenceScreenResId_disableTriState_returnLegacyLayout()239     public void testGetPreferenceScreenResId_disableTriState_returnLegacyLayout() {
240         mFragment.mEnableTriState = false;
241         assertThat(mFragment.getPreferenceScreenResId()).isEqualTo(R.xml.power_usage_detail_legacy);
242     }
243 
244     @Test
testInitHeader_NoAppEntry_BuildByBundle()245     public void testInitHeader_NoAppEntry_BuildByBundle() {
246         mFragment.mAppEntry = null;
247         mFragment.initHeader();
248 
249         verify(mEntityHeaderController).setIcon(nullable(Drawable.class));
250         verify(mEntityHeaderController).setLabel(APP_LABEL);
251     }
252 
253     @Test
testInitHeader_HasAppEntry_BuildByAppEntry()254     public void testInitHeader_HasAppEntry_BuildByAppEntry() {
255         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
256                 new InstantAppDataProvider() {
257                     @Override
258                     public boolean isInstantApp(ApplicationInfo info) {
259                         return false;
260                     }
261                 });
262         mFragment.mAppEntry = mAppEntry;
263         mFragment.initHeader();
264 
265         verify(mEntityHeaderController).setIcon(mAppEntry);
266         verify(mEntityHeaderController).setLabel(mAppEntry);
267         verify(mEntityHeaderController).setIsInstantApp(false);
268     }
269 
270     @Test
testInitHeader_HasAppEntry_InstantApp()271     public void testInitHeader_HasAppEntry_InstantApp() {
272         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
273                 new InstantAppDataProvider() {
274                     @Override
275                     public boolean isInstantApp(ApplicationInfo info) {
276                         return true;
277                     }
278                 });
279         mFragment.mAppEntry = mAppEntry;
280         mFragment.initHeader();
281 
282         verify(mEntityHeaderController).setIcon(mAppEntry);
283         verify(mEntityHeaderController).setLabel(mAppEntry);
284         verify(mEntityHeaderController).setIsInstantApp(true);
285     }
286 
287     @Test
testInitHeader_noUsageTimeAndGraphDisabled_hasCorrectSummary()288     public void testInitHeader_noUsageTimeAndGraphDisabled_hasCorrectSummary() {
289         when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
290                 .thenReturn(false);
291 
292         Bundle bundle = new Bundle(2);
293         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, /* value */ 0);
294         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, /* value */ 0);
295         when(mFragment.getArguments()).thenReturn(bundle);
296 
297         mFragment.initHeader();
298 
299         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
300         verify(mEntityHeaderController).setSummary(captor.capture());
301         assertThat(captor.getValue().toString())
302                 .isEqualTo("No usage from last full charge");
303     }
304 
305     @Test
testInitHeader_bgTwoMinFgZeroAndGraphDisabled_hasCorrectSummary()306     public void testInitHeader_bgTwoMinFgZeroAndGraphDisabled_hasCorrectSummary() {
307         when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
308                 .thenReturn(false);
309 
310         final long backgroundTimeTwoMinutes = 120000;
311         final long foregroundTimeZero = 0;
312         Bundle bundle = new Bundle(2);
313         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeTwoMinutes);
314         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeZero);
315         when(mFragment.getArguments()).thenReturn(bundle);
316 
317         mFragment.initHeader();
318 
319         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
320         verify(mEntityHeaderController).setSummary(captor.capture());
321         assertThat(captor.getValue().toString())
322                 .isEqualTo("2 min background from last full charge");
323     }
324 
325     @Test
testInitHeader_bgLessThanAMinFgZeroAndGraphDisabled_hasCorrectSummary()326     public void testInitHeader_bgLessThanAMinFgZeroAndGraphDisabled_hasCorrectSummary() {
327         when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
328                 .thenReturn(false);
329 
330         final long backgroundTimeLessThanAMinute = 59999;
331         final long foregroundTimeZero = 0;
332         Bundle bundle = new Bundle(2);
333         bundle.putLong(
334                 AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeLessThanAMinute);
335         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeZero);
336         when(mFragment.getArguments()).thenReturn(bundle);
337 
338         mFragment.initHeader();
339 
340         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
341         verify(mEntityHeaderController).setSummary(captor.capture());
342         assertThat(captor.getValue().toString())
343                 .isEqualTo("Background less than a minute from last full charge");
344     }
345 
346     @Test
testInitHeader_totalUsageLessThanAMinAndGraphDisabled_hasCorrectSummary()347     public void testInitHeader_totalUsageLessThanAMinAndGraphDisabled_hasCorrectSummary() {
348         when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
349                 .thenReturn(false);
350 
351         final long backgroundTimeLessThanHalfMinute = 20000;
352         final long foregroundTimeLessThanHalfMinute = 20000;
353         Bundle bundle = new Bundle(2);
354         bundle.putLong(
355                 AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeLessThanHalfMinute);
356         bundle.putLong(
357                 AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeLessThanHalfMinute);
358         when(mFragment.getArguments()).thenReturn(bundle);
359 
360         mFragment.initHeader();
361 
362         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
363         verify(mEntityHeaderController).setSummary(captor.capture());
364         assertThat(captor.getValue().toString())
365                 .isEqualTo("Total less than a minute from last full charge");
366     }
367 
368     @Test
testInitHeader_TotalAMinutesBgLessThanAMinAndGraphDisabled_hasCorrectSummary()369     public void testInitHeader_TotalAMinutesBgLessThanAMinAndGraphDisabled_hasCorrectSummary() {
370         when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
371                 .thenReturn(false);
372 
373         final long backgroundTimeZero = 59999;
374         final long foregroundTimeTwoMinutes = 1;
375         Bundle bundle = new Bundle(2);
376         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero);
377         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes);
378         when(mFragment.getArguments()).thenReturn(bundle);
379 
380         mFragment.initHeader();
381 
382         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
383         verify(mEntityHeaderController).setSummary(captor.capture());
384         assertThat(captor.getValue().toString())
385                 .isEqualTo("1 min total • background less than a minute\nfrom last full charge");
386     }
387 
388     @Test
testInitHeader_TotalAMinBackgroundZeroAndGraphDisabled_hasCorrectSummary()389     public void testInitHeader_TotalAMinBackgroundZeroAndGraphDisabled_hasCorrectSummary() {
390         when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
391                 .thenReturn(false);
392         final long backgroundTimeZero = 0;
393         final long foregroundTimeAMinutes = 60000;
394         Bundle bundle = new Bundle(2);
395         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero);
396         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeAMinutes);
397         when(mFragment.getArguments()).thenReturn(bundle);
398 
399         mFragment.initHeader();
400 
401         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
402         verify(mEntityHeaderController).setSummary(captor.capture());
403         assertThat(captor.getValue().toString())
404                 .isEqualTo("1 min total from last full charge");
405     }
406 
407     @Test
testInitHeader_fgTwoMinBgFourMinAndGraphDisabled_hasCorrectSummary()408     public void testInitHeader_fgTwoMinBgFourMinAndGraphDisabled_hasCorrectSummary() {
409         when(mFeatureFactory.powerUsageFeatureProvider.isChartGraphEnabled(mContext))
410                 .thenReturn(false);
411         final long backgroundTimeFourMinute = 240000;
412         final long foregroundTimeTwoMinutes = 120000;
413         Bundle bundle = new Bundle(2);
414         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeFourMinute);
415         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes);
416         when(mFragment.getArguments()).thenReturn(bundle);
417         mFragment.initHeader();
418 
419         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
420         verify(mEntityHeaderController).setSummary(captor.capture());
421         assertThat(captor.getValue().toString())
422                 .isEqualTo("6 min total • 4 min background\nfrom last full charge");
423     }
424 
425     @Test
testInitHeader_noUsageTime_hasCorrectSummary()426     public void testInitHeader_noUsageTime_hasCorrectSummary() {
427         Bundle bundle = new Bundle(2);
428         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, /* value */ 0);
429         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, /* value */ 0);
430         when(mFragment.getArguments()).thenReturn(bundle);
431 
432         mFragment.initHeader();
433 
434         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
435         verify(mEntityHeaderController).setSummary(captor.capture());
436         assertThat(captor.getValue().toString())
437                 .isEqualTo("No usage for past 24 hr");
438     }
439 
440     @Test
testInitHeader_noUsageTimeButConsumedPower_hasEmptySummary()441     public void testInitHeader_noUsageTimeButConsumedPower_hasEmptySummary() {
442         Bundle bundle = new Bundle(3);
443         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, /* value */ 0);
444         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, /* value */ 0);
445         bundle.putInt(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_AMOUNT, /* value */ 10);
446         when(mFragment.getArguments()).thenReturn(bundle);
447 
448         mFragment.initHeader();
449 
450         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
451         verify(mEntityHeaderController).setSummary(captor.capture());
452         assertThat(captor.getValue().toString()).isEmpty();
453     }
454 
455     @Test
testInitHeader_backgroundTwoMinForegroundZero_hasCorrectSummary()456     public void testInitHeader_backgroundTwoMinForegroundZero_hasCorrectSummary() {
457         final long backgroundTimeTwoMinutes = 120000;
458         final long foregroundTimeZero = 0;
459         Bundle bundle = new Bundle(2);
460         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeTwoMinutes);
461         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeZero);
462         when(mFragment.getArguments()).thenReturn(bundle);
463 
464         mFragment.initHeader();
465 
466         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
467         verify(mEntityHeaderController).setSummary(captor.capture());
468         assertThat(captor.getValue().toString())
469                 .isEqualTo("2 min background for past 24 hr");
470     }
471 
472     @Test
testInitHeader_backgroundLessThanAMinForegroundZero_hasCorrectSummary()473     public void testInitHeader_backgroundLessThanAMinForegroundZero_hasCorrectSummary() {
474         final long backgroundTimeLessThanAMinute = 59999;
475         final long foregroundTimeZero = 0;
476         Bundle bundle = new Bundle(2);
477         bundle.putLong(
478                 AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeLessThanAMinute);
479         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeZero);
480         when(mFragment.getArguments()).thenReturn(bundle);
481 
482         mFragment.initHeader();
483 
484         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
485         verify(mEntityHeaderController).setSummary(captor.capture());
486         assertThat(captor.getValue().toString())
487                 .isEqualTo("Background less than a minute for past 24 hr");
488     }
489 
490     @Test
testInitHeader_totalUsageLessThanAMin_hasCorrectSummary()491     public void testInitHeader_totalUsageLessThanAMin_hasCorrectSummary() {
492         final long backgroundTimeLessThanHalfMinute = 20000;
493         final long foregroundTimeLessThanHalfMinute = 20000;
494         Bundle bundle = new Bundle(2);
495         bundle.putLong(
496                 AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeLessThanHalfMinute);
497         bundle.putLong(
498                 AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeLessThanHalfMinute);
499         when(mFragment.getArguments()).thenReturn(bundle);
500 
501         mFragment.initHeader();
502 
503         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
504         verify(mEntityHeaderController).setSummary(captor.capture());
505         assertThat(captor.getValue().toString())
506                 .isEqualTo("Total less than a minute for past 24 hr");
507     }
508 
509     @Test
testInitHeader_TotalAMinutesBackgroundLessThanAMin_hasCorrectSummary()510     public void testInitHeader_TotalAMinutesBackgroundLessThanAMin_hasCorrectSummary() {
511         final long backgroundTimeZero = 59999;
512         final long foregroundTimeTwoMinutes = 1;
513         Bundle bundle = new Bundle(2);
514         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero);
515         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes);
516         when(mFragment.getArguments()).thenReturn(bundle);
517 
518         mFragment.initHeader();
519 
520         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
521         verify(mEntityHeaderController).setSummary(captor.capture());
522         assertThat(captor.getValue().toString())
523                 .isEqualTo("1 min total • background less than a minute\nfor past 24 hr");
524     }
525 
526     @Test
testInitHeader_TotalAMinBackgroundZero_hasCorrectSummary()527     public void testInitHeader_TotalAMinBackgroundZero_hasCorrectSummary() {
528         final long backgroundTimeZero = 0;
529         final long foregroundTimeAMinutes = 60000;
530         Bundle bundle = new Bundle(2);
531         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero);
532         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeAMinutes);
533         when(mFragment.getArguments()).thenReturn(bundle);
534 
535         mFragment.initHeader();
536 
537         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
538         verify(mEntityHeaderController).setSummary(captor.capture());
539         assertThat(captor.getValue().toString())
540                 .isEqualTo("1 min total for past 24 hr");
541     }
542 
543     @Test
testInitHeader_foregroundTwoMinBackgroundFourMin_hasCorrectSummary()544     public void testInitHeader_foregroundTwoMinBackgroundFourMin_hasCorrectSummary() {
545         final long backgroundTimeFourMinute = 240000;
546         final long foregroundTimeTwoMinutes = 120000;
547         Bundle bundle = new Bundle(2);
548         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeFourMinute);
549         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes);
550         when(mFragment.getArguments()).thenReturn(bundle);
551         mFragment.initHeader();
552 
553         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
554         verify(mEntityHeaderController).setSummary(captor.capture());
555         assertThat(captor.getValue().toString())
556                 .isEqualTo("6 min total • 4 min background\nfor past 24 hr");
557     }
558 
559     @Test
testInitHeader_totalUsageLessThanAMinWithSlotTime_hasCorrectSummary()560     public void testInitHeader_totalUsageLessThanAMinWithSlotTime_hasCorrectSummary() {
561         final long backgroundTimeLessThanHalfMinute = 20000;
562         final long foregroundTimeLessThanHalfMinute = 20000;
563         Bundle bundle = new Bundle(2);
564         bundle.putLong(
565                 AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeLessThanHalfMinute);
566         bundle.putLong(
567                 AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeLessThanHalfMinute);
568         bundle.putString(AdvancedPowerUsageDetail.EXTRA_SLOT_TIME, SLOT_TIME);
569         when(mFragment.getArguments()).thenReturn(bundle);
570 
571         mFragment.initHeader();
572 
573         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
574         verify(mEntityHeaderController).setSummary(captor.capture());
575         assertThat(captor.getValue().toString())
576                 .isEqualTo("Total less than a minute for 12 am-2 am");
577     }
578 
579     @Test
testInitHeader_TotalAMinBackgroundLessThanAMinWithSlotTime_hasCorrectSummary()580     public void testInitHeader_TotalAMinBackgroundLessThanAMinWithSlotTime_hasCorrectSummary() {
581         final long backgroundTimeZero = 59999;
582         final long foregroundTimeTwoMinutes = 1;
583         Bundle bundle = new Bundle(2);
584         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero);
585         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes);
586         bundle.putString(AdvancedPowerUsageDetail.EXTRA_SLOT_TIME, SLOT_TIME);
587         when(mFragment.getArguments()).thenReturn(bundle);
588 
589         mFragment.initHeader();
590 
591         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
592         verify(mEntityHeaderController).setSummary(captor.capture());
593         assertThat(captor.getValue().toString())
594                 .isEqualTo("1 min total • background less than a minute\nfor 12 am-2 am");
595     }
596 
597     @Test
testInitHeader_TotalAMinBackgroundZeroWithSlotTime_hasCorrectSummary()598     public void testInitHeader_TotalAMinBackgroundZeroWithSlotTime_hasCorrectSummary() {
599         final long backgroundTimeZero = 0;
600         final long foregroundTimeAMinutes = 60000;
601         Bundle bundle = new Bundle(2);
602         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero);
603         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeAMinutes);
604         bundle.putString(AdvancedPowerUsageDetail.EXTRA_SLOT_TIME, SLOT_TIME);
605         when(mFragment.getArguments()).thenReturn(bundle);
606 
607         mFragment.initHeader();
608 
609         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
610         verify(mEntityHeaderController).setSummary(captor.capture());
611         assertThat(captor.getValue().toString())
612                 .isEqualTo("1 min total for 12 am-2 am");
613     }
614 
615     @Test
testInitHeader_foregroundTwoMinBackgroundFourMinWithSlotTime_hasCorrectSummary()616     public void testInitHeader_foregroundTwoMinBackgroundFourMinWithSlotTime_hasCorrectSummary() {
617         final long backgroundTimeFourMinute = 240000;
618         final long foregroundTimeTwoMinutes = 120000;
619         Bundle bundle = new Bundle(2);
620         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeFourMinute);
621         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes);
622         bundle.putString(AdvancedPowerUsageDetail.EXTRA_SLOT_TIME, SLOT_TIME);
623         when(mFragment.getArguments()).thenReturn(bundle);
624         mFragment.initHeader();
625 
626         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
627         verify(mEntityHeaderController).setSummary(captor.capture());
628         assertThat(captor.getValue().toString())
629                 .isEqualTo("6 min total • 4 min background\nfor 12 am-2 am");
630     }
631 
632     @Test
testStartBatteryDetailPage_hasBasicData()633     public void testStartBatteryDetailPage_hasBasicData() {
634         AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
635                 mBatteryEntry, USAGE_PERCENT, /*isValidToShowSummary=*/ true);
636 
637         assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID);
638         assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME))
639             .isEqualTo(BACKGROUND_TIME_MS);
640         assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME))
641             .isEqualTo(FOREGROUND_TIME_MS);
642         assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT))
643             .isEqualTo(USAGE_PERCENT);
644     }
645 
646     @Test
testStartBatteryDetailPage_invalidToShowSummary_noFGBDData()647     public void testStartBatteryDetailPage_invalidToShowSummary_noFGBDData() {
648         AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
649                 mBatteryEntry, USAGE_PERCENT, /*isValidToShowSummary=*/ false);
650 
651         assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID);
652         assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME))
653                 .isEqualTo(0);
654         assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME))
655                 .isEqualTo(0);
656         assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT))
657                 .isEqualTo(USAGE_PERCENT);
658     }
659 
660     @Test
testStartBatteryDetailPage_NormalApp()661     public void testStartBatteryDetailPage_NormalApp() {
662         when(mBatteryEntry.getDefaultPackageName()).thenReturn(PACKAGE_NAME[0]);
663 
664         AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
665                 mBatteryEntry, USAGE_PERCENT, /*isValidToShowSummary=*/ true);
666 
667         assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)).isEqualTo(
668                 PACKAGE_NAME[0]);
669     }
670 
671     @Test
testStartBatteryDetailPage_SystemApp()672     public void testStartBatteryDetailPage_SystemApp() {
673         when(mBatteryEntry.getDefaultPackageName()).thenReturn(null);
674 
675         AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
676                 mBatteryEntry, USAGE_PERCENT, /*isValidToShowSummary=*/ true);
677 
678         assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_LABEL)).isEqualTo(APP_LABEL);
679         assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_ICON_ID)).isEqualTo(ICON_ID);
680         assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)).isNull();
681     }
682 
683     @Test
testStartBatteryDetailPage_WorkApp()684     public void testStartBatteryDetailPage_WorkApp() {
685         final int appUid = 1010019;
686         doReturn(appUid).when(mBatteryEntry).getUid();
687 
688         AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
689                 mBatteryEntry, USAGE_PERCENT, /*isValidToShowSummary=*/ true);
690 
691         verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(10)));
692     }
693 
694     @Test
testStartBatteryDetailPage_typeUser_startByCurrentUser()695     public void testStartBatteryDetailPage_typeUser_startByCurrentUser() {
696         when(mBatteryEntry.isUserEntry()).thenReturn(true);
697 
698         final int currentUser = 20;
699         ShadowActivityManager.setCurrentUser(currentUser);
700         AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
701                 mBatteryEntry, USAGE_PERCENT, /*isValidToShowSummary=*/ true);
702 
703         verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(currentUser)));
704     }
705 
706     @Test
testStartBatteryDetailPage_noBatteryUsage_hasBasicData()707     public void testStartBatteryDetailPage_noBatteryUsage_hasBasicData() {
708         final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
709 
710         AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, PACKAGE_NAME[0]);
711 
712         verify(mActivity).startActivity(captor.capture());
713 
714         assertThat(captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS)
715             .getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME))
716             .isEqualTo(PACKAGE_NAME[0]);
717 
718         assertThat(captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS)
719             .getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT))
720             .isEqualTo("0%");
721     }
722 
723     @Test
testStartBatteryDetailPage_batteryEntryNotExisted_extractUidFromPackageName()724     public void testStartBatteryDetailPage_batteryEntryNotExisted_extractUidFromPackageName() throws
725             PackageManager.NameNotFoundException {
726         doReturn(UID).when(mPackageManager).getPackageUid(PACKAGE_NAME[0], 0 /* no flag */);
727 
728         AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment, PACKAGE_NAME[0]);
729 
730         assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID);
731     }
732 
733     @Test
testInitPreference_hasCorrectSummary()734     public void testInitPreference_hasCorrectSummary() {
735         Bundle bundle = new Bundle(4);
736         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, BACKGROUND_TIME_MS);
737         bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, FOREGROUND_TIME_MS);
738         bundle.putString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT, USAGE_PERCENT);
739         bundle.putInt(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_AMOUNT, POWER_MAH);
740         when(mFragment.getArguments()).thenReturn(bundle);
741 
742         doReturn(mContext.getText(R.string.battery_used_for)).when(mFragment).getText(
743                 R.string.battery_used_for);
744         doReturn(mContext.getText(R.string.battery_active_for)).when(mFragment).getText(
745                 R.string.battery_active_for);
746 
747         mFragment.initPreference(mContext);
748 
749         assertThat(mForegroundPreference.getSummary().toString()).isEqualTo("Used for 0 min");
750         assertThat(mBackgroundPreference.getSummary().toString()).isEqualTo("Active for 0 min");
751     }
752 
753     @Test
testInitPreferenceForTriState_isValidPackageName_hasCorrectString()754     public void testInitPreferenceForTriState_isValidPackageName_hasCorrectString() {
755         when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(false);
756 
757         mFragment.initPreferenceForTriState(mContext);
758 
759         assertThat(mFooterPreference.getTitle().toString())
760                 .isEqualTo("This app requires optimized battery usage.");
761     }
762 
763     @Test
testInitPreferenceForTriState_isSystemOrDefaultApp_hasCorrectString()764     public void testInitPreferenceForTriState_isSystemOrDefaultApp_hasCorrectString() {
765         when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
766         when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
767 
768         mFragment.initPreferenceForTriState(mContext);
769 
770         assertThat(mFooterPreference.getTitle()
771                 .toString()).isEqualTo("This app requires unrestricted battery usage.");
772     }
773 
774     @Test
testInitPreferenceForTriState_hasCorrectString()775     public void testInitPreferenceForTriState_hasCorrectString() {
776         when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
777         when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
778 
779         mFragment.initPreferenceForTriState(mContext);
780 
781         assertThat(mFooterPreference.getTitle().toString())
782                 .isEqualTo("Changing how an app uses your battery can affect its performance.");
783     }
784 
785     @Test
testOnRadioButtonClicked_clickOptimizePref_optimizePreferenceChecked()786     public void testOnRadioButtonClicked_clickOptimizePref_optimizePreferenceChecked() {
787         mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
788         mRestrictedPreference.setKey(KEY_PREF_RESTRICTED);
789         mUnrestrictedPreference.setKey(KEY_PREF_UNRESTRICTED);
790         mFragment.onRadioButtonClicked(mOptimizePreference);
791 
792         assertThat(mOptimizePreference.isChecked()).isTrue();
793         assertThat(mRestrictedPreference.isChecked()).isFalse();
794         assertThat(mUnrestrictedPreference.isChecked()).isFalse();
795     }
796 
797     @Test
testOnPause_optimizationModeChanged_logPreference()798     public void testOnPause_optimizationModeChanged_logPreference() {
799         final int mode = BatteryOptimizeUtils.MODE_RESTRICTED;
800         mFragment.mOptimizationMode = mode;
801         when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(mode);
802         mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
803 
804         mFragment.onRadioButtonClicked(mOptimizePreference);
805         mFragment.onPause();
806 
807         verify(mMetricsFeatureProvider)
808                 .action(
809                         SettingsEnums.OPEN_APP_BATTERY_USAGE,
810                         SettingsEnums.ACTION_APP_BATTERY_USAGE_OPTIMIZED,
811                         SettingsEnums.OPEN_APP_BATTERY_USAGE,
812                         /* package name*/ "none",
813                         /* consumed battery */ 0);
814     }
815 
816     @Test
testOnPause_optimizationModeIsNotChanged_notInvokeLogging()817     public void testOnPause_optimizationModeIsNotChanged_notInvokeLogging() {
818         final int mode = BatteryOptimizeUtils.MODE_OPTIMIZED;
819         mFragment.mOptimizationMode = mode;
820         when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(mode);
821         mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
822 
823         mFragment.onRadioButtonClicked(mOptimizePreference);
824         mFragment.onPause();
825 
826         verifyZeroInteractions(mMetricsFeatureProvider);
827     }
828 
829     @Test
notifyBackupManager_optimizationModeIsNotChanged_notInvokeDataChanged()830     public void notifyBackupManager_optimizationModeIsNotChanged_notInvokeDataChanged() {
831         final int mode = BatteryOptimizeUtils.MODE_RESTRICTED;
832         mFragment.mOptimizationMode = mode;
833         when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(mode);
834 
835         mFragment.notifyBackupManager();
836 
837         verifyZeroInteractions(mBackupManager);
838     }
839 
840     @Test
notifyBackupManager_optimizationModeIsChanged_invokeDataChanged()841     public void notifyBackupManager_optimizationModeIsChanged_invokeDataChanged() {
842         mFragment.mOptimizationMode = BatteryOptimizeUtils.MODE_RESTRICTED;
843         when(mBatteryOptimizeUtils.getAppOptimizationMode())
844                 .thenReturn(BatteryOptimizeUtils.MODE_UNRESTRICTED);
845 
846         mFragment.notifyBackupManager();
847 
848         verify(mBackupManager).dataChanged();
849     }
850 
851     @Test
notifyBackupManager_triStateIsNotEnabled_notInvokeDataChanged()852     public void notifyBackupManager_triStateIsNotEnabled_notInvokeDataChanged() {
853         mFragment.mOptimizationMode = BatteryOptimizeUtils.MODE_RESTRICTED;
854         when(mBatteryOptimizeUtils.getAppOptimizationMode())
855                 .thenReturn(BatteryOptimizeUtils.MODE_UNRESTRICTED);
856         mFragment.mEnableTriState = false;
857 
858         mFragment.onPause();
859 
860         verifyZeroInteractions(mBackupManager);
861     }
862 }
863