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.system;
18 
19 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
20 import static android.telephony.SubscriptionManager.MIN_SUBSCRIPTION_ID_VALUE;
21 
22 import static com.android.car.settings.common.PreferenceController.AVAILABLE;
23 import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING;
24 import static com.android.car.settings.common.PreferenceController.CONDITIONALLY_UNAVAILABLE;
25 import static com.android.car.settings.common.PreferenceController.UNSUPPORTED_ON_DEVICE;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static org.mockito.ArgumentMatchers.anyInt;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.when;
33 import static org.mockito.Mockito.withSettings;
34 
35 import android.car.drivingstate.CarUxRestrictions;
36 import android.content.Context;
37 import android.content.pm.PackageManager;
38 import android.telephony.SubscriptionInfo;
39 import android.telephony.SubscriptionManager;
40 
41 import androidx.lifecycle.LifecycleOwner;
42 import androidx.preference.ListPreference;
43 import androidx.test.core.app.ApplicationProvider;
44 import androidx.test.ext.junit.runners.AndroidJUnit4;
45 
46 import com.android.car.settings.common.FragmentController;
47 import com.android.car.settings.common.PreferenceControllerTestUtil;
48 import com.android.car.settings.testutils.TestLifecycleOwner;
49 import com.android.dx.mockito.inline.extended.ExtendedMockito;
50 
51 import org.junit.After;
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.Mock;
56 import org.mockito.MockitoAnnotations;
57 import org.mockito.MockitoSession;
58 
59 import java.util.Arrays;
60 import java.util.Collections;
61 import java.util.List;
62 
63 /** Unit test for {@link ResetNetworkSubscriptionPreferenceController}. */
64 @RunWith(AndroidJUnit4.class)
65 public class ResetNetworkSubscriptionPreferenceControllerTest {
66     private static final int SUBID_1 = MIN_SUBSCRIPTION_ID_VALUE;
67     private static final int SUBID_2 = SUBID_1 + 1;
68     private static final int SUBID_3 = SUBID_2 + 1;
69     private static final int SUBID_4 = SUBID_3 + 1;
70 
71     private Context mContext = spy(ApplicationProvider.getApplicationContext());
72     private LifecycleOwner mLifecycleOwner;
73     private ListPreference mPreference;
74     private ResetNetworkSubscriptionPreferenceController mPreferenceController;
75     private CarUxRestrictions mCarUxRestrictions;
76     private MockitoSession mSession;
77 
78     @Mock
79     private FragmentController mFragmentController;
80     @Mock
81     private PackageManager mMockPm;
82     @Mock
83     private SubscriptionManager mMockSubscriptionManager;
84 
85     @Before
setUp()86     public void setUp() {
87         MockitoAnnotations.initMocks(this);
88         mLifecycleOwner = new TestLifecycleOwner();
89 
90         mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
91                 CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
92 
93         when(mContext.getPackageManager()).thenReturn(mMockPm);
94         // Default to AVAILABLE status. Tests for this behavior will do their own setup.
95         when(mMockPm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
96         when(mContext.getSystemService(SubscriptionManager.class))
97                 .thenReturn(mMockSubscriptionManager);
98         when(mMockSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(null);
99         mSession = ExtendedMockito.mockitoSession().mockStatic(
100                 SubscriptionManager.class, withSettings().lenient()).startMocking();
101         // Default to having no defaults. Tests for this behavior will do their own setup.
102         when(SubscriptionManager.isUsableSubIdValue(anyInt())).thenCallRealMethod();
103         when(SubscriptionManager.getDefaultSubscriptionId()).thenReturn(INVALID_SUBSCRIPTION_ID);
104         when(SubscriptionManager.getDefaultSmsSubscriptionId()).thenReturn(INVALID_SUBSCRIPTION_ID);
105         when(SubscriptionManager.getDefaultVoiceSubscriptionId()).thenReturn(
106                 INVALID_SUBSCRIPTION_ID);
107         when(SubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(
108                 INVALID_SUBSCRIPTION_ID);
109 
110         mPreference = new ListPreference(mContext);
111         mPreferenceController = new ResetNetworkSubscriptionPreferenceController(mContext,
112                 "key", mFragmentController, mCarUxRestrictions);
113         PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
114         mPreferenceController.onCreate(mLifecycleOwner);
115     }
116 
117     @After
tearDown()118     public void tearDown() {
119         if (mSession != null) {
120             mSession.finishMocking();
121         }
122     }
123 
124     @Test
getAvailabilityStatus_telephonyAvailable_available()125     public void getAvailabilityStatus_telephonyAvailable_available() {
126         assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
127     }
128 
129     @Test
getAvailabilityStatus_telephonyAvailable_available_zoneWrite()130     public void getAvailabilityStatus_telephonyAvailable_available_zoneWrite() {
131         mPreferenceController.setAvailabilityStatusForZone("write");
132         PreferenceControllerTestUtil.assertAvailability(
133                 mPreferenceController.getAvailabilityStatus(), AVAILABLE);
134     }
135 
136     @Test
getAvailabilityStatus_telephonyAvailable_available_zoneRead()137     public void getAvailabilityStatus_telephonyAvailable_available_zoneRead() {
138         mPreferenceController.setAvailabilityStatusForZone("read");
139         PreferenceControllerTestUtil.assertAvailability(
140                 mPreferenceController.getAvailabilityStatus(), AVAILABLE_FOR_VIEWING);
141     }
142 
143     @Test
getAvailabilityStatus_telephonyAvailable_available_zoneHidden()144     public void getAvailabilityStatus_telephonyAvailable_available_zoneHidden() {
145         mPreferenceController.setAvailabilityStatusForZone("hidden");
146         PreferenceControllerTestUtil.assertAvailability(
147                 mPreferenceController.getAvailabilityStatus(), CONDITIONALLY_UNAVAILABLE);
148     }
149 
150     @Test
getAvailabilityStatus_telephonyNotAvailable_unsupportedOnDevice()151     public void getAvailabilityStatus_telephonyNotAvailable_unsupportedOnDevice() {
152         when(mMockPm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
153 
154         assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
155     }
156 
157     @Test
getAvailabilityStatus_telephonyNotAvailable_unsupportedOnDevice_zoneWrite()158     public void getAvailabilityStatus_telephonyNotAvailable_unsupportedOnDevice_zoneWrite() {
159         when(mMockPm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
160         mPreferenceController.setAvailabilityStatusForZone("write");
161 
162         PreferenceControllerTestUtil.assertAvailability(
163                 mPreferenceController.getAvailabilityStatus(), UNSUPPORTED_ON_DEVICE);
164     }
165 
166     @Test
getAvailabilityStatus_telephonyNotAvailable_unsupportedOnDevice_zoneRead()167     public void getAvailabilityStatus_telephonyNotAvailable_unsupportedOnDevice_zoneRead() {
168         when(mMockPm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
169         mPreferenceController.setAvailabilityStatusForZone("read");
170 
171         PreferenceControllerTestUtil.assertAvailability(
172                 mPreferenceController.getAvailabilityStatus(), UNSUPPORTED_ON_DEVICE);
173     }
174 
175     @Test
getAvailabilityStatus_telephonyNotAvailable_unsupportedOnDevice_zoneHidden()176     public void getAvailabilityStatus_telephonyNotAvailable_unsupportedOnDevice_zoneHidden() {
177         when(mMockPm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
178         mPreferenceController.setAvailabilityStatusForZone("hidden");
179 
180         PreferenceControllerTestUtil.assertAvailability(
181                 mPreferenceController.getAvailabilityStatus(), UNSUPPORTED_ON_DEVICE);
182     }
183 
184     @Test
refreshUi_nullSubscriptions_hidesPreference()185     public void refreshUi_nullSubscriptions_hidesPreference() {
186         mPreferenceController.refreshUi();
187 
188         assertThat(mPreference.isVisible()).isFalse();
189     }
190 
191     @Test
refreshUi_nullSubscriptions_setsValue()192     public void refreshUi_nullSubscriptions_setsValue() {
193         mPreferenceController.refreshUi();
194 
195         assertThat(mPreference.getValue()).isEqualTo(
196                 String.valueOf(INVALID_SUBSCRIPTION_ID));
197     }
198 
199     @Test
refreshUi_noSubscriptions_hidesPreference()200     public void refreshUi_noSubscriptions_hidesPreference() {
201         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
202                 .thenReturn(Collections.emptyList());
203 
204         mPreferenceController.refreshUi();
205 
206         assertThat(mPreference.isVisible()).isFalse();
207     }
208 
209     @Test
refreshUi_noSubscriptions_setsValue()210     public void refreshUi_noSubscriptions_setsValue() {
211         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
212                 .thenReturn(Collections.emptyList());
213 
214         mPreferenceController.refreshUi();
215 
216         assertThat(mPreference.getValue()).isEqualTo(
217                 String.valueOf(INVALID_SUBSCRIPTION_ID));
218     }
219 
220     @Test
refreshUi_oneSubscription_hidesPreference()221     public void refreshUi_oneSubscription_hidesPreference() {
222         List<SubscriptionInfo> subscriptionInfoList = Collections.singletonList(
223                 createSubInfo(SUBID_1, "sub1"));
224         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
225                 .thenReturn(subscriptionInfoList);
226 
227         mPreferenceController.refreshUi();
228 
229         assertThat(mPreference.isVisible()).isFalse();
230     }
231 
232     @Test
refreshUi_oneSubscription_setsValue()233     public void refreshUi_oneSubscription_setsValue() {
234         List<SubscriptionInfo> subscriptionInfoList = Collections.singletonList(
235                 createSubInfo(SUBID_1, "sub1"));
236         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
237                 .thenReturn(subscriptionInfoList);
238 
239         mPreferenceController.refreshUi();
240 
241         assertThat(mPreference.getValue()).isEqualTo(String.valueOf(SUBID_1));
242     }
243 
244     @Test
refreshUi_multipleSubscriptions_showsPreference()245     public void refreshUi_multipleSubscriptions_showsPreference() {
246         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(createSubInfo(SUBID_1, "sub1"),
247                 createSubInfo(SUBID_2, "sub2"));
248         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
249                 .thenReturn(subscriptionInfoList);
250 
251         mPreferenceController.refreshUi();
252 
253         assertThat(mPreference.isVisible()).isTrue();
254     }
255 
256     @Test
refreshUi_multipleSubscriptions_populatesEntries()257     public void refreshUi_multipleSubscriptions_populatesEntries() {
258         String displayName1 = "sub1";
259         String displayName2 = "sub2";
260         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(
261                 createSubInfo(SUBID_1, displayName1), createSubInfo(SUBID_2, displayName2));
262         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
263                 .thenReturn(subscriptionInfoList);
264 
265         mPreferenceController.refreshUi();
266 
267         assertThat(Arrays.asList(mPreference.getEntries())).containsExactly(displayName1,
268                 displayName2);
269         assertThat(Arrays.asList(mPreference.getEntryValues())).containsExactly(
270                 String.valueOf(SUBID_1),
271                 String.valueOf(SUBID_2));
272     }
273 
274     @Test
refreshUi_defaultSelection_fourthPriority_system()275     public void refreshUi_defaultSelection_fourthPriority_system() {
276         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(
277                 createSubInfo(SUBID_1, "sub1"), createSubInfo(SUBID_2, "sub2"),
278                 createSubInfo(SUBID_3, "sub3"), createSubInfo(SUBID_4, "sub4"));
279         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
280                 .thenReturn(subscriptionInfoList);
281 
282         setDefaultSubscriptionId(SUBID_4);
283         mPreferenceController.refreshUi();
284 
285         assertThat(mPreference.getValue()).isEqualTo(String.valueOf(SUBID_4));
286     }
287 
288     @Test
refreshUi_defaultSelection_thirdPriority_sms()289     public void refreshUi_defaultSelection_thirdPriority_sms() {
290         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(createSubInfo(SUBID_1, "sub1"),
291                 createSubInfo(SUBID_2, "sub2"), createSubInfo(SUBID_3, "sub3"),
292                 createSubInfo(SUBID_4, "sub4"));
293         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
294                 .thenReturn(subscriptionInfoList);
295 
296         setDefaultSubscriptionId(SUBID_4);
297         setDefaultSmsSubscriptionId(SUBID_3);
298         mPreferenceController.refreshUi();
299 
300         assertThat(mPreference.getValue()).isEqualTo(String.valueOf(SUBID_3));
301     }
302 
303     @Test
refreshUi_defaultSelection_secondPriority_voice()304     public void refreshUi_defaultSelection_secondPriority_voice() {
305         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(createSubInfo(SUBID_1, "sub1"),
306                 createSubInfo(SUBID_2, "sub2"), createSubInfo(SUBID_3, "sub3"),
307                 createSubInfo(SUBID_4, "sub4"));
308         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
309                 .thenReturn(subscriptionInfoList);
310 
311         setDefaultSubscriptionId(SUBID_4);
312         setDefaultSmsSubscriptionId(SUBID_3);
313         setDefaultVoiceSubscriptionId(SUBID_2);
314         mPreferenceController.refreshUi();
315 
316         assertThat(mPreference.getValue()).isEqualTo(String.valueOf(SUBID_2));
317     }
318 
319     @Test
refreshUi_defaultSelection_firstPriority_data()320     public void refreshUi_defaultSelection_firstPriority_data() {
321         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(createSubInfo(SUBID_1, "sub1"),
322                 createSubInfo(SUBID_2, "sub2"), createSubInfo(SUBID_3, "sub3"),
323                 createSubInfo(SUBID_4, "sub4"));
324         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
325                 .thenReturn(subscriptionInfoList);
326 
327         setDefaultSubscriptionId(SUBID_4);
328         setDefaultSmsSubscriptionId(SUBID_3);
329         setDefaultVoiceSubscriptionId(SUBID_2);
330         setDefaultDataSubscriptionId(SUBID_1);
331         mPreferenceController.refreshUi();
332 
333         assertThat(mPreference.getValue()).isEqualTo(String.valueOf(SUBID_1));
334     }
335 
336     @Test
refreshUi_title_fourthPriority_subscriptionNetworkIds()337     public void refreshUi_title_fourthPriority_subscriptionNetworkIds() {
338         SubscriptionInfo subInfo = createSubInfo(
339                 SUBID_1,
340                 /* displayName= */ "",
341                 /* carrierName= */ "",
342                 /* number= */ "");
343         // Multiple subscriptions so that preference is shown / title is set.
344         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(subInfo,
345                 createSubInfo(SUBID_2, "sub2"));
346         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
347                 .thenReturn(subscriptionInfoList);
348         setDefaultDataSubscriptionId(SUBID_1);
349 
350         mPreferenceController.refreshUi();
351 
352         String title = mPreference.getTitle().toString();
353         assertThat(title).contains(String.valueOf(subInfo.getMcc()));
354         assertThat(title).contains(String.valueOf(subInfo.getMnc()));
355         assertThat(title).contains(String.valueOf(subInfo.getSimSlotIndex()));
356         assertThat(title).contains(String.valueOf(subInfo.getSubscriptionId()));
357     }
358 
359     @Test
refreshUi_title_thirdPriority_subscriptionCarrierName()360     public void refreshUi_title_thirdPriority_subscriptionCarrierName() {
361         SubscriptionInfo subInfo = createSubInfo(
362                 SUBID_1,
363                 /* displayName= */ "",
364                 "carrierName",
365                 /* number= */ "");
366         // Multiple subscriptions so that preference is shown / title is set.
367         // Multiple subscriptions so that preference is shown / title is set.
368         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(subInfo,
369                 createSubInfo(SUBID_2, "sub2"));
370         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
371                 .thenReturn(subscriptionInfoList);
372         setDefaultDataSubscriptionId(SUBID_1);
373 
374         mPreferenceController.refreshUi();
375 
376         assertThat(mPreference.getTitle()).isEqualTo(subInfo.getCarrierName());
377     }
378 
379     @Test
refreshUi_title_secondPriority_subscriptionNumber()380     public void refreshUi_title_secondPriority_subscriptionNumber() {
381         SubscriptionInfo subInfo = createSubInfo(
382                 SUBID_1,
383                 /* displayName= */ "",
384                 "carrierName",
385                 "number");
386         // Multiple subscriptions so that preference is shown / title is set.
387         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(subInfo,
388                 createSubInfo(SUBID_2, "sub2"));
389         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
390                 .thenReturn(subscriptionInfoList);
391         setDefaultDataSubscriptionId(SUBID_1);
392 
393         mPreferenceController.refreshUi();
394 
395         assertThat(mPreference.getTitle()).isEqualTo(subInfo.getNumber());
396     }
397 
398     @Test
refreshUi_title_firstPriority_subscriptionDisplayName()399     public void refreshUi_title_firstPriority_subscriptionDisplayName() {
400         SubscriptionInfo subInfo = createSubInfo(
401                 SUBID_1,
402                 "displayName",
403                 "carrierName",
404                 "number");
405         // Multiple subscriptions so that preference is shown / title is set.
406         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(subInfo,
407                 createSubInfo(SUBID_2, "sub2"));
408         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
409                 .thenReturn(subscriptionInfoList);
410         setDefaultDataSubscriptionId(SUBID_1);
411 
412         mPreferenceController.refreshUi();
413 
414         assertThat(mPreference.getTitle()).isEqualTo(subInfo.getDisplayName());
415     }
416 
417     @Test
handlePreferenceChanged_updatesTitle()418     public void handlePreferenceChanged_updatesTitle() {
419         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(createSubInfo(SUBID_1, "sub1"),
420                 createSubInfo(SUBID_2, "sub2"));
421         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
422                 .thenReturn(subscriptionInfoList);
423         setDefaultDataSubscriptionId(SUBID_1);
424         mPreferenceController.refreshUi();
425 
426         mPreference.callChangeListener(String.valueOf(SUBID_2));
427 
428         assertThat(mPreference.getTitle()).isEqualTo("sub2");
429     }
430 
431     @Test
handlePreferenceChanged_returnsTrue()432     public void handlePreferenceChanged_returnsTrue() {
433         List<SubscriptionInfo> subscriptionInfoList = Arrays.asList(createSubInfo(SUBID_1, "sub1"),
434                 createSubInfo(SUBID_2, "sub2"));
435         when(mMockSubscriptionManager.getActiveSubscriptionInfoList())
436                 .thenReturn(subscriptionInfoList);
437         setDefaultDataSubscriptionId(SUBID_1);
438         mPreferenceController.refreshUi();
439 
440         assertThat(mPreferenceController.handlePreferenceChanged(mPreference,
441                 String.valueOf(SUBID_2))).isTrue();
442     }
443 
444     /** Reduce SubscriptionInfo constructor args to the ones we care about here. */
createSubInfo(int subId, String displayName)445     private SubscriptionInfo createSubInfo(int subId, String displayName) {
446         return createSubInfo(subId, displayName, "carrierName", "number");
447     }
448 
449     /** Reduce SubscriptionInfo constructor args to the ones we care about here. */
createSubInfo(int subId, String displayName, String carrierName, String number)450     private SubscriptionInfo createSubInfo(int subId, String displayName, String carrierName,
451             String number) {
452         // Hidden constructor so resort to mocking.
453         SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
454         when(subscriptionInfo.getSubscriptionId()).thenReturn(subId);
455         when(subscriptionInfo.getDisplayName()).thenReturn(displayName);
456         when(subscriptionInfo.getCarrierName()).thenReturn(carrierName);
457         when(subscriptionInfo.getNumber()).thenReturn(number);
458         when(subscriptionInfo.getSimSlotIndex()).thenReturn(111);
459         when(subscriptionInfo.getMcc()).thenReturn(222);
460         when(subscriptionInfo.getMnc()).thenReturn(333);
461         return subscriptionInfo;
462     }
463 
setDefaultSubscriptionId(int id)464     private void setDefaultSubscriptionId(int id) {
465         when(SubscriptionManager.getDefaultSubscriptionId()).thenReturn(id);
466     }
467 
setDefaultSmsSubscriptionId(int id)468     private void setDefaultSmsSubscriptionId(int id) {
469         when(SubscriptionManager.getDefaultSmsSubscriptionId()).thenReturn(id);
470     }
471 
setDefaultVoiceSubscriptionId(int id)472     private void setDefaultVoiceSubscriptionId(int id) {
473         when(SubscriptionManager.getDefaultVoiceSubscriptionId()).thenReturn(id);
474     }
475 
setDefaultDataSubscriptionId(int id)476     private void setDefaultDataSubscriptionId(int id) {
477         when(SubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(id);
478     }
479 }
480