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