1 /* 2 * Copyright (C) 2019 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.car.settings.datausage; 18 19 import static com.android.car.settings.common.PreferenceController.AVAILABLE; 20 import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.when; 26 import static org.robolectric.shadow.api.Shadow.extract; 27 28 import android.content.Context; 29 import android.net.NetworkTemplate; 30 import android.telephony.SubscriptionInfo; 31 import android.telephony.SubscriptionManager; 32 import android.telephony.SubscriptionPlan; 33 import android.telephony.TelephonyManager; 34 import android.text.TextUtils; 35 import android.text.format.Formatter; 36 37 import androidx.lifecycle.Lifecycle; 38 39 import com.android.car.settings.CarSettingsRobolectricTestRunner; 40 import com.android.car.settings.R; 41 import com.android.car.settings.common.PreferenceControllerTestHelper; 42 import com.android.car.settings.testutils.ShadowDataUsageController; 43 import com.android.car.settings.testutils.ShadowSubscriptionManager; 44 import com.android.car.settings.testutils.ShadowTelephonyManager; 45 import com.android.settingslib.net.DataUsageController; 46 47 import com.google.android.collect.Lists; 48 49 import org.junit.After; 50 import org.junit.Before; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 import org.robolectric.RuntimeEnvironment; 56 import org.robolectric.annotation.Config; 57 import org.robolectric.shadow.api.Shadow; 58 59 import java.time.Period; 60 import java.time.ZonedDateTime; 61 import java.util.concurrent.TimeUnit; 62 63 @RunWith(CarSettingsRobolectricTestRunner.class) 64 @Config(shadows = {ShadowTelephonyManager.class, ShadowSubscriptionManager.class, 65 ShadowDataUsageController.class}) 66 public class DataUsageSummaryPreferenceControllerTest { 67 68 private static final CharSequence TEST_CARRIER_NAME = "TEST_CARRIER_NAME"; 69 70 private Context mContext; 71 private DataUsageSummaryPreference mDataUsageSummaryPreference; 72 private DataUsageSummaryPreferenceController mController; 73 private PreferenceControllerTestHelper<DataUsageSummaryPreferenceController> mControllerHelper; 74 private NetworkTemplate mNetworkTemplate; 75 @Mock 76 private DataUsageController mDataUsageController; 77 78 @Before setUp()79 public void setUp() { 80 MockitoAnnotations.initMocks(this); 81 82 SubscriptionInfo info = mock(SubscriptionInfo.class); 83 when(info.getSubscriptionId()).thenReturn(1); 84 ShadowSubscriptionManager.setDefaultDataSubscriptionInfo(info); 85 ShadowDataUsageController.setInstance(mDataUsageController); 86 87 mContext = RuntimeEnvironment.application; 88 mDataUsageSummaryPreference = new DataUsageSummaryPreference(mContext); 89 mControllerHelper = new PreferenceControllerTestHelper<>(mContext, 90 DataUsageSummaryPreferenceController.class, mDataUsageSummaryPreference); 91 mController = mControllerHelper.getController(); 92 93 mNetworkTemplate = DataUsageUtils.getMobileNetworkTemplate( 94 mContext.getSystemService(TelephonyManager.class), 95 DataUsageUtils.getDefaultSubscriptionId( 96 mContext.getSystemService(SubscriptionManager.class))); 97 } 98 99 @After tearDown()100 public void tearDown() { 101 ShadowTelephonyManager.reset(); 102 ShadowSubscriptionManager.reset(); 103 ShadowDataUsageController.reset(); 104 } 105 106 @Test getAvailabilityStatus_hasSim_isAvailable()107 public void getAvailabilityStatus_hasSim_isAvailable() { 108 getShadowTelephonyManager().setSimState(TelephonyManager.SIM_STATE_LOADED); 109 assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); 110 } 111 112 @Test getAvailabilityStatus_noSim_isConditionallyUnavailable()113 public void getAvailabilityStatus_noSim_isConditionallyUnavailable() { 114 getShadowTelephonyManager().setSimState(TelephonyManager.SIM_STATE_UNKNOWN); 115 assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); 116 } 117 118 @Test refreshUi_hasUsage_titleSet()119 public void refreshUi_hasUsage_titleSet() { 120 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 121 info.usageLevel = 10000; 122 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 123 124 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 125 mController.refreshUi(); 126 127 String usedValueString = Formatter.formatBytes(mContext.getResources(), info.usageLevel, 128 Formatter.FLAG_CALCULATE_ROUNDED | Formatter.FLAG_IEC_UNITS).value; 129 assertThat(mDataUsageSummaryPreference.getTitle().toString()).contains(usedValueString); 130 } 131 132 @Test refreshUi_noLimits_doesntSetDataLimitText()133 public void refreshUi_noLimits_doesntSetDataLimitText() { 134 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 135 info.usageLevel = 10000; 136 info.limitLevel = -1; 137 info.warningLevel = -1; 138 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 139 140 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 141 mController.refreshUi(); 142 143 assertThat(mDataUsageSummaryPreference.getDataLimitText()).isNull(); 144 } 145 146 @Test refreshUi_hasLimit_setsDataLimitText()147 public void refreshUi_hasLimit_setsDataLimitText() { 148 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 149 info.usageLevel = 10000; 150 info.limitLevel = 100000; 151 info.warningLevel = -1; 152 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 153 154 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 155 mController.refreshUi(); 156 157 assertThat(mDataUsageSummaryPreference.getDataLimitText().toString()).isEqualTo( 158 TextUtils.expandTemplate(mContext.getText(R.string.cell_data_limit), 159 DataUsageUtils.bytesToIecUnits(mContext, info.limitLevel)).toString()); 160 } 161 162 @Test refreshUi_hasWarning_setsDataLimitText()163 public void refreshUi_hasWarning_setsDataLimitText() { 164 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 165 info.usageLevel = 10000; 166 info.limitLevel = -1; 167 info.warningLevel = 50000; 168 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 169 170 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 171 mController.refreshUi(); 172 173 assertThat(mDataUsageSummaryPreference.getDataLimitText().toString()).isEqualTo( 174 TextUtils.expandTemplate(mContext.getText(R.string.cell_data_warning), 175 DataUsageUtils.bytesToIecUnits(mContext, info.warningLevel)).toString()); 176 } 177 178 @Test refreshUi_hasWarningAndLimit_setsDataLimitText()179 public void refreshUi_hasWarningAndLimit_setsDataLimitText() { 180 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 181 info.usageLevel = 10000; 182 info.limitLevel = 100000; 183 info.warningLevel = 50000; 184 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 185 186 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 187 mController.refreshUi(); 188 189 assertThat(mDataUsageSummaryPreference.getDataLimitText().toString()).isEqualTo( 190 TextUtils.expandTemplate(mContext.getText(R.string.cell_data_warning_and_limit), 191 DataUsageUtils.bytesToIecUnits(mContext, info.warningLevel), 192 DataUsageUtils.bytesToIecUnits(mContext, info.limitLevel)).toString()); 193 } 194 195 @Test refreshUi_endTimeIsGreaterThanOneDay_setsBillingCycleText()196 public void refreshUi_endTimeIsGreaterThanOneDay_setsBillingCycleText() { 197 int numDays = 20; 198 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 199 // Add an extra hour to account for the difference in time when the test calls 200 // System.currentTimeMillis() vs when the code calls it. 201 info.cycleEnd = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(numDays) 202 + TimeUnit.HOURS.toMillis(1); 203 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 204 205 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 206 mController.refreshUi(); 207 208 assertThat(mDataUsageSummaryPreference.getRemainingBillingCycleText().toString()) 209 .isEqualTo( 210 mContext.getResources().getQuantityString(R.plurals.billing_cycle_days_left, 211 numDays, numDays)); 212 } 213 214 @Test refreshUi_endTimeIsLessThanOneDay_setsBillingCycleText()215 public void refreshUi_endTimeIsLessThanOneDay_setsBillingCycleText() { 216 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 217 info.cycleEnd = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(22); 218 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 219 220 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 221 mController.refreshUi(); 222 223 assertThat(mDataUsageSummaryPreference.getRemainingBillingCycleText().toString()) 224 .isEqualTo( 225 mContext.getString(R.string.billing_cycle_less_than_one_day_left)); 226 } 227 228 @Test refreshUi_endTimeIsNow_setsBillingCycleText()229 public void refreshUi_endTimeIsNow_setsBillingCycleText() { 230 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 231 info.cycleEnd = System.currentTimeMillis(); 232 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 233 234 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 235 mController.refreshUi(); 236 237 assertThat(mDataUsageSummaryPreference.getRemainingBillingCycleText().toString()) 238 .isEqualTo( 239 mContext.getString(R.string.billing_cycle_none_left)); 240 } 241 242 @Test refreshUi_hasCarrierName_hasRecentUpdate_setsCarrierInfoText()243 public void refreshUi_hasCarrierName_hasRecentUpdate_setsCarrierInfoText() { 244 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 245 info.usageLevel = 10000; 246 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 247 248 setCarrierName(TEST_CARRIER_NAME); 249 setSubscriptionPlan(/* usageBytes= */ 1000L, System.currentTimeMillis()); 250 251 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 252 mController.refreshUi(); 253 254 assertThat(mDataUsageSummaryPreference.getCarrierInfoText()).isEqualTo( 255 TextUtils.expandTemplate(mContext.getText(R.string.carrier_and_update_now_text), 256 TEST_CARRIER_NAME)); 257 } 258 259 @Test refreshUi_hasCarrierName_hasOldUpdate_setsCarrierInfoText()260 public void refreshUi_hasCarrierName_hasOldUpdate_setsCarrierInfoText() { 261 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 262 info.usageLevel = 10000; 263 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 264 265 int numDays = 15; 266 setCarrierName(TEST_CARRIER_NAME); 267 setSubscriptionPlan(/* usageBytes= */ 1000L, 268 System.currentTimeMillis() - TimeUnit.DAYS.toMillis(numDays)); 269 270 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 271 mController.refreshUi(); 272 273 assertThat(mDataUsageSummaryPreference.getCarrierInfoText()).isEqualTo( 274 TextUtils.expandTemplate(mContext.getText(R.string.carrier_and_update_text), 275 TEST_CARRIER_NAME, numDays + " days")); 276 } 277 278 @Test refreshUi_noCarrierName_hasRecentUpdate_setsCarrierInfoText()279 public void refreshUi_noCarrierName_hasRecentUpdate_setsCarrierInfoText() { 280 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 281 info.usageLevel = 10000; 282 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 283 284 setSubscriptionPlan(/* usageBytes= */ 1000L, System.currentTimeMillis()); 285 286 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 287 mController.refreshUi(); 288 289 assertThat(mDataUsageSummaryPreference.getCarrierInfoText().toString()).isEqualTo( 290 mContext.getString(R.string.no_carrier_update_now_text)); 291 } 292 293 @Test refreshUi_noCarrierName_hasOldUpdate_setsCarrierInfoText()294 public void refreshUi_noCarrierName_hasOldUpdate_setsCarrierInfoText() { 295 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 296 info.usageLevel = 10000; 297 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 298 299 int numDays = 15; 300 setSubscriptionPlan(/* usageBytes= */ 1000L, 301 System.currentTimeMillis() - TimeUnit.DAYS.toMillis(numDays)); 302 303 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 304 mController.refreshUi(); 305 306 assertThat(mDataUsageSummaryPreference.getCarrierInfoText()).isEqualTo( 307 TextUtils.expandTemplate(mContext.getText(R.string.no_carrier_update_text), 308 null, numDays + " days")); 309 } 310 311 @Test refreshUi_hasUpdateTimeOlderThanWarning_setsCarrierInfoStyle()312 public void refreshUi_hasUpdateTimeOlderThanWarning_setsCarrierInfoStyle() { 313 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 314 info.usageLevel = 10000; 315 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 316 317 318 // Subtract an extra hour to account fo the difference in calls to 319 // System.currentTimeMillis(). 320 setSubscriptionPlan(/* usageBytes= */ 1000L, 321 System.currentTimeMillis() - DataUsageSummaryPreferenceController.WARNING_AGE 322 - TimeUnit.HOURS.toMillis(1)); 323 324 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 325 mController.refreshUi(); 326 327 assertThat(mDataUsageSummaryPreference.getCarrierInfoTextStyle()).isEqualTo( 328 R.style.DataUsageSummaryCarrierInfoWarningTextAppearance); 329 } 330 331 @Test refreshUi_hasUpdateTimeYoungerThanWarning_setsCarrierInfoStyle()332 public void refreshUi_hasUpdateTimeYoungerThanWarning_setsCarrierInfoStyle() { 333 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 334 info.usageLevel = 10000; 335 when(mDataUsageController.getDataUsageInfo(mNetworkTemplate)).thenReturn(info); 336 337 // Subtract an extra hour to account fo the difference in calls to 338 // System.currentTimeMillis(). 339 setSubscriptionPlan(/* usageBytes= */ 1000L, 340 System.currentTimeMillis() - DataUsageSummaryPreferenceController.WARNING_AGE 341 + TimeUnit.HOURS.toMillis(1)); 342 343 mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE); 344 mController.refreshUi(); 345 346 assertThat(mDataUsageSummaryPreference.getCarrierInfoTextStyle()).isEqualTo( 347 R.style.DataUsageSummaryCarrierInfoTextAppearance); 348 } 349 getShadowTelephonyManager()350 private ShadowTelephonyManager getShadowTelephonyManager() { 351 return (ShadowTelephonyManager) extract( 352 mContext.getSystemService(TelephonyManager.class)); 353 } 354 getShadowSubscriptionManager()355 private ShadowSubscriptionManager getShadowSubscriptionManager() { 356 return Shadow.extract(mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)); 357 } 358 setCarrierName(CharSequence name)359 private void setCarrierName(CharSequence name) { 360 SubscriptionInfo subInfo = new SubscriptionInfo(/* id= */ 0, /* iccId= */ "", 361 /* simSlotIndex= */ 0, /* displayName= */ "", name, 362 /* nameSource= */ 0, /* iconTint= */ 0, /* number= */ "", 363 /* roaming= */ 0, /* icon= */ null, /* mcc= */ "", /* mnc= */ "", 364 /* countryIso= */ "", /* isEmbedded= */ false, 365 /* accessRules= */ null, /* cardString= */ ""); 366 ShadowSubscriptionManager.setDefaultDataSubscriptionInfo(subInfo); 367 } 368 setSubscriptionPlan(long usageBytes, long snapshotMillis)369 private void setSubscriptionPlan(long usageBytes, long snapshotMillis) { 370 ZonedDateTime start = ZonedDateTime.now(); 371 ZonedDateTime end = ZonedDateTime.now().plusDays(30); 372 SubscriptionPlan plan = new SubscriptionPlan.Builder(start, end, Period.ofMonths(1)) 373 .setDataLimit(/* dataLimitBytes= */ 5000000000L, 374 SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) 375 .setDataUsage(usageBytes, snapshotMillis) 376 .build(); 377 getShadowSubscriptionManager().setSubscriptionPlans(Lists.newArrayList(plan)); 378 } 379 } 380