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.assertTrue;
22 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
23 import static org.mockito.Mockito.any;
24 import static org.mockito.Mockito.anyBoolean;
25 import static org.mockito.Mockito.anyInt;
26 import static org.mockito.Mockito.anyString;
27 import static org.mockito.Mockito.doNothing;
28 import static org.mockito.Mockito.doReturn;
29 import static org.mockito.Mockito.eq;
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.util.ArraySet;
45 
46 import androidx.fragment.app.FragmentActivity;
47 import androidx.preference.PreferenceManager;
48 import androidx.preference.PreferenceScreen;
49 import androidx.recyclerview.widget.RecyclerView;
50 
51 import com.android.settings.applications.AppInfoBase;
52 import com.android.settings.testutils.FakeFeatureFactory;
53 import com.android.settings.testutils.shadow.ShadowDataUsageUtils;
54 import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
55 import com.android.settings.testutils.shadow.ShadowFragment;
56 import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
57 import com.android.settings.widget.EntityHeaderController;
58 import com.android.settingslib.AppItem;
59 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
60 import com.android.settingslib.RestrictedSwitchPreference;
61 import com.android.settingslib.core.AbstractPreferenceController;
62 import com.android.settingslib.net.UidDetail;
63 import com.android.settingslib.net.UidDetailProvider;
64 
65 import org.junit.After;
66 import org.junit.Before;
67 import org.junit.Test;
68 import org.junit.runner.RunWith;
69 import org.mockito.Answers;
70 import org.mockito.Mock;
71 import org.mockito.MockitoAnnotations;
72 import org.robolectric.Robolectric;
73 import org.robolectric.RobolectricTestRunner;
74 import org.robolectric.RuntimeEnvironment;
75 import org.robolectric.annotation.Config;
76 import org.robolectric.shadows.ShadowSubscriptionManager;
77 import org.robolectric.util.ReflectionHelpers;
78 
79 import java.util.List;
80 
81 @RunWith(RobolectricTestRunner.class)
82 @Config(shadows = {ShadowEntityHeaderController.class, ShadowRestrictedLockUtilsInternal.class})
83 public class AppDataUsageTest {
84 
85     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
86     private EntityHeaderController mHeaderController;
87     @Mock
88     private PackageManager mPackageManager;
89 
90     private AppDataUsage mFragment;
91 
92     @Before
setUp()93     public void setUp() {
94         MockitoAnnotations.initMocks(this);
95 
96         ShadowEntityHeaderController.setUseMock(mHeaderController);
97         when(mHeaderController.setUid(anyInt())).thenReturn(mHeaderController);
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 TestFragment());
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 TestFragment());
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         mFragment = spy(new TestFragment());
166 
167         when(mFragment.getPreferenceManager())
168                 .thenReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS));
169         doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
170         ReflectionHelpers.setField(mFragment, "mAppItem", mock(AppItem.class));
171 
172         mFragment.addEntityHeader();
173 
174         verify(mHeaderController).setHasAppInfoLink(false);
175     }
176 
177     @Test
bindAppHeader_workApp_shouldSetWorkAppUid()178     public void bindAppHeader_workApp_shouldSetWorkAppUid()
179             throws PackageManager.NameNotFoundException {
180         final int fakeUserId = 100;
181 
182         mFragment = spy(new TestFragment());
183         final ArraySet<String> packages = new ArraySet<>();
184         packages.add("pkg");
185         final AppItem appItem = new AppItem(123456789);
186 
187         ReflectionHelpers.setField(mFragment, "mPackageManager", mPackageManager);
188         ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
189         ReflectionHelpers.setField(mFragment, "mPackages", packages);
190 
191         when(mPackageManager.getPackageUidAsUser(anyString(), anyInt()))
192                 .thenReturn(fakeUserId);
193 
194         when(mHeaderController.setHasAppInfoLink(anyBoolean())).thenReturn(mHeaderController);
195 
196         when(mFragment.getPreferenceManager())
197                 .thenReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS));
198         doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
199 
200         mFragment.addEntityHeader();
201 
202         verify(mHeaderController).setHasAppInfoLink(true);
203         verify(mHeaderController).setUid(fakeUserId);
204     }
205 
206     @Test
changePreference_backgroundData_shouldUpdateUI()207     public void changePreference_backgroundData_shouldUpdateUI() {
208         mFragment = spy(new TestFragment());
209         final AppItem appItem = new AppItem(123456789);
210         final RestrictedSwitchPreference pref = mock(RestrictedSwitchPreference.class);
211         final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class);
212         ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
213         ReflectionHelpers.setField(mFragment, "mRestrictBackground", pref);
214         ReflectionHelpers.setField(mFragment, "mDataSaverBackend", dataSaverBackend);
215 
216         doNothing().when(mFragment).updatePrefs();
217 
218         mFragment.onPreferenceChange(pref, true /* value */);
219 
220         verify(mFragment).updatePrefs();
221     }
222 
223     @Test
updatePrefs_restrictedByAdmin_shouldDisablePreference()224     public void updatePrefs_restrictedByAdmin_shouldDisablePreference() {
225         mFragment = spy(new TestFragment());
226         final int testUid = 123123;
227         final AppItem appItem = new AppItem(testUid);
228         final RestrictedSwitchPreference restrictBackgroundPref
229                 = mock(RestrictedSwitchPreference.class);
230         final RestrictedSwitchPreference unrestrictedDataPref
231                 = mock(RestrictedSwitchPreference.class);
232         final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class);
233         final NetworkPolicyManager networkPolicyManager = mock(NetworkPolicyManager.class);
234         ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
235         ReflectionHelpers.setField(mFragment, "mRestrictBackground", restrictBackgroundPref);
236         ReflectionHelpers.setField(mFragment, "mUnrestrictedData", unrestrictedDataPref);
237         ReflectionHelpers.setField(mFragment, "mDataSaverBackend", dataSaverBackend);
238         ReflectionHelpers.setField(mFragment.services, "mPolicyManager", networkPolicyManager);
239         ReflectionHelpers.setField(mFragment, "mContext", RuntimeEnvironment.application);
240         when(mFragment.getListView()).thenReturn(mock(RecyclerView.class));
241 
242         ShadowRestrictedLockUtilsInternal.setRestricted(true);
243         doReturn(NetworkPolicyManager.POLICY_NONE).when(networkPolicyManager)
244                 .getUidPolicy(testUid);
245 
246         mFragment.updatePrefs();
247 
248         verify(restrictBackgroundPref).setDisabledByAdmin(any(EnforcedAdmin.class));
249         verify(unrestrictedDataPref).setDisabledByAdmin(any(EnforcedAdmin.class));
250     }
251 
252     @Test
253     @Config(shadows = {ShadowDataUsageUtils.class, ShadowSubscriptionManager.class,
254             ShadowFragment.class})
onCreate_noNetworkTemplateAndInvalidDataSubscription_shouldUseWifiTemplate()255     public void onCreate_noNetworkTemplateAndInvalidDataSubscription_shouldUseWifiTemplate() {
256         ShadowDataUsageUtils.IS_MOBILE_DATA_SUPPORTED = true;
257         ShadowDataUsageUtils.IS_WIFI_SUPPORTED = true;
258         ShadowSubscriptionManager.setDefaultDataSubscriptionId(
259                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
260         mFragment = spy(new TestFragment());
261         doReturn(Robolectric.setupActivity(FragmentActivity.class)).when(mFragment).getActivity();
262         doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
263         final UidDetailProvider uidDetailProvider = mock(UidDetailProvider.class);
264         doReturn(uidDetailProvider).when(mFragment).getUidDetailProvider();
265         doReturn(new UidDetail()).when(uidDetailProvider).getUidDetail(anyInt(), anyBoolean());
266 
267         ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
268                 FakeFeatureFactory.setupForTest().dashboardFeatureProvider);
269         final Bundle args = new Bundle();
270         args.putInt(AppInfoBase.ARG_PACKAGE_UID, 123123);
271         mFragment.setArguments(args);
272 
273         mFragment.onCreate(Bundle.EMPTY);
274 
275         assertThat(mFragment.mTemplate.getMatchRule())
276                 .isEqualTo(NetworkTemplate.MATCH_WIFI);
277         assertTrue(mFragment.mTemplate.getSubscriberIds().isEmpty());
278         assertTrue(mFragment.mTemplate.getWifiNetworkKeys().isEmpty());
279     }
280 
281     private static class TestFragment extends AppDataUsage {
282         @Override
use(Class<T> clazz)283         protected <T extends AbstractPreferenceController> T use(Class<T> clazz) {
284             return mock(clazz);
285         }
286 
287         @Override
initCycle(List<Integer> uidList)288         void initCycle(List<Integer> uidList) {
289         }
290 
291         @Override
isSimHardwareVisible(Context context)292         public boolean isSimHardwareVisible(Context context) {
293             return true;
294         }
295     }
296 }
297