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