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