1 /* 2 * Copyright (C) 2022 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.services.telephony.domainselection; 18 19 import static org.junit.Assert.assertNotNull; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.ArgumentMatchers.eq; 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.never; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.verifyNoMoreInteractions; 27 import static org.mockito.Mockito.when; 28 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.content.Context; 32 import android.os.Handler; 33 import android.os.Looper; 34 import android.telephony.BarringInfo; 35 import android.telephony.DomainSelectionService; 36 import android.telephony.DomainSelectionService.SelectionAttributes; 37 import android.telephony.DomainSelectionService.SelectorType; 38 import android.telephony.ServiceState; 39 import android.telephony.SubscriptionInfo; 40 import android.telephony.SubscriptionManager; 41 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 42 import android.telephony.TransportSelectorCallback; 43 import android.testing.TestableLooper; 44 45 import androidx.test.filters.SmallTest; 46 import androidx.test.runner.AndroidJUnit4; 47 48 import com.android.TestContext; 49 import com.android.internal.telephony.flags.Flags; 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.ArgumentCaptor; 56 import org.mockito.Mock; 57 import org.mockito.Mockito; 58 import org.mockito.MockitoAnnotations; 59 60 import java.util.ArrayList; 61 import java.util.List; 62 import java.util.concurrent.Executor; 63 64 /** 65 * Unit tests for TelephonyDomainSelectionService. 66 */ 67 @RunWith(AndroidJUnit4.class) 68 public class TelephonyDomainSelectionServiceTest { 69 private TelephonyDomainSelectionService.ImsStateTrackerFactory mImsStateTrackerFactory = 70 new TelephonyDomainSelectionService.ImsStateTrackerFactory() { 71 @Override 72 public ImsStateTracker create(Context context, int slotId, 73 @NonNull Looper looper) { 74 return mImsStateTracker; 75 } 76 }; 77 private TelephonyDomainSelectionService.DomainSelectorFactory mDomainSelectorFactory = 78 new TelephonyDomainSelectionService.DomainSelectorFactory() { 79 @Override 80 public DomainSelectorBase create(Context context, int slotId, int subId, 81 @SelectorType int selectorType, boolean isEmergency, 82 @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker, 83 @NonNull DomainSelectorBase.DestroyListener listener, 84 @NonNull CrossSimRedialingController crossSimRedialingController, 85 @NonNull DataConnectionStateHelper dataConnectionStateHelper) { 86 switch (selectorType) { 87 case DomainSelectionService.SELECTOR_TYPE_CALLING: // fallthrough 88 case DomainSelectionService.SELECTOR_TYPE_SMS: 89 mDomainSelectorDestroyListener = listener; 90 if (subId == SUB_1) { 91 return mDomainSelectorBase1; 92 } else { 93 return mDomainSelectorBase2; 94 } 95 default: 96 return null; 97 } 98 } 99 }; 100 private static class TestTelephonyDomainSelectionService 101 extends TelephonyDomainSelectionService { 102 private final Context mContext; 103 TestTelephonyDomainSelectionService(Context context, @NonNull ImsStateTrackerFactory imsStateTrackerFactory, @NonNull DomainSelectorFactory domainSelectorFactory, @Nullable DataConnectionStateHelper dataConnectionStateHelper)104 TestTelephonyDomainSelectionService(Context context, 105 @NonNull ImsStateTrackerFactory imsStateTrackerFactory, 106 @NonNull DomainSelectorFactory domainSelectorFactory, 107 @Nullable DataConnectionStateHelper dataConnectionStateHelper) { 108 super(imsStateTrackerFactory, domainSelectorFactory, 109 dataConnectionStateHelper); 110 mContext = context; 111 } 112 113 @Override onCreate()114 public void onCreate() { 115 // attach test context. 116 attachBaseContext(mContext); 117 super.onCreate(); 118 } 119 } 120 private static final int SLOT_0 = 0; 121 private static final int SUB_1 = 1; 122 private static final int SUB_2 = 2; 123 private static final String CALL_ID = "Call_1"; 124 private static final @SelectorType int TEST_SELECTOR_TYPE = 125 DomainSelectionService.SELECTOR_TYPE_CALLING; 126 private static final @SelectorType int INVALID_SELECTOR_TYPE = -1; 127 128 @Mock private DomainSelectorBase mDomainSelectorBase1; 129 @Mock private DomainSelectorBase mDomainSelectorBase2; 130 @Mock private TransportSelectorCallback mSelectorCallback1; 131 @Mock private TransportSelectorCallback mSelectorCallback2; 132 @Mock private ImsStateTracker mImsStateTracker; 133 @Mock private DataConnectionStateHelper mDataConnectionStateHelper; 134 135 private final ServiceState mServiceState = new ServiceState(); 136 private final BarringInfo mBarringInfo = new BarringInfo(); 137 private Context mContext; 138 private Handler mServiceHandler; 139 private TestableLooper mTestableLooper; 140 private SubscriptionManager mSubscriptionManager; 141 private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; 142 private DomainSelectorBase.DestroyListener mDomainSelectorDestroyListener; 143 private TelephonyDomainSelectionService mDomainSelectionService; 144 145 @Before setUp()146 public void setUp() throws Exception { 147 MockitoAnnotations.initMocks(this); 148 149 if (Looper.myLooper() == null) { 150 Looper.prepare(); 151 } 152 153 mContext = new TestContext(); 154 mDomainSelectionService = new TestTelephonyDomainSelectionService(mContext, 155 mImsStateTrackerFactory, mDomainSelectorFactory, 156 mDataConnectionStateHelper); 157 mDomainSelectionService.onCreate(); 158 mServiceHandler = new Handler(mDomainSelectionService.getLooper()); 159 mTestableLooper = new TestableLooper(mDomainSelectionService.getLooper()); 160 161 mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); 162 if (Flags.workProfileApiSplit()) { 163 doReturn(mSubscriptionManager).when(mSubscriptionManager).createForAllUserProfiles(); 164 } 165 ArgumentCaptor<OnSubscriptionsChangedListener> listenerCaptor = 166 ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class); 167 verify(mSubscriptionManager).addOnSubscriptionsChangedListener( 168 any(Executor.class), listenerCaptor.capture()); 169 mOnSubscriptionsChangedListener = listenerCaptor.getValue(); 170 } 171 172 @After tearDown()173 public void tearDown() throws Exception { 174 if (mTestableLooper != null) { 175 mTestableLooper.destroy(); 176 mTestableLooper = null; 177 } 178 mServiceHandler = null; 179 180 if (mDomainSelectionService != null) { 181 mDomainSelectionService.onDestroy(); 182 mDomainSelectionService = null; 183 } 184 185 mDomainSelectorBase1 = null; 186 mDomainSelectorBase2 = null; 187 mSelectorCallback1 = null; 188 mSelectorCallback2 = null; 189 mImsStateTracker = null; 190 mSubscriptionManager = null; 191 mOnSubscriptionsChangedListener = null; 192 mDomainSelectorDestroyListener = null; 193 } 194 195 @Test 196 @SmallTest testGetExecutor()197 public void testGetExecutor() { 198 assertNotNull(mDomainSelectionService.getExecutor()); 199 } 200 201 @Test 202 @SmallTest testOnDomainSelection()203 public void testOnDomainSelection() { 204 SelectionAttributes attr1 = new SelectionAttributes.Builder( 205 SLOT_0, SUB_1, TEST_SELECTOR_TYPE) 206 .setCallId(CALL_ID) 207 .setEmergency(true) 208 .build(); 209 mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1); 210 processAllMessages(); 211 212 verify(mImsStateTracker).start(eq(SUB_1)); 213 verify(mSelectorCallback1).onCreated(eq(mDomainSelectorBase1)); 214 verifyNoMoreInteractions(mSelectorCallback1); 215 verify(mDomainSelectorBase1).selectDomain(eq(attr1), eq(mSelectorCallback1)); 216 } 217 218 @Test 219 @SmallTest testOnDomainSelectionWithInvalidSelectorType()220 public void testOnDomainSelectionWithInvalidSelectorType() { 221 SelectionAttributes attr1 = new SelectionAttributes.Builder( 222 SLOT_0, SUB_1, INVALID_SELECTOR_TYPE) 223 .setCallId(CALL_ID) 224 .setEmergency(true) 225 .build(); 226 mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1); 227 processAllMessages(); 228 229 verify(mImsStateTracker, never()).start(anyInt()); 230 verify(mSelectorCallback1).onSelectionTerminated(anyInt()); 231 verifyNoMoreInteractions(mSelectorCallback1); 232 verify(mDomainSelectorBase1, never()).selectDomain(eq(attr1), eq(mSelectorCallback1)); 233 } 234 235 @Test 236 @SmallTest testOnDomainSelectionTwiceWithDestroy()237 public void testOnDomainSelectionTwiceWithDestroy() { 238 SelectionAttributes attr1 = new SelectionAttributes.Builder( 239 SLOT_0, SUB_1, TEST_SELECTOR_TYPE) 240 .setCallId(CALL_ID) 241 .setEmergency(true) 242 .build(); 243 mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1); 244 processAllMessages(); 245 246 verify(mImsStateTracker).start(eq(SUB_1)); 247 verify(mSelectorCallback1).onCreated(eq(mDomainSelectorBase1)); 248 verifyNoMoreInteractions(mSelectorCallback1); 249 verify(mDomainSelectorBase1).selectDomain(eq(attr1), eq(mSelectorCallback1)); 250 251 // Notify the domain selection service that this domain selector is destroyed. 252 mDomainSelectorDestroyListener.onDomainSelectorDestroyed(mDomainSelectorBase1); 253 254 SelectionAttributes attr2 = new SelectionAttributes.Builder( 255 SLOT_0, SUB_2, TEST_SELECTOR_TYPE) 256 .setCallId(CALL_ID) 257 .setEmergency(true) 258 .build(); 259 mDomainSelectionService.onDomainSelection(attr2, mSelectorCallback2); 260 processAllMessages(); 261 262 verify(mImsStateTracker).start(eq(SUB_2)); 263 verify(mSelectorCallback2).onCreated(eq(mDomainSelectorBase2)); 264 verifyNoMoreInteractions(mSelectorCallback2); 265 verify(mDomainSelectorBase2).selectDomain(eq(attr2), eq(mSelectorCallback2)); 266 } 267 268 @Test 269 @SmallTest testOnDomainSelectionTwiceWithoutDestroy()270 public void testOnDomainSelectionTwiceWithoutDestroy() { 271 SelectionAttributes attr1 = new SelectionAttributes.Builder( 272 SLOT_0, SUB_1, TEST_SELECTOR_TYPE) 273 .setCallId(CALL_ID) 274 .setEmergency(true) 275 .build(); 276 mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1); 277 processAllMessages(); 278 279 verify(mImsStateTracker).start(eq(SUB_1)); 280 verify(mSelectorCallback1).onCreated(eq(mDomainSelectorBase1)); 281 verifyNoMoreInteractions(mSelectorCallback1); 282 verify(mDomainSelectorBase1).selectDomain(eq(attr1), eq(mSelectorCallback1)); 283 284 SelectionAttributes attr2 = new SelectionAttributes.Builder( 285 SLOT_0, SUB_2, TEST_SELECTOR_TYPE) 286 .setCallId(CALL_ID) 287 .setEmergency(true) 288 .build(); 289 mDomainSelectionService.onDomainSelection(attr2, mSelectorCallback2); 290 processAllMessages(); 291 292 verify(mImsStateTracker).start(eq(SUB_2)); 293 verify(mSelectorCallback2).onCreated(eq(mDomainSelectorBase2)); 294 verifyNoMoreInteractions(mSelectorCallback2); 295 verify(mDomainSelectorBase2).selectDomain(eq(attr2), eq(mSelectorCallback2)); 296 } 297 298 @Test 299 @SmallTest testOnServiceStateUpdated()300 public void testOnServiceStateUpdated() { 301 mDomainSelectionService.onServiceStateUpdated(SLOT_0, SUB_1, mServiceState); 302 303 verify(mImsStateTracker).updateServiceState(eq(mServiceState)); 304 } 305 306 @Test 307 @SmallTest testOnBarringInfoUpdated()308 public void testOnBarringInfoUpdated() { 309 mDomainSelectionService.onBarringInfoUpdated(SLOT_0, SUB_1, mBarringInfo); 310 311 verify(mImsStateTracker).updateBarringInfo(eq(mBarringInfo)); 312 } 313 314 @Test 315 @SmallTest testOnDestroy()316 public void testOnDestroy() { 317 SelectionAttributes attr1 = new SelectionAttributes.Builder( 318 SLOT_0, SUB_1, TEST_SELECTOR_TYPE) 319 .setCallId(CALL_ID) 320 .setEmergency(true) 321 .build(); 322 mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1); 323 processAllMessages(); 324 325 mDomainSelectionService.onDestroy(); 326 327 verify(mImsStateTracker).destroy(); 328 verify(mDomainSelectorBase1).destroy(); 329 verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(any()); 330 } 331 332 @Test 333 @SmallTest testHandleSubscriptionsChangedWithEmptySubscriptionInfo()334 public void testHandleSubscriptionsChangedWithEmptySubscriptionInfo() { 335 when(mSubscriptionManager.getActiveSubscriptionInfoList()) 336 .thenReturn(null, new ArrayList<SubscriptionInfo>()); 337 338 mOnSubscriptionsChangedListener.onSubscriptionsChanged(); 339 mOnSubscriptionsChangedListener.onSubscriptionsChanged(); 340 341 verify(mImsStateTracker, never()).start(anyInt()); 342 } 343 344 @Test 345 @SmallTest testHandleSubscriptionsChangedWithActiveSubscriptionInfoAndInvalidSlotIndex()346 public void testHandleSubscriptionsChangedWithActiveSubscriptionInfoAndInvalidSlotIndex() { 347 SubscriptionInfo subsInfo = Mockito.mock(SubscriptionInfo.class); 348 List<SubscriptionInfo> subsInfoList = new ArrayList<>(); 349 subsInfoList.add(subsInfo); 350 when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(subsInfoList); 351 when(subsInfo.getSimSlotIndex()).thenReturn(SubscriptionManager.INVALID_SIM_SLOT_INDEX); 352 353 mOnSubscriptionsChangedListener.onSubscriptionsChanged(); 354 355 verify(mImsStateTracker, never()).start(anyInt()); 356 } 357 358 @Test 359 @SmallTest testHandleSubscriptionsChangedWithActiveSubscriptionInfo()360 public void testHandleSubscriptionsChangedWithActiveSubscriptionInfo() { 361 SubscriptionInfo subsInfo = Mockito.mock(SubscriptionInfo.class); 362 List<SubscriptionInfo> subsInfoList = new ArrayList<>(); 363 subsInfoList.add(subsInfo); 364 when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(subsInfoList); 365 when(subsInfo.getSubscriptionId()) 366 .thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID, SUB_1); 367 when(subsInfo.getSimSlotIndex()).thenReturn(SLOT_0); 368 369 mOnSubscriptionsChangedListener.onSubscriptionsChanged(); 370 mOnSubscriptionsChangedListener.onSubscriptionsChanged(); 371 372 verify(mImsStateTracker).start(eq(SubscriptionManager.INVALID_SUBSCRIPTION_ID)); 373 verify(mImsStateTracker).start(eq(SUB_1)); 374 } 375 processAllMessages()376 private void processAllMessages() { 377 while (!mTestableLooper.getLooper().getQueue().isIdle()) { 378 mTestableLooper.processAllMessages(); 379 } 380 } 381 } 382