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