1 package android.telephony.cts; 2 3 import static org.junit.Assert.assertEquals; 4 import static org.junit.Assert.assertNotNull; 5 import static org.junit.Assert.assertNull; 6 import static org.junit.Assert.assertTrue; 7 import static org.junit.Assert.fail; 8 import static org.junit.Assume.assumeTrue; 9 10 import android.content.Context; 11 import android.content.pm.PackageManager; 12 import android.platform.test.annotations.RequiresFlagsDisabled; 13 import android.platform.test.annotations.RequiresFlagsEnabled; 14 import android.platform.test.flag.junit.CheckFlagsRule; 15 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 16 import android.telephony.CallAttributes; 17 import android.telephony.CallState; 18 import android.telephony.PhoneStateListener; 19 import android.telephony.PreciseCallState; 20 import android.telephony.ServiceState; 21 import android.telephony.SignalStrength; 22 import android.telephony.SubscriptionManager; 23 import android.telephony.TelephonyCallback; 24 import android.telephony.TelephonyManager; 25 import android.telephony.TelephonyManager.CarrierPrivilegesCallback; 26 import android.telephony.TelephonyRegistryManager; 27 import android.telephony.emergency.EmergencyNumber; 28 import android.telephony.ims.ImsCallProfile; 29 import android.text.TextUtils; 30 import android.util.Log; 31 import android.util.Pair; 32 33 import androidx.annotation.NonNull; 34 import androidx.annotation.Nullable; 35 import androidx.test.InstrumentationRegistry; 36 37 import com.android.compatibility.common.util.ShellIdentityUtils; 38 import com.android.internal.telephony.flags.Flags; 39 40 import org.junit.Before; 41 import org.junit.Rule; 42 import org.junit.Test; 43 44 import java.util.ArrayList; 45 import java.util.HashSet; 46 import java.util.List; 47 import java.util.Set; 48 import java.util.concurrent.LinkedBlockingQueue; 49 import java.util.concurrent.Semaphore; 50 import java.util.concurrent.TimeUnit; 51 52 /** 53 * Test TelephonyRegistryManagerTest APIs. 54 */ 55 public class TelephonyRegistryManagerTest { 56 private TelephonyRegistryManager mTelephonyRegistryMgr; 57 private static final long TIMEOUT_MILLIS = 1000; 58 59 @Rule 60 public final CheckFlagsRule mCheckFlagsRule = 61 DeviceFlagsValueProvider.createCheckFlagsRule(); 62 63 @Before setUp()64 public void setUp() throws Exception { 65 assumeTrue(InstrumentationRegistry.getContext().getPackageManager() 66 .hasSystemFeature(PackageManager.FEATURE_TELEPHONY)); 67 68 mTelephonyRegistryMgr = (TelephonyRegistryManager) InstrumentationRegistry.getContext() 69 .getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); 70 } 71 72 /** 73 * expect security exception as there is no carrier privilege permission. 74 */ 75 @Test testNotifyCarrierNetworkChange()76 public void testNotifyCarrierNetworkChange() { 77 try { 78 mTelephonyRegistryMgr.notifyCarrierNetworkChange(true); 79 fail("Expected SecurityException for notifyCarrierNetworkChange"); 80 } catch (SecurityException ex) { 81 /* Expected */ 82 } 83 } 84 85 /** 86 * expect security exception as there is no carrier privilege permission. 87 */ 88 @Test testNotifyCarrierNetworkChangeWithSubscription()89 public void testNotifyCarrierNetworkChangeWithSubscription() { 90 try { 91 mTelephonyRegistryMgr.notifyCarrierNetworkChange( 92 SubscriptionManager.getDefaultSubscriptionId(), /*active=*/ true); 93 fail("Expected SecurityException for notifyCarrierNetworkChange with subscription"); 94 } catch (SecurityException expected) { 95 } 96 } 97 98 @Test testNotifyCallStateChangedForAllSubscriptions()99 public void testNotifyCallStateChangedForAllSubscriptions() throws Exception { 100 Context context = InstrumentationRegistry.getContext(); 101 102 LinkedBlockingQueue<Pair<Integer, String>> queue = new LinkedBlockingQueue<>(1); 103 PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) { 104 @Override 105 public void onCallStateChanged(int state, String number) { 106 queue.offer(Pair.create(state, number)); 107 } 108 }; 109 TelephonyManager tm = context.getSystemService(TelephonyManager.class); 110 tm.listen(psl, PhoneStateListener.LISTEN_CALL_STATE); 111 // clear the initial result from registering the listener. 112 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 113 114 String dummyNumber = "288124"; 115 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 116 (trm) -> trm.notifyCallStateChangedForAllSubscriptions( 117 TelephonyManager.CALL_STATE_IDLE, dummyNumber)); 118 119 Pair<Integer, String> result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 120 assertNotNull("Timed out waiting for phone state change", result); 121 assertEquals(TelephonyManager.CALL_STATE_IDLE, result.first.longValue()); 122 assertTrue(!TextUtils.isEmpty(result.second)); 123 } 124 125 @Test testNotifyCallStateChanged()126 public void testNotifyCallStateChanged() throws Exception { 127 Context context = InstrumentationRegistry.getContext(); 128 129 LinkedBlockingQueue<Pair<Integer, String>> queue = new LinkedBlockingQueue<>(1); 130 PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) { 131 @Override 132 public void onCallStateChanged(int state, String number) { 133 queue.offer(Pair.create(state, number)); 134 } 135 }; 136 TelephonyManager tm = context.getSystemService(TelephonyManager.class); 137 tm = tm.createForSubscriptionId(SubscriptionManager.getDefaultSubscriptionId()); 138 tm.listen(psl, PhoneStateListener.LISTEN_CALL_STATE); 139 // clear the initial result from registering the listener. 140 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 141 142 String dummyNumber = "288124"; 143 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 144 (trm) -> trm.notifyCallStateChanged( 145 SubscriptionManager.getSlotIndex( 146 SubscriptionManager.getDefaultSubscriptionId()), 147 SubscriptionManager.getDefaultSubscriptionId(), 148 TelephonyManager.CALL_STATE_IDLE, dummyNumber)); 149 150 Pair<Integer, String> result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 151 assertNotNull("Timed out waiting for phone state change", result); 152 assertEquals(TelephonyManager.CALL_STATE_IDLE, result.first.longValue()); 153 assertTrue(!TextUtils.isEmpty(result.second)); 154 } 155 156 @Test testNotifyServiceStateChanged()157 public void testNotifyServiceStateChanged() throws Exception { 158 Context context = InstrumentationRegistry.getContext(); 159 160 LinkedBlockingQueue<ServiceState> queue = new LinkedBlockingQueue<>(1); 161 PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) { 162 @Override 163 public void onServiceStateChanged(ServiceState ss) { 164 queue.offer(ss); 165 } 166 }; 167 TelephonyManager tm = context.getSystemService(TelephonyManager.class); 168 tm.listen(psl, PhoneStateListener.LISTEN_SERVICE_STATE); 169 // clear the initial result from registering the listener. 170 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 171 172 ServiceState dummyState = new ServiceState(); 173 dummyState.setCdmaSystemAndNetworkId(1234, 5678); 174 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 175 (trm) -> trm.notifyServiceStateChanged( 176 SubscriptionManager.getSlotIndex( 177 SubscriptionManager.getDefaultSubscriptionId()), 178 SubscriptionManager.getDefaultSubscriptionId(), 179 dummyState)); 180 181 ServiceState result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 182 assertNotNull("Timed out waiting for phone state change", result); 183 assertEquals(dummyState, result); 184 } 185 186 @Test testNotifySignalStrengthChanged()187 public void testNotifySignalStrengthChanged() throws Exception { 188 Context context = InstrumentationRegistry.getContext(); 189 190 LinkedBlockingQueue<SignalStrength> queue = new LinkedBlockingQueue<>(1); 191 PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) { 192 @Override 193 public void onSignalStrengthsChanged(SignalStrength ss) { 194 queue.offer(ss); 195 } 196 }; 197 TelephonyManager tm = context.getSystemService(TelephonyManager.class); 198 tm.listen(psl, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 199 // clear the initial result from registering the listener. 200 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 201 202 SignalStrength testValue = new SignalStrength(); 203 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 204 (trm) -> trm.notifySignalStrengthChanged( 205 SubscriptionManager.getSlotIndex( 206 SubscriptionManager.getDefaultSubscriptionId()), 207 SubscriptionManager.getDefaultSubscriptionId(), 208 testValue)); 209 210 SignalStrength result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 211 assertNotNull("Timed out waiting for phone state change", result); 212 assertEquals(testValue, result); 213 } 214 215 @Test testNotifyMessageWaitingChanged()216 public void testNotifyMessageWaitingChanged() throws Exception { 217 Context context = InstrumentationRegistry.getContext(); 218 219 LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1); 220 PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) { 221 @Override 222 public void onMessageWaitingIndicatorChanged(boolean msgWaitingInd) { 223 queue.offer(msgWaitingInd); 224 } 225 }; 226 TelephonyManager tm = context.getSystemService(TelephonyManager.class); 227 tm.listen(psl, PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR); 228 // clear the initial result from registering the listener. 229 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 230 231 boolean testValue = true; 232 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 233 (trm) -> trm.notifyMessageWaitingChanged( 234 SubscriptionManager.getSlotIndex( 235 SubscriptionManager.getDefaultSubscriptionId()), 236 SubscriptionManager.getDefaultSubscriptionId(), 237 testValue)); 238 239 boolean result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 240 assertEquals(testValue, result); 241 } 242 243 @Test testNotifyCallForwardingChanged()244 public void testNotifyCallForwardingChanged() throws Exception { 245 Context context = InstrumentationRegistry.getContext(); 246 247 LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1); 248 PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) { 249 @Override 250 public void onCallForwardingIndicatorChanged(boolean callForwarding) { 251 queue.offer(callForwarding); 252 } 253 }; 254 TelephonyManager tm = context.getSystemService(TelephonyManager.class); 255 tm.listen(psl, PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR); 256 // clear the initial result from registering the listener. 257 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 258 259 boolean testValue = true; 260 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 261 (trm) -> trm.notifyCallForwardingChanged( 262 SubscriptionManager.getDefaultSubscriptionId(), 263 testValue)); 264 265 boolean result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 266 assertEquals(testValue, result); 267 } 268 269 @Test 270 @RequiresFlagsDisabled(Flags.FLAG_NOTIFY_DATA_ACTIVITY_CHANGED_WITH_SLOT) testNotifyDataActivityChanged()271 public void testNotifyDataActivityChanged() throws Exception { 272 Context context = InstrumentationRegistry.getContext(); 273 274 LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(1); 275 PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) { 276 @Override 277 public void onDataActivity(int activity) { 278 queue.offer(activity); 279 } 280 }; 281 TelephonyManager tm = context.getSystemService(TelephonyManager.class); 282 tm.listen(psl, PhoneStateListener.LISTEN_DATA_ACTIVITY); 283 // clear the initial result from registering the listener. 284 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 285 286 int testValue = TelephonyManager.DATA_ACTIVITY_DORMANT; 287 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 288 (trm) -> trm.notifyDataActivityChanged( 289 SubscriptionManager.getDefaultSubscriptionId(), 290 testValue)); 291 292 int result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 293 assertEquals(testValue, result); 294 } 295 296 @Test 297 @RequiresFlagsEnabled(Flags.FLAG_NOTIFY_DATA_ACTIVITY_CHANGED_WITH_SLOT) testNotifyDataActivityChangedWithSlot()298 public void testNotifyDataActivityChangedWithSlot() throws Exception { 299 Context context = InstrumentationRegistry.getContext(); 300 301 LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(1); 302 PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) { 303 @Override 304 public void onDataActivity(int activity) { 305 queue.offer(activity); 306 } 307 }; 308 TelephonyManager tm = context.getSystemService(TelephonyManager.class); 309 tm.listen(psl, PhoneStateListener.LISTEN_DATA_ACTIVITY); 310 // clear the initial result from registering the listener. 311 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 312 313 int testValue = TelephonyManager.DATA_ACTIVITY_DORMANT; 314 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 315 (trm) -> trm.notifyDataActivityChanged( 316 SubscriptionManager.getSlotIndex( 317 SubscriptionManager.getDefaultSubscriptionId()), 318 SubscriptionManager.getDefaultSubscriptionId(), 319 testValue)); 320 321 int result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 322 assertEquals(testValue, result); 323 } 324 325 @Test testCarrierPrivilegesCallback()326 public void testCarrierPrivilegesCallback() throws Exception { 327 Context context = InstrumentationRegistry.getContext(); 328 329 LinkedBlockingQueue<Pair<Set<String>, Set<Integer>>> carrierPrivilegesQueue = 330 new LinkedBlockingQueue(2); 331 LinkedBlockingQueue<Pair<String, Integer>> carrierServiceQueue = new LinkedBlockingQueue(2); 332 333 CarrierPrivilegesCallback cpc = new TestCarrierPrivilegesCallback(carrierPrivilegesQueue, 334 carrierServiceQueue); 335 CarrierPrivilegesCallback cpc2 = new TestCarrierPrivilegesCallback(carrierPrivilegesQueue, 336 carrierServiceQueue); 337 338 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 339 try { 340 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn( 341 telephonyManager, 342 tm -> tm.registerCarrierPrivilegesCallback(0, context.getMainExecutor(), cpc)); 343 // Clear the initial carrierPrivilegesResult from registering the listener. We can't 344 // necessarily guarantee this is empty so don't assert on it other than the fact we 345 // got _something_. We restore this at the end of the test. 346 Pair<Set<String>, Set<Integer>> initialCarrierPrivilegesState = 347 carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 348 assertNotNull(initialCarrierPrivilegesState); 349 Pair<String, Integer> initialCarrierServiceState = 350 carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 351 assertNotNull(initialCarrierServiceState); 352 353 // Update state 354 Set<String> privilegedPackageNames = 355 Set.of("com.carrier.package1", "com.carrier.package2"); 356 Set<Integer> privilegedUids = Set.of(12345, 54321); 357 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn( 358 mTelephonyRegistryMgr, 359 trm -> { 360 trm.notifyCarrierPrivilegesChanged( 361 0, privilegedPackageNames, privilegedUids); 362 trm.notifyCarrierServiceChanged(0, "com.carrier.package1", 12345); 363 }); 364 Pair<Set<String>, Set<Integer>> carrierPrivilegesResult = 365 carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 366 assertEquals(privilegedPackageNames, carrierPrivilegesResult.first); 367 assertEquals(privilegedUids, carrierPrivilegesResult.second); 368 369 Pair<String, Integer> carrierServiceResult = 370 carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 371 assertEquals("com.carrier.package1", carrierServiceResult.first); 372 assertEquals(12345, (long) carrierServiceResult.second); 373 374 // Update the state again, but only notify carrier privileges change this time 375 Set<String> newPrivilegedPackageNames = Set.of("com.carrier.package1", 376 "com.carrier.package3"); 377 Set<Integer> newPrivilegedUids = Set.of(12345, 678910); 378 379 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn( 380 mTelephonyRegistryMgr, 381 trm -> { 382 trm.notifyCarrierPrivilegesChanged( 383 0, newPrivilegedPackageNames, newPrivilegedUids); 384 }); 385 // The CarrierPrivileges pkgs and UIDs should be updated 386 carrierPrivilegesResult = 387 carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 388 assertEquals(newPrivilegedPackageNames, carrierPrivilegesResult.first); 389 assertEquals(newPrivilegedUids, carrierPrivilegesResult.second); 390 391 // And the CarrierService change notification should NOT be triggered 392 assertNull(carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); 393 394 // Registering cpc2 now immediately gets us the most recent state 395 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn( 396 telephonyManager, 397 tm -> tm.registerCarrierPrivilegesCallback(0, context.getMainExecutor(), cpc2)); 398 carrierPrivilegesResult = carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, 399 TimeUnit.MILLISECONDS); 400 assertEquals(newPrivilegedPackageNames, carrierPrivilegesResult.first); 401 assertEquals(newPrivilegedUids, carrierPrivilegesResult.second); 402 403 carrierServiceResult = carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 404 assertEquals("com.carrier.package1", carrierServiceResult.first); 405 assertEquals(12345, (long) carrierServiceResult.second); 406 407 // Removing cpc means it won't get the final callback when we restore the original state 408 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn( 409 telephonyManager, tm -> tm.unregisterCarrierPrivilegesCallback(cpc)); 410 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn( 411 mTelephonyRegistryMgr, 412 trm -> { 413 trm.notifyCarrierPrivilegesChanged( 414 0, initialCarrierPrivilegesState.first, 415 initialCarrierPrivilegesState.second); 416 trm.notifyCarrierServiceChanged(0, initialCarrierServiceState.first, 417 initialCarrierServiceState.second); 418 }); 419 420 carrierPrivilegesResult = carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, 421 TimeUnit.MILLISECONDS); 422 assertEquals(initialCarrierPrivilegesState.first, carrierPrivilegesResult.first); 423 assertEquals(initialCarrierPrivilegesState.second, carrierPrivilegesResult.second); 424 425 carrierServiceResult = carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 426 assertEquals(initialCarrierServiceState.first, carrierServiceResult.first); 427 assertEquals(initialCarrierServiceState.second, carrierServiceResult.second); 428 429 // No further callbacks received 430 assertNull(carrierPrivilegesQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); 431 assertNull(carrierServiceQueue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); 432 } finally { 433 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn( 434 telephonyManager, 435 tm -> { 436 tm.unregisterCarrierPrivilegesCallback(cpc); // redundant, but still allowed 437 tm.unregisterCarrierPrivilegesCallback(cpc2); 438 }); 439 } 440 } 441 442 private class TestCarrierPrivilegesCallback implements CarrierPrivilegesCallback { 443 LinkedBlockingQueue<Pair<Set<String>, Set<Integer>>> mCarrierPrivilegesQueue; 444 LinkedBlockingQueue<Pair<String, Integer>> mCarrierServiceQueue; 445 TestCarrierPrivilegesCallback( LinkedBlockingQueue<Pair<Set<String>, Set<Integer>>> carrierPrivilegesQueue, LinkedBlockingQueue<Pair<String, Integer>> carrierServiceQueue)446 TestCarrierPrivilegesCallback( 447 LinkedBlockingQueue<Pair<Set<String>, Set<Integer>>> carrierPrivilegesQueue, 448 LinkedBlockingQueue<Pair<String, Integer>> carrierServiceQueue) { 449 mCarrierPrivilegesQueue = carrierPrivilegesQueue; 450 mCarrierServiceQueue = carrierServiceQueue; 451 } 452 453 @Override onCarrierPrivilegesChanged(@onNull Set<String> privilegedPackageNames, @NonNull Set<Integer> privilegedUids)454 public void onCarrierPrivilegesChanged(@NonNull Set<String> privilegedPackageNames, 455 @NonNull Set<Integer> privilegedUids) { 456 mCarrierPrivilegesQueue.offer(new Pair<>(privilegedPackageNames, privilegedUids)); 457 } 458 459 @Override onCarrierServiceChanged(@ullable String carrierServicePackageName, int carrierServiceUid)460 public void onCarrierServiceChanged(@Nullable String carrierServicePackageName, 461 int carrierServiceUid) { 462 mCarrierServiceQueue.offer(new Pair<>(carrierServicePackageName, carrierServiceUid)); 463 } 464 } 465 466 467 private static class SimultaneousCallingListener extends TelephonyCallback implements 468 TelephonyCallback.SimultaneousCellularCallingSupportListener { 469 470 private final LinkedBlockingQueue<Set<Integer>> mQueue; 471 SimultaneousCallingListener(LinkedBlockingQueue<Set<Integer>> queue)472 SimultaneousCallingListener(LinkedBlockingQueue<Set<Integer>> queue) { 473 mQueue = queue; 474 } 475 476 @Override onSimultaneousCellularCallingSubscriptionsChanged( @onNull Set<Integer> simultaneousCallingSubscriptionIds)477 public void onSimultaneousCellularCallingSubscriptionsChanged( 478 @NonNull Set<Integer> simultaneousCallingSubscriptionIds) { 479 mQueue.offer(simultaneousCallingSubscriptionIds); 480 } 481 } 482 483 @RequiresFlagsEnabled(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) 484 @Test testSimultaneousCellularCallingNotifications()485 public void testSimultaneousCellularCallingNotifications() throws Exception { 486 LinkedBlockingQueue<Set<Integer>> queue = new LinkedBlockingQueue<>(2); 487 SimultaneousCallingListener listener = new SimultaneousCallingListener(queue); 488 Context context = InstrumentationRegistry.getContext(); 489 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 490 491 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 492 (tm) -> tm.registerTelephonyCallback(context.getMainExecutor(), listener), 493 "android.permission.READ_PRIVILEGED_PHONE_STATE"); 494 // get the current value 495 Set<Integer> initialVal = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 496 Set<Integer> testVal = new HashSet<>(); 497 testVal.add(1000); 498 testVal.add(1100); 499 try { 500 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 501 (trm) -> trm.notifySimultaneousCellularCallingSubscriptionsChanged(testVal)); 502 Set<Integer> resultVal = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 503 assertEquals(testVal, resultVal); 504 } finally { 505 // set back the initial value so that we do not cause an invalid value to be returned. 506 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 507 (trm) -> trm.notifySimultaneousCellularCallingSubscriptionsChanged(initialVal)); 508 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 509 (tm) -> tm.unregisterTelephonyCallback(listener)); 510 } 511 } 512 513 514 @Test testNotifyPreciseCallStateWithImsCall()515 public void testNotifyPreciseCallStateWithImsCall() throws Exception { 516 Context context = InstrumentationRegistry.getContext(); 517 518 LinkedBlockingQueue<List<CallState>> queue = new LinkedBlockingQueue<>(1); 519 TestTelephonyCallback testCb = new TestTelephonyCallback(queue); 520 521 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 522 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 523 (tm) -> tm.registerTelephonyCallback(context.getMainExecutor(), testCb)); 524 // clear the initial result from registering the listener. 525 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 526 527 int[] dummyCallStates = {PreciseCallState.PRECISE_CALL_STATE_INCOMING, 528 PreciseCallState.PRECISE_CALL_STATE_ACTIVE, 529 PreciseCallState.PRECISE_CALL_STATE_IDLE}; 530 String[] dummyImsCallIds = {"1", "0", "-1"}; 531 int[] dummyImsServiceTypes = {ImsCallProfile.SERVICE_TYPE_NORMAL, 532 ImsCallProfile.SERVICE_TYPE_NORMAL, 533 ImsCallProfile.SERVICE_TYPE_NONE}; 534 int[] dummyImsCallTypes = {ImsCallProfile.CALL_TYPE_VT, 535 ImsCallProfile.CALL_TYPE_VOICE, 536 ImsCallProfile.CALL_TYPE_NONE}; 537 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 538 (trm) -> trm.notifyPreciseCallState( 539 SubscriptionManager.getSlotIndex( 540 SubscriptionManager.getDefaultSubscriptionId()), 541 SubscriptionManager.getDefaultSubscriptionId(), 542 dummyCallStates, dummyImsCallIds, dummyImsServiceTypes, dummyImsCallTypes)); 543 544 List<CallState> testCallStatesResult = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 545 assertNotNull("Timed out waiting for phone state change", testCallStatesResult); 546 assertEquals(2, testCallStatesResult.size()); 547 assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, 548 testCallStatesResult.get(0).getCallState()); 549 assertEquals(PreciseCallState.PRECISE_CALL_STATE_INCOMING, 550 testCallStatesResult.get(1).getCallState()); 551 assertEquals("0", 552 testCallStatesResult.get(0).getImsCallSessionId()); 553 assertEquals("1", 554 testCallStatesResult.get(1).getImsCallSessionId()); 555 assertEquals(ImsCallProfile.CALL_TYPE_VOICE, 556 testCallStatesResult.get(0).getImsCallType()); 557 assertEquals(ImsCallProfile.CALL_TYPE_VT, 558 testCallStatesResult.get(1).getImsCallType()); 559 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 560 (tm) -> tm.unregisterTelephonyCallback(testCb)); 561 } 562 563 @Test testNotifyPreciseCallStateWithCsCall()564 public void testNotifyPreciseCallStateWithCsCall() throws Exception { 565 Context context = InstrumentationRegistry.getContext(); 566 567 LinkedBlockingQueue<List<CallState>> queue = new LinkedBlockingQueue<>(1); 568 TestTelephonyCallback testCb = new TestTelephonyCallback(queue); 569 570 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 571 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 572 (tm) -> tm.registerTelephonyCallback(context.getMainExecutor(), testCb)); 573 // clear the initial result from registering the listener. 574 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 575 576 int[] dummyCallStates = {PreciseCallState.PRECISE_CALL_STATE_INCOMING, 577 PreciseCallState.PRECISE_CALL_STATE_ACTIVE, 578 PreciseCallState.PRECISE_CALL_STATE_IDLE}; 579 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 580 (trm) -> trm.notifyPreciseCallState( 581 SubscriptionManager.getSlotIndex( 582 SubscriptionManager.getDefaultSubscriptionId()), 583 SubscriptionManager.getDefaultSubscriptionId(), 584 dummyCallStates, null, null, null)); 585 586 List<CallState> testCallStatesResult = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 587 assertNotNull("Timed out waiting for phone state change", testCallStatesResult); 588 assertEquals(2, testCallStatesResult.size()); 589 assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, 590 testCallStatesResult.get(0).getCallState()); 591 assertEquals(PreciseCallState.PRECISE_CALL_STATE_INCOMING, 592 testCallStatesResult.get(1).getCallState()); 593 assertNull(testCallStatesResult.get(0).getImsCallSessionId()); 594 assertNull(testCallStatesResult.get(1).getImsCallSessionId()); 595 assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, 596 testCallStatesResult.get(0).getImsCallServiceType()); 597 assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, 598 testCallStatesResult.get(1).getImsCallServiceType()); 599 assertEquals(ImsCallProfile.CALL_TYPE_NONE, 600 testCallStatesResult.get(0).getImsCallType()); 601 assertEquals(ImsCallProfile.CALL_TYPE_NONE, 602 testCallStatesResult.get(1).getImsCallType()); 603 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 604 (tm) -> tm.unregisterTelephonyCallback(testCb)); 605 } 606 607 @Test testNotifyPreciseCallStateLegacyCallback()608 public void testNotifyPreciseCallStateLegacyCallback() throws Exception { 609 Context context = InstrumentationRegistry.getContext(); 610 611 LinkedBlockingQueue<CallAttributes> queue = new LinkedBlockingQueue<>(1); 612 TestTelephonyCallbackLegacy testCb = new TestTelephonyCallbackLegacy(queue); 613 614 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 615 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 616 (tm) -> tm.registerTelephonyCallback(context.getMainExecutor(), testCb)); 617 // clear the initial result from registering the listener. 618 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 619 620 int[] dummyCallStates = {PreciseCallState.PRECISE_CALL_STATE_INCOMING, 621 PreciseCallState.PRECISE_CALL_STATE_HOLDING, 622 PreciseCallState.PRECISE_CALL_STATE_IDLE}; 623 String[] dummyImsCallIds = {"1", "0", "-1"}; 624 int[] dummyImsServiceTypes = {ImsCallProfile.SERVICE_TYPE_NORMAL, 625 ImsCallProfile.SERVICE_TYPE_NORMAL, 626 ImsCallProfile.SERVICE_TYPE_NONE}; 627 int[] dummyImsCallTypes = {ImsCallProfile.CALL_TYPE_VT, 628 ImsCallProfile.CALL_TYPE_VOICE, 629 ImsCallProfile.CALL_TYPE_NONE}; 630 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 631 (trm) -> trm.notifyPreciseCallState( 632 SubscriptionManager.getSlotIndex( 633 SubscriptionManager.getDefaultSubscriptionId()), 634 SubscriptionManager.getDefaultSubscriptionId(), 635 dummyCallStates, dummyImsCallIds, dummyImsServiceTypes, dummyImsCallTypes)); 636 637 CallAttributes testCallAttributesResult = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 638 assertNotNull("Timed out waiting for phone state change", testCallAttributesResult); 639 640 assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, 641 testCallAttributesResult.getPreciseCallState().getForegroundCallState()); 642 assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, 643 testCallAttributesResult.getPreciseCallState().getBackgroundCallState()); 644 assertEquals(PreciseCallState.PRECISE_CALL_STATE_INCOMING, 645 testCallAttributesResult.getPreciseCallState().getRingingCallState()); 646 647 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 648 (tm) -> tm.unregisterTelephonyCallback(testCb)); 649 } 650 651 @Test testNotifyPreciseCallStatePhoneStateListener()652 public void testNotifyPreciseCallStatePhoneStateListener() throws Exception { 653 Context context = InstrumentationRegistry.getContext(); 654 655 LinkedBlockingQueue<CallAttributes> queue = new LinkedBlockingQueue<>(1); 656 PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) { 657 @Override 658 public void onCallAttributesChanged(CallAttributes ca) { 659 queue.offer(ca); 660 } 661 }; 662 663 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 664 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 665 (tm) -> tm.listen(psl, PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)); 666 // clear the initial result from registering the listener. 667 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 668 669 int[] dummyCallStates = {PreciseCallState.PRECISE_CALL_STATE_IDLE, 670 PreciseCallState.PRECISE_CALL_STATE_ACTIVE, 671 PreciseCallState.PRECISE_CALL_STATE_HOLDING}; 672 String[] dummyImsCallIds = {"-1", "0", "1"}; 673 int[] dummyImsServiceTypes = {ImsCallProfile.SERVICE_TYPE_NONE, 674 ImsCallProfile.SERVICE_TYPE_NORMAL, 675 ImsCallProfile.SERVICE_TYPE_NORMAL}; 676 int[] dummyImsCallTypes = {ImsCallProfile.CALL_TYPE_NONE, 677 ImsCallProfile.CALL_TYPE_VOICE, 678 ImsCallProfile.CALL_TYPE_VT}; 679 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 680 (trm) -> trm.notifyPreciseCallState( 681 SubscriptionManager.getSlotIndex( 682 SubscriptionManager.getDefaultSubscriptionId()), 683 SubscriptionManager.getDefaultSubscriptionId(), 684 dummyCallStates, dummyImsCallIds, dummyImsServiceTypes, dummyImsCallTypes)); 685 686 CallAttributes testCallAttributesResult = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 687 assertNotNull("Timed out waiting for phone state change", testCallAttributesResult); 688 689 assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, 690 testCallAttributesResult.getPreciseCallState().getForegroundCallState()); 691 assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, 692 testCallAttributesResult.getPreciseCallState().getBackgroundCallState()); 693 assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, 694 testCallAttributesResult.getPreciseCallState().getRingingCallState()); 695 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 696 (tm) -> tm.listen(psl, PhoneStateListener.LISTEN_NONE)); 697 } 698 699 @Test testNotifyOutgoingEmergencyCall()700 public void testNotifyOutgoingEmergencyCall() throws Exception { 701 Context context = InstrumentationRegistry.getContext(); 702 String testEmergencyNumber = "9998887776655443210"; 703 EmergencyNumber emergencyNumber = new EmergencyNumber( 704 testEmergencyNumber, 705 "us", 706 "30", 707 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, 708 new ArrayList<>(), 709 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, 710 EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); 711 int defaultSubId = SubscriptionManager.getDefaultSubscriptionId(); 712 int phoneId = SubscriptionManager.getSlotIndex(defaultSubId); 713 714 LinkedBlockingQueue<List<CallState>> queue = new LinkedBlockingQueue<>(1); 715 TestTelephonyCallback testCb = new TestTelephonyCallback(queue); 716 717 // Register telephony callback. 718 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 719 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 720 (tm) -> tm.registerTelephonyCallback(context.getMainExecutor(), testCb)); 721 // clear the initial result from registering the listener. 722 queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 723 724 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 725 (trm) -> trm.notifyOutgoingEmergencyCall(phoneId, defaultSubId, emergencyNumber)); 726 assertTrue(testCb.mCallbackSemaphore.tryAcquire(15, TimeUnit.SECONDS)); 727 assertEquals(emergencyNumber, testCb.mLastOutgoingEmergencyNumber); 728 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 729 (tm) -> tm.unregisterTelephonyCallback(testCb)); 730 } 731 732 private class TestTelephonyCallback extends TelephonyCallback 733 implements TelephonyCallback.CallAttributesListener, 734 TelephonyCallback.OutgoingEmergencyCallListener { 735 public Semaphore mCallbackSemaphore = new Semaphore(0); 736 LinkedBlockingQueue<List<CallState>> mTestCallStatesQueue; 737 private EmergencyNumber mLastOutgoingEmergencyNumber; 738 TestTelephonyCallback(LinkedBlockingQueue<List<CallState>> queue)739 TestTelephonyCallback(LinkedBlockingQueue<List<CallState>> queue) { 740 mTestCallStatesQueue = queue; 741 } 742 @Override onCallStatesChanged(@onNull List<CallState> callStateList)743 public void onCallStatesChanged(@NonNull List<CallState> callStateList) { 744 mTestCallStatesQueue.offer(callStateList); 745 } 746 747 @Override onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber, int subscriptionId)748 public void onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber, 749 int subscriptionId) { 750 Log.i("telecomTag", "onOutgoingEmergencyCall: telephony callback"); 751 mLastOutgoingEmergencyNumber = placedEmergencyNumber; 752 mCallbackSemaphore.release(); 753 } 754 } 755 756 private class TestTelephonyCallbackLegacy extends TelephonyCallback 757 implements TelephonyCallback.CallAttributesListener { 758 LinkedBlockingQueue<CallAttributes> mTestCallAttributes; TestTelephonyCallbackLegacy(LinkedBlockingQueue<CallAttributes> queue)759 TestTelephonyCallbackLegacy(LinkedBlockingQueue<CallAttributes> queue) { 760 mTestCallAttributes = queue; 761 } 762 @Override onCallAttributesChanged(@onNull CallAttributes callAttributes)763 public void onCallAttributesChanged(@NonNull CallAttributes callAttributes) { 764 mTestCallAttributes.offer(callAttributes); 765 } 766 } 767 768 private static class CarrierRoamingNtnModeListener extends TelephonyCallback 769 implements TelephonyCallback.CarrierRoamingNtnModeListener { 770 771 private final LinkedBlockingQueue<Boolean> mQueue; 772 CarrierRoamingNtnModeListener(LinkedBlockingQueue<Boolean> queue)773 CarrierRoamingNtnModeListener(LinkedBlockingQueue<Boolean> queue) { 774 mQueue = queue; 775 } 776 777 @Override onCarrierRoamingNtnModeChanged(boolean active)778 public void onCarrierRoamingNtnModeChanged(boolean active) { 779 mQueue.offer(active); 780 } 781 } 782 783 @Test 784 @RequiresFlagsEnabled(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) testCarrierRoamingNtnModeChanged()785 public void testCarrierRoamingNtnModeChanged() throws Exception { 786 LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1); 787 CarrierRoamingNtnModeListener listener = new CarrierRoamingNtnModeListener(queue); 788 789 Context context = InstrumentationRegistry.getContext(); 790 TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); 791 telephonyManager = telephonyManager.createForSubscriptionId( 792 SubscriptionManager.getDefaultSubscriptionId()); 793 794 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 795 (tm) -> tm.registerTelephonyCallback(context.getMainExecutor(), listener), 796 "android.permission.READ_PRIVILEGED_PHONE_STATE"); 797 798 // Get the current value 799 boolean initialValue = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 800 801 try { 802 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 803 (trm) -> trm.notifyCarrierRoamingNtnModeChanged( 804 SubscriptionManager.getDefaultSubscriptionId(), true)); 805 boolean resultVal = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 806 assertTrue(resultVal); 807 } finally { 808 // set back the initial value so that we do not cause an invalid value to be returned. 809 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr, 810 (trm) -> trm.notifyCarrierRoamingNtnModeChanged( 811 SubscriptionManager.getDefaultSubscriptionId(), initialValue)); 812 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(telephonyManager, 813 (tm) -> tm.unregisterTelephonyCallback(listener)); 814 } 815 } 816 } 817