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.datausage;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.anyBoolean;
23 import static org.mockito.ArgumentMatchers.anyInt;
24 import static org.mockito.ArgumentMatchers.anyString;
25 import static org.mockito.Matchers.eq;
26 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
27 import static org.mockito.Mockito.doNothing;
28 import static org.mockito.Mockito.doReturn;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.spy;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.content.Context;
35 import android.content.pm.ApplicationInfo;
36 import android.content.pm.PackageManager;
37 import android.content.pm.PackageManager.NameNotFoundException;
38 import android.net.NetworkPolicyManager;
39 import android.net.NetworkTemplate;
40 import android.os.Bundle;
41 import android.os.Process;
42 import android.telephony.SubscriptionManager;
43 import android.text.format.DateUtils;
44 import android.util.ArraySet;
45 import android.view.View;
46 
47 import androidx.fragment.app.FragmentActivity;
48 import androidx.preference.Preference;
49 import androidx.preference.PreferenceManager;
50 import androidx.preference.PreferenceScreen;
51 
52 import com.android.settings.applications.AppInfoBase;
53 import com.android.settings.testutils.FakeFeatureFactory;
54 import com.android.settings.testutils.shadow.ShadowDataUsageUtils;
55 import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
56 import com.android.settings.testutils.shadow.ShadowFragment;
57 import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
58 import com.android.settings.widget.EntityHeaderController;
59 import com.android.settingslib.AppItem;
60 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
61 import com.android.settingslib.RestrictedSwitchPreference;
62 import com.android.settingslib.net.NetworkCycleDataForUid;
63 import com.android.settingslib.net.NetworkCycleDataForUidLoader;
64 import com.android.settingslib.net.UidDetail;
65 import com.android.settingslib.net.UidDetailProvider;
66 
67 import org.junit.After;
68 import org.junit.Before;
69 import org.junit.Test;
70 import org.junit.runner.RunWith;
71 import org.mockito.Answers;
72 import org.mockito.Mock;
73 import org.mockito.MockitoAnnotations;
74 import org.robolectric.Robolectric;
75 import org.robolectric.RobolectricTestRunner;
76 import org.robolectric.RuntimeEnvironment;
77 import org.robolectric.annotation.Config;
78 import org.robolectric.shadows.ShadowSubscriptionManager;
79 import org.robolectric.util.ReflectionHelpers;
80 
81 import java.util.ArrayList;
82 import java.util.List;
83 
84 @RunWith(RobolectricTestRunner.class)
85 @Config(shadows = {ShadowEntityHeaderController.class, ShadowRestrictedLockUtilsInternal.class})
86 public class AppDataUsageTest {
87 
88     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
89     private EntityHeaderController mHeaderController;
90     @Mock
91     private PackageManager mPackageManager;
92 
93     private AppDataUsage mFragment;
94 
95     @Before
setUp()96     public void setUp() {
97         MockitoAnnotations.initMocks(this);
98     }
99 
100     @After
tearDown()101     public void tearDown() {
102         ShadowEntityHeaderController.reset();
103     }
104 
105     @Test
106     @Config(shadows = ShadowFragment.class)
onCreate_appUid_shouldGetAppLabelFromAppInfo()107     public void onCreate_appUid_shouldGetAppLabelFromAppInfo() throws NameNotFoundException {
108         mFragment = spy(new AppDataUsage());
109         final FragmentActivity activity = spy(Robolectric.setupActivity(FragmentActivity.class));
110         doReturn(mPackageManager).when(activity).getPackageManager();
111         doReturn(activity).when(mFragment).getActivity();
112         doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
113         ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
114                 FakeFeatureFactory.setupForTest().dashboardFeatureProvider);
115         final String packageName = "testPackage";
116         final int uid = (Process.FIRST_APPLICATION_UID + Process.LAST_APPLICATION_UID) / 2;
117         doReturn(new String[]{packageName}).when(mPackageManager).getPackagesForUid(uid);
118         final String label = "testLabel";
119         final AppItem appItem = new AppItem(uid);
120         appItem.uids.put(uid, true);
121         final ApplicationInfo info = spy(new ApplicationInfo());
122         doReturn(label).when(info).loadLabel(mPackageManager);
123         when(mPackageManager.getApplicationInfoAsUser(
124                 eq(packageName), anyInt() /* flags */, anyInt() /* userId */)).thenReturn(info);
125         final Bundle args = new Bundle();
126         args.putParcelable(AppDataUsage.ARG_APP_ITEM, appItem);
127         args.putInt(AppInfoBase.ARG_PACKAGE_UID, uid);
128         mFragment.setArguments(args);
129 
130         mFragment.onCreate(Bundle.EMPTY);
131 
132         assertThat(mFragment.mLabel).isEqualTo(label);
133     }
134 
135     @Test
136     @Config(shadows = ShadowFragment.class)
onCreate_notAppUid_shouldGetAppLabelFromUidDetailProvider()137     public void onCreate_notAppUid_shouldGetAppLabelFromUidDetailProvider() {
138         mFragment = spy(new AppDataUsage());
139         ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
140                 FakeFeatureFactory.setupForTest().dashboardFeatureProvider);
141         doReturn(Robolectric.setupActivity(FragmentActivity.class)).when(mFragment).getActivity();
142         doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
143         final UidDetailProvider uidDetailProvider = mock(UidDetailProvider.class);
144         doReturn(uidDetailProvider).when(mFragment).getUidDetailProvider();
145         final String label = "testLabel";
146         final int uid = Process.SYSTEM_UID;
147         final UidDetail uidDetail = new UidDetail();
148         uidDetail.label = label;
149         when(uidDetailProvider.getUidDetail(eq(uid), anyBoolean() /* blocking */)).
150                 thenReturn(uidDetail);
151         final AppItem appItem = new AppItem(uid);
152         appItem.uids.put(uid, true);
153         final Bundle args = new Bundle();
154         args.putParcelable(AppDataUsage.ARG_APP_ITEM, appItem);
155         args.putInt(AppInfoBase.ARG_PACKAGE_UID, uid);
156         mFragment.setArguments(args);
157 
158         mFragment.onCreate(Bundle.EMPTY);
159 
160         assertThat(mFragment.mLabel).isEqualTo(label);
161     }
162 
163     @Test
bindAppHeader_allWorkApps_shouldNotShowAppInfoLink()164     public void bindAppHeader_allWorkApps_shouldNotShowAppInfoLink() {
165         ShadowEntityHeaderController.setUseMock(mHeaderController);
166         when(mHeaderController.setRecyclerView(any(), any())).thenReturn(mHeaderController);
167         when(mHeaderController.setUid(anyInt())).thenReturn(mHeaderController);
168 
169         mFragment = spy(new AppDataUsage());
170 
171         when(mFragment.getPreferenceManager())
172                 .thenReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS));
173         doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
174         ReflectionHelpers.setField(mFragment, "mAppItem", mock(AppItem.class));
175 
176         mFragment.onViewCreated(new View(RuntimeEnvironment.application), new Bundle());
177 
178         verify(mHeaderController).setHasAppInfoLink(false);
179     }
180 
181     @Test
bindAppHeader_workApp_shouldSetWorkAppUid()182     public void bindAppHeader_workApp_shouldSetWorkAppUid()
183             throws PackageManager.NameNotFoundException {
184         final int fakeUserId = 100;
185 
186         mFragment = spy(new AppDataUsage());
187         final ArraySet<String> packages = new ArraySet<>();
188         packages.add("pkg");
189         final AppItem appItem = new AppItem(123456789);
190 
191         ReflectionHelpers.setField(mFragment, "mPackageManager", mPackageManager);
192         ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
193         ReflectionHelpers.setField(mFragment, "mPackages", packages);
194 
195         when(mPackageManager.getPackageUidAsUser(anyString(), anyInt()))
196                 .thenReturn(fakeUserId);
197 
198         ShadowEntityHeaderController.setUseMock(mHeaderController);
199         when(mHeaderController.setRecyclerView(any(), any())).thenReturn(mHeaderController);
200         when(mHeaderController.setUid(fakeUserId)).thenReturn(mHeaderController);
201         when(mHeaderController.setHasAppInfoLink(anyBoolean())).thenReturn(mHeaderController);
202 
203         when(mFragment.getPreferenceManager())
204                 .thenReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS));
205         doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
206 
207         mFragment.onViewCreated(new View(RuntimeEnvironment.application), new Bundle());
208 
209         verify(mHeaderController).setHasAppInfoLink(true);
210         verify(mHeaderController).setUid(fakeUserId);
211     }
212 
213     @Test
changePreference_backgroundData_shouldUpdateUI()214     public void changePreference_backgroundData_shouldUpdateUI() {
215         mFragment = spy(new AppDataUsage());
216         final AppItem appItem = new AppItem(123456789);
217         final RestrictedSwitchPreference pref = mock(RestrictedSwitchPreference.class);
218         final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class);
219         ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
220         ReflectionHelpers.setField(mFragment, "mRestrictBackground", pref);
221         ReflectionHelpers.setField(mFragment, "mDataSaverBackend", dataSaverBackend);
222 
223         doNothing().when(mFragment).updatePrefs();
224 
225         mFragment.onPreferenceChange(pref, true /* value */);
226 
227         verify(mFragment).updatePrefs();
228     }
229 
230     @Test
updatePrefs_restrictedByAdmin_shouldDisablePreference()231     public void updatePrefs_restrictedByAdmin_shouldDisablePreference() {
232         mFragment = spy(new AppDataUsage());
233         final int testUid = 123123;
234         final AppItem appItem = new AppItem(testUid);
235         final RestrictedSwitchPreference restrictBackgroundPref
236                 = mock(RestrictedSwitchPreference.class);
237         final RestrictedSwitchPreference unrestrictedDataPref
238                 = mock(RestrictedSwitchPreference.class);
239         final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class);
240         final NetworkPolicyManager networkPolicyManager = mock(NetworkPolicyManager.class);
241         ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
242         ReflectionHelpers.setField(mFragment, "mRestrictBackground", restrictBackgroundPref);
243         ReflectionHelpers.setField(mFragment, "mUnrestrictedData", unrestrictedDataPref);
244         ReflectionHelpers.setField(mFragment, "mDataSaverBackend", dataSaverBackend);
245         ReflectionHelpers.setField(mFragment.services, "mPolicyManager", networkPolicyManager);
246 
247         ShadowRestrictedLockUtilsInternal.setRestricted(true);
248         doReturn(NetworkPolicyManager.POLICY_NONE).when(networkPolicyManager)
249                 .getUidPolicy(testUid);
250 
251         mFragment.updatePrefs();
252 
253         verify(restrictBackgroundPref).setDisabledByAdmin(any(EnforcedAdmin.class));
254         verify(unrestrictedDataPref).setDisabledByAdmin(any(EnforcedAdmin.class));
255     }
256 
257     @Test
bindData_noAppUsageData_shouldHideCycleSpinner()258     public void bindData_noAppUsageData_shouldHideCycleSpinner() {
259         mFragment = spy(new AppDataUsage());
260         final SpinnerPreference cycle = mock(SpinnerPreference.class);
261         ReflectionHelpers.setField(mFragment, "mCycle", cycle);
262         final Preference preference = mock(Preference.class);
263         ReflectionHelpers.setField(mFragment, "mBackgroundUsage", preference);
264         ReflectionHelpers.setField(mFragment, "mForegroundUsage", preference);
265         ReflectionHelpers.setField(mFragment, "mTotalUsage", preference);
266         ReflectionHelpers.setField(mFragment, "mContext", RuntimeEnvironment.application);
267 
268         mFragment.bindData(0 /* position */);
269 
270         verify(cycle).setVisible(false);
271     }
272 
273     @Test
bindData_hasAppUsageData_shouldShowCycleSpinnerAndUpdateUsageSummary()274     public void bindData_hasAppUsageData_shouldShowCycleSpinnerAndUpdateUsageSummary() {
275         mFragment = spy(new AppDataUsage());
276         final Context context = RuntimeEnvironment.application;
277         ReflectionHelpers.setField(mFragment, "mContext", context);
278         final long backgroundBytes = 1234L;
279         final long foregroundBytes = 5678L;
280         final List<NetworkCycleDataForUid> appUsage = new ArrayList<>();
281         appUsage.add(new NetworkCycleDataForUid.Builder()
282                 .setBackgroundUsage(backgroundBytes).setForegroundUsage(foregroundBytes).build());
283         ReflectionHelpers.setField(mFragment, "mUsageData", appUsage);
284         final Preference backgroundPref = mock(Preference.class);
285         ReflectionHelpers.setField(mFragment, "mBackgroundUsage", backgroundPref);
286         final Preference foregroundPref = mock(Preference.class);
287         ReflectionHelpers.setField(mFragment, "mForegroundUsage", foregroundPref);
288         final Preference totalPref = mock(Preference.class);
289         ReflectionHelpers.setField(mFragment, "mTotalUsage", totalPref);
290         final SpinnerPreference cycle = mock(SpinnerPreference.class);
291         ReflectionHelpers.setField(mFragment, "mCycle", cycle);
292 
293         mFragment.bindData(0 /* position */);
294 
295         verify(cycle).setVisible(true);
296         verify(totalPref).setSummary(
297                 DataUsageUtils.formatDataUsage(context, backgroundBytes + foregroundBytes));
298         verify(backgroundPref).setSummary(DataUsageUtils.formatDataUsage(context, backgroundBytes));
299         verify(foregroundPref).setSummary(DataUsageUtils.formatDataUsage(context, foregroundBytes));
300     }
301 
302     @Test
onCreateLoader_categoryApp_shouldQueryDataUsageUsingAppKey()303     public void onCreateLoader_categoryApp_shouldQueryDataUsageUsingAppKey() {
304         mFragment = new AppDataUsage();
305         final Context context = RuntimeEnvironment.application;
306         final int testUid = 123123;
307         final AppItem appItem = new AppItem(testUid);
308         appItem.category = AppItem.CATEGORY_APP;
309         ReflectionHelpers.setField(mFragment, "mContext", context);
310         ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
311         ReflectionHelpers.setField(mFragment, "mTemplate",
312                 NetworkTemplate.buildTemplateWifiWildcard());
313         final long end = System.currentTimeMillis();
314         final long start = end - (DateUtils.WEEK_IN_MILLIS * 4);
315 
316         final NetworkCycleDataForUidLoader loader = (NetworkCycleDataForUidLoader)
317                 mFragment.mUidDataCallbacks.onCreateLoader(0, Bundle.EMPTY);
318 
319         final List<Integer> uids = loader.getUids();
320         assertThat(uids).hasSize(1);
321         assertThat(uids.get(0)).isEqualTo(testUid);
322     }
323 
324     @Test
onCreateLoader_categoryUser_shouldQueryDataUsageUsingAssociatedUids()325     public void onCreateLoader_categoryUser_shouldQueryDataUsageUsingAssociatedUids() {
326         mFragment = new AppDataUsage();
327         final Context context = RuntimeEnvironment.application;
328         final int testUserId = 11;
329         final AppItem appItem = new AppItem(testUserId);
330         appItem.category = AppItem.CATEGORY_USER;
331         appItem.addUid(123);
332         appItem.addUid(456);
333         appItem.addUid(789);
334         ReflectionHelpers.setField(mFragment, "mContext", context);
335         ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
336         ReflectionHelpers.setField(mFragment, "mTemplate",
337                 NetworkTemplate.buildTemplateWifiWildcard());
338         final long end = System.currentTimeMillis();
339         final long start = end - (DateUtils.WEEK_IN_MILLIS * 4);
340 
341         final NetworkCycleDataForUidLoader loader = (NetworkCycleDataForUidLoader)
342                 mFragment.mUidDataCallbacks.onCreateLoader(0, Bundle.EMPTY);
343 
344         final List<Integer> uids = loader.getUids();
345         assertThat(uids).hasSize(3);
346         assertThat(uids.get(0)).isEqualTo(123);
347         assertThat(uids.get(1)).isEqualTo(456);
348         assertThat(uids.get(2)).isEqualTo(789);
349     }
350 
351     @Test
onCreateLoader_hasCyclesSpecified_shouldQueryDataUsageForSpecifiedCycles()352     public void onCreateLoader_hasCyclesSpecified_shouldQueryDataUsageForSpecifiedCycles() {
353         final long startTime = 1521583200000L;
354         final long endTime = 1521676800000L;
355         ArrayList<Long> testCycles = new ArrayList<>();
356         testCycles.add(endTime);
357         testCycles.add(startTime);
358         final int uid = 123;
359         final AppItem appItem = new AppItem(uid);
360         appItem.category = AppItem.CATEGORY_APP;
361         appItem.addUid(uid);
362 
363         mFragment = new AppDataUsage();
364         ReflectionHelpers.setField(mFragment, "mContext", RuntimeEnvironment.application);
365         ReflectionHelpers.setField(mFragment, "mCycles", testCycles);
366         ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
367         ReflectionHelpers.setField(mFragment, "mTemplate",
368                 NetworkTemplate.buildTemplateWifiWildcard());
369 
370         final NetworkCycleDataForUidLoader loader = (NetworkCycleDataForUidLoader)
371                 mFragment.mUidDataCallbacks.onCreateLoader(0 /* id */, Bundle.EMPTY /* args */);
372 
373         final ArrayList<Long> cycles = loader.getCycles();
374         assertThat(cycles).hasSize(2);
375         assertThat(cycles.get(0)).isEqualTo(endTime);
376         assertThat(cycles.get(1)).isEqualTo(startTime);
377     }
378 
379     @Test
onLoadFinished_hasSelectedCycleSpecified_shouldSelectSpecifiedCycle()380     public void onLoadFinished_hasSelectedCycleSpecified_shouldSelectSpecifiedCycle() {
381         final long now = System.currentTimeMillis();
382         final long tenDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 10);
383         final long twentyDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 20);
384         final long thirtyDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 30);
385         final List<NetworkCycleDataForUid> data = new ArrayList<>();
386         NetworkCycleDataForUid.Builder builder = new NetworkCycleDataForUid.Builder();
387         builder.setStartTime(thirtyDaysAgo).setEndTime(twentyDaysAgo).setTotalUsage(9876L);
388         data.add(builder.build());
389         builder = new NetworkCycleDataForUid.Builder();
390         builder.setStartTime(twentyDaysAgo).setEndTime(tenDaysAgo).setTotalUsage(5678L);
391         data.add(builder.build());
392         builder = new NetworkCycleDataForUid.Builder();
393         builder.setStartTime(tenDaysAgo).setEndTime(now).setTotalUsage(1234L);
394         data.add(builder.build());
395 
396         mFragment = new AppDataUsage();
397         ReflectionHelpers.setField(mFragment, "mContext", RuntimeEnvironment.application);
398         ReflectionHelpers.setField(mFragment, "mCycleAdapter", mock(CycleAdapter.class));
399         ReflectionHelpers.setField(mFragment, "mSelectedCycle", tenDaysAgo);
400         final Preference backgroundPref = mock(Preference.class);
401         ReflectionHelpers.setField(mFragment, "mBackgroundUsage", backgroundPref);
402         final Preference foregroundPref = mock(Preference.class);
403         ReflectionHelpers.setField(mFragment, "mForegroundUsage", foregroundPref);
404         final Preference totalPref = mock(Preference.class);
405         ReflectionHelpers.setField(mFragment, "mTotalUsage", totalPref);
406         final SpinnerPreference cycle = mock(SpinnerPreference.class);
407         ReflectionHelpers.setField(mFragment, "mCycle", cycle);
408 
409         mFragment.mUidDataCallbacks.onLoadFinished(null /* loader */, data);
410 
411         verify(cycle).setSelection(1);
412     }
413 
414     @Test
415     @Config(shadows = {ShadowDataUsageUtils.class, ShadowSubscriptionManager.class,
416             ShadowFragment.class})
onCreate_noNetworkTemplateAndInvalidDataSubscription_shouldUseWifiTemplate()417     public void onCreate_noNetworkTemplateAndInvalidDataSubscription_shouldUseWifiTemplate() {
418         ShadowDataUsageUtils.IS_MOBILE_DATA_SUPPORTED = true;
419         ShadowDataUsageUtils.IS_WIFI_SUPPORTED = true;
420         ShadowDataUsageUtils.HAS_SIM = false;
421         ShadowSubscriptionManager.setDefaultDataSubscriptionId(
422                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
423         mFragment = spy(new AppDataUsage());
424         doReturn(Robolectric.setupActivity(FragmentActivity.class)).when(mFragment).getActivity();
425         doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
426         final UidDetailProvider uidDetailProvider = mock(UidDetailProvider.class);
427         doReturn(uidDetailProvider).when(mFragment).getUidDetailProvider();
428         doReturn(new UidDetail()).when(uidDetailProvider).getUidDetail(anyInt(), anyBoolean());
429 
430         ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
431                 FakeFeatureFactory.setupForTest().dashboardFeatureProvider);
432         final Bundle args = new Bundle();
433         args.putInt(AppInfoBase.ARG_PACKAGE_UID, 123123);
434         mFragment.setArguments(args);
435 
436         mFragment.onCreate(Bundle.EMPTY);
437 
438         assertThat(mFragment.mTemplate.getMatchRule())
439                 .isEqualTo(NetworkTemplate.MATCH_WIFI_WILDCARD);
440     }
441 }
442