1 /* 2 * Copyright (C) 2021 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.AVAILABLE_FOR_VIEWING; 21 import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE; 22 23 import static com.google.common.truth.Truth.assertThat; 24 25 import static org.mockito.ArgumentMatchers.any; 26 import static org.mockito.ArgumentMatchers.anyInt; 27 import static org.mockito.Mockito.mock; 28 import static org.mockito.Mockito.spy; 29 import static org.mockito.Mockito.when; 30 31 import android.car.drivingstate.CarUxRestrictions; 32 import android.content.Context; 33 import android.telephony.SubscriptionInfo; 34 import android.telephony.SubscriptionManager; 35 import android.telephony.SubscriptionPlan; 36 import android.telephony.TelephonyManager; 37 import android.text.TextUtils; 38 import android.text.format.Formatter; 39 40 import androidx.lifecycle.LifecycleOwner; 41 import androidx.test.core.app.ApplicationProvider; 42 import androidx.test.ext.junit.runners.AndroidJUnit4; 43 44 import com.android.car.settings.R; 45 import com.android.car.settings.common.FragmentController; 46 import com.android.car.settings.common.PreferenceControllerTestUtil; 47 import com.android.car.settings.testutils.TestLifecycleOwner; 48 import com.android.dx.mockito.inline.extended.ExtendedMockito; 49 import com.android.settingslib.net.DataUsageController; 50 51 import com.google.android.collect.Lists; 52 53 import org.junit.After; 54 import org.junit.Before; 55 import org.junit.Test; 56 import org.junit.runner.RunWith; 57 import org.mockito.Mock; 58 import org.mockito.MockitoAnnotations; 59 import org.mockito.MockitoSession; 60 61 import java.time.Period; 62 import java.time.ZonedDateTime; 63 import java.util.concurrent.TimeUnit; 64 65 @RunWith(AndroidJUnit4.class) 66 public class DataUsageSummaryPreferenceControllerTest { 67 68 private static final CharSequence TEST_CARRIER_NAME = "TEST_CARRIER_NAME"; 69 private static final int SUB_ID = 1; 70 71 private Context mContext = spy(ApplicationProvider.getApplicationContext()); 72 private LifecycleOwner mLifecycleOwner; 73 private CarUxRestrictions mCarUxRestrictions; 74 private DataUsageSummaryPreference mDataUsageSummaryPreference; 75 private DataUsageSummaryPreferenceController mPreferenceController; 76 private MockitoSession mSession; 77 78 @Mock 79 private FragmentController mMockFragmentController; 80 @Mock 81 private DataUsageController mMockDataUsageController; 82 @Mock 83 private SubscriptionManager mMockSubscriptionManager; 84 @Mock 85 private TelephonyManager mMockTelephonyManager; 86 87 @Before setUp()88 public void setUp() { 89 MockitoAnnotations.initMocks(this); 90 mLifecycleOwner = new TestLifecycleOwner(); 91 92 mSession = ExtendedMockito.mockitoSession() 93 .spyStatic(TelephonyManager.class) 94 .startMocking(); 95 96 ExtendedMockito.when(TelephonyManager.from(mContext)).thenReturn(mMockTelephonyManager); 97 when(mMockTelephonyManager.createForSubscriptionId(SUB_ID)) 98 .thenReturn(mMockTelephonyManager); 99 100 mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true, 101 CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build(); 102 mPreferenceController = new DataUsageSummaryPreferenceController(mContext, 103 /* preferenceKey= */ "key", mMockFragmentController, 104 mCarUxRestrictions, mMockSubscriptionManager, mMockDataUsageController); 105 mDataUsageSummaryPreference = new DataUsageSummaryPreference(mContext); 106 mPreferenceController.setFields(SUB_ID); 107 PreferenceControllerTestUtil.assignPreference(mPreferenceController, 108 mDataUsageSummaryPreference); 109 110 SubscriptionInfo info = mock(SubscriptionInfo.class); 111 when(mMockSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info); 112 113 when(mMockTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_LOADED); 114 } 115 116 @After tearDown()117 public void tearDown() { 118 if (mSession != null) { 119 mSession.finishMocking(); 120 } 121 } 122 123 @Test getAvailabilityStatus_hasSim_isAvailable()124 public void getAvailabilityStatus_hasSim_isAvailable() { 125 assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE); 126 } 127 128 @Test getAvailabilityStatus_hasSim_isAvailable_zoneWrite()129 public void getAvailabilityStatus_hasSim_isAvailable_zoneWrite() { 130 mPreferenceController.setAvailabilityStatusForZone("write"); 131 PreferenceControllerTestUtil.assertAvailability( 132 mPreferenceController.getAvailabilityStatus(), AVAILABLE); 133 } 134 135 @Test getAvailabilityStatus_hasSim_isAvailable_zoneRead()136 public void getAvailabilityStatus_hasSim_isAvailable_zoneRead() { 137 mPreferenceController.setAvailabilityStatusForZone("read"); 138 PreferenceControllerTestUtil.assertAvailability( 139 mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING); 140 } 141 142 @Test getAvailabilityStatus_hasSim_isAvailable_zoneHidden()143 public void getAvailabilityStatus_hasSim_isAvailable_zoneHidden() { 144 mPreferenceController.setAvailabilityStatusForZone("hidden"); 145 PreferenceControllerTestUtil.assertAvailability( 146 mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE); 147 } 148 149 @Test getAvailabilityStatus_noSim_isConditionallyUnavailable()150 public void getAvailabilityStatus_noSim_isConditionallyUnavailable() { 151 when(mMockTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_UNKNOWN); 152 assertThat(mPreferenceController.getAvailabilityStatus()) 153 .isEqualTo(CONDITIONALLY_UNAVAILABLE); 154 } 155 156 @Test getAvailabilityStatus_noSim_isConditionallyUnavailable_zoneWrite()157 public void getAvailabilityStatus_noSim_isConditionallyUnavailable_zoneWrite() { 158 when(mMockTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_UNKNOWN); 159 mPreferenceController.setAvailabilityStatusForZone("write"); 160 PreferenceControllerTestUtil.assertAvailability( 161 mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE); 162 } 163 164 @Test getAvailabilityStatus_noSim_isConditionallyUnavailable_zoneRead()165 public void getAvailabilityStatus_noSim_isConditionallyUnavailable_zoneRead() { 166 when(mMockTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_UNKNOWN); 167 mPreferenceController.setAvailabilityStatusForZone("read"); 168 PreferenceControllerTestUtil.assertAvailability( 169 mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE); 170 } 171 172 @Test getAvailabilityStatus_noSim_isConditionallyUnavailable_zoneHidden()173 public void getAvailabilityStatus_noSim_isConditionallyUnavailable_zoneHidden() { 174 when(mMockTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_UNKNOWN); 175 mPreferenceController.setAvailabilityStatusForZone("hidden"); 176 PreferenceControllerTestUtil.assertAvailability( 177 mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE); 178 } 179 180 @Test refreshUi_hasUsage_titleSet()181 public void refreshUi_hasUsage_titleSet() { 182 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 183 info.usageLevel = 10000; 184 when(mMockDataUsageController.getDataUsageInfo(any())).thenReturn(info); 185 186 mPreferenceController.onCreate(mLifecycleOwner); 187 mPreferenceController.refreshUi(); 188 189 String usedValueString = Formatter.formatBytes(mContext.getResources(), info.usageLevel, 190 Formatter.FLAG_CALCULATE_ROUNDED | Formatter.FLAG_IEC_UNITS).value; 191 assertThat(mDataUsageSummaryPreference.getTitle().toString()).contains(usedValueString); 192 } 193 194 @Test refreshUi_hasCarrierName_hasRecentUpdate_setsCarrierInfoText()195 public void refreshUi_hasCarrierName_hasRecentUpdate_setsCarrierInfoText() { 196 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 197 info.usageLevel = 10000; 198 when(mMockDataUsageController.getDataUsageInfo(any())).thenReturn(info); 199 200 setCarrierName(TEST_CARRIER_NAME); 201 setSubscriptionPlan(/* usageBytes= */ 1000L, System.currentTimeMillis()); 202 203 mPreferenceController.onCreate(mLifecycleOwner); 204 mPreferenceController.refreshUi(); 205 206 assertThat(mDataUsageSummaryPreference.getCarrierInfoText()).isEqualTo( 207 TextUtils.expandTemplate(mContext.getText(R.string.carrier_and_update_now_text), 208 TEST_CARRIER_NAME)); 209 } 210 211 @Test refreshUi_hasCarrierName_hasOldUpdate_setsCarrierInfoText()212 public void refreshUi_hasCarrierName_hasOldUpdate_setsCarrierInfoText() { 213 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 214 info.usageLevel = 10000; 215 when(mMockDataUsageController.getDataUsageInfo(any())).thenReturn(info); 216 217 int numDays = 15; 218 setCarrierName(TEST_CARRIER_NAME); 219 setSubscriptionPlan(/* usageBytes= */ 1000L, 220 System.currentTimeMillis() - TimeUnit.DAYS.toMillis(numDays)); 221 222 mPreferenceController.onCreate(mLifecycleOwner); 223 mPreferenceController.refreshUi(); 224 225 assertThat(mDataUsageSummaryPreference.getCarrierInfoText()).isEqualTo( 226 TextUtils.expandTemplate(mContext.getText(R.string.carrier_and_update_text), 227 TEST_CARRIER_NAME, numDays + " days")); 228 } 229 230 @Test refreshUi_noCarrierName_hasRecentUpdate_setsCarrierInfoText()231 public void refreshUi_noCarrierName_hasRecentUpdate_setsCarrierInfoText() { 232 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 233 info.usageLevel = 10000; 234 when(mMockDataUsageController.getDataUsageInfo(any())).thenReturn(info); 235 236 setSubscriptionPlan(/* usageBytes= */ 1000L, System.currentTimeMillis()); 237 238 mPreferenceController.onCreate(mLifecycleOwner); 239 mPreferenceController.refreshUi(); 240 241 assertThat(mDataUsageSummaryPreference.getCarrierInfoText().toString()).isEqualTo( 242 mContext.getString(R.string.no_carrier_update_now_text)); 243 } 244 245 @Test refreshUi_noCarrierName_hasOldUpdate_setsCarrierInfoText()246 public void refreshUi_noCarrierName_hasOldUpdate_setsCarrierInfoText() { 247 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 248 info.usageLevel = 10000; 249 when(mMockDataUsageController.getDataUsageInfo(any())).thenReturn(info); 250 251 int numDays = 15; 252 setSubscriptionPlan(/* usageBytes= */ 1000L, 253 System.currentTimeMillis() - TimeUnit.DAYS.toMillis(numDays)); 254 255 mPreferenceController.onCreate(mLifecycleOwner); 256 mPreferenceController.refreshUi(); 257 258 assertThat(mDataUsageSummaryPreference.getCarrierInfoText()).isEqualTo( 259 TextUtils.expandTemplate(mContext.getText(R.string.no_carrier_update_text), 260 null, numDays + " days")); 261 } 262 263 @Test refreshUi_hasUpdateTimeOlderThanWarning_setsCarrierInfoStyle()264 public void refreshUi_hasUpdateTimeOlderThanWarning_setsCarrierInfoStyle() { 265 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 266 info.usageLevel = 10000; 267 when(mMockDataUsageController.getDataUsageInfo(any())).thenReturn(info); 268 269 270 // Subtract an extra hour to account fo the difference in calls to 271 // System.currentTimeMillis(). 272 setSubscriptionPlan(/* usageBytes= */ 1000L, 273 System.currentTimeMillis() - DataUsageSummaryPreferenceController.WARNING_AGE 274 - TimeUnit.HOURS.toMillis(1)); 275 276 mPreferenceController.onCreate(mLifecycleOwner); 277 mPreferenceController.refreshUi(); 278 279 assertThat(mDataUsageSummaryPreference.getCarrierInfoTextStyle()).isEqualTo( 280 R.style.DataUsageSummaryCarrierInfoWarningTextAppearance); 281 } 282 283 @Test refreshUi_hasUpdateTimeYoungerThanWarning_setsCarrierInfoStyle()284 public void refreshUi_hasUpdateTimeYoungerThanWarning_setsCarrierInfoStyle() { 285 DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo(); 286 info.usageLevel = 10000; 287 when(mMockDataUsageController.getDataUsageInfo(any())).thenReturn(info); 288 289 // Subtract an extra hour to account fo the difference in calls to 290 // System.currentTimeMillis(). 291 setSubscriptionPlan(/* usageBytes= */ 1000L, 292 System.currentTimeMillis() - DataUsageSummaryPreferenceController.WARNING_AGE 293 + TimeUnit.HOURS.toMillis(1)); 294 295 mPreferenceController.onCreate(mLifecycleOwner); 296 mPreferenceController.refreshUi(); 297 298 assertThat(mDataUsageSummaryPreference.getCarrierInfoTextStyle()).isEqualTo( 299 R.style.DataUsageSummaryCarrierInfoTextAppearance); 300 } 301 setCarrierName(CharSequence name)302 private void setCarrierName(CharSequence name) { 303 SubscriptionInfo subInfo = new SubscriptionInfo(/* id= */ 0, /* iccId= */ "", 304 /* simSlotIndex= */ 0, /* displayName= */ "", name, 305 /* nameSource= */ 0, /* iconTint= */ 0, /* number= */ "", 306 /* roaming= */ 0, /* icon= */ null, /* mcc= */ "", /* mnc= */ "", 307 /* countryIso= */ "", /* isEmbedded= */ false, 308 /* accessRules= */ null, /* cardString= */ ""); 309 when(mMockSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(subInfo); 310 } 311 setSubscriptionPlan(long usageBytes, long snapshotMillis)312 private void setSubscriptionPlan(long usageBytes, long snapshotMillis) { 313 ZonedDateTime start = ZonedDateTime.now(); 314 ZonedDateTime end = ZonedDateTime.now().plusDays(30); 315 SubscriptionPlan plan = new SubscriptionPlan.Builder(start, end, Period.ofMonths(1)) 316 .setDataLimit(/* dataLimitBytes= */ 5000000000L, 317 SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) 318 .setDataUsage(usageBytes, snapshotMillis) 319 .build(); 320 when(mMockSubscriptionManager.getSubscriptionPlans(anyInt())) 321 .thenReturn(Lists.newArrayList(plan)); 322 } 323 } 324