1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.telephony.ims.cts;
18 
19 import static android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.DUPLEX_MODE_RECEIVE_ONLY;
20 import static android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.DUPLEX_MODE_SEND_ONLY;
21 import static android.telephony.ims.RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN;
22 import static android.telephony.ims.RcsContactUceCapability.REQUEST_RESULT_FOUND;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 
29 import android.app.UiAutomation;
30 import android.content.BroadcastReceiver;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.net.Uri;
35 import android.os.PersistableBundle;
36 import android.telecom.PhoneAccount;
37 import android.telephony.CarrierConfigManager;
38 import android.telephony.SubscriptionManager;
39 import android.telephony.TelephonyManager;
40 import android.telephony.cts.util.TelephonyUtils;
41 import android.telephony.ims.ImsException;
42 import android.telephony.ims.ImsManager;
43 import android.telephony.ims.ProvisioningManager;
44 import android.telephony.ims.RcsContactPresenceTuple;
45 import android.telephony.ims.RcsContactUceCapability;
46 import android.telephony.ims.RcsUceAdapter;
47 import android.telephony.ims.feature.ImsFeature;
48 import android.telephony.ims.stub.ImsFeatureConfiguration;
49 import android.util.Log;
50 
51 import androidx.test.platform.app.InstrumentationRegistry;
52 
53 import com.android.compatibility.common.util.ShellIdentityUtils;
54 import com.android.i18n.phonenumbers.NumberParseException;
55 import com.android.i18n.phonenumbers.PhoneNumberUtil;
56 import com.android.i18n.phonenumbers.Phonenumber;
57 
58 import org.junit.After;
59 import org.junit.AfterClass;
60 import org.junit.Before;
61 import org.junit.BeforeClass;
62 import org.junit.Test;
63 
64 import java.text.SimpleDateFormat;
65 import java.time.Instant;
66 import java.util.ArrayList;
67 import java.util.GregorianCalendar;
68 import java.util.List;
69 import java.util.Random;
70 import java.util.concurrent.BlockingQueue;
71 import java.util.concurrent.CountDownLatch;
72 import java.util.concurrent.LinkedBlockingQueue;
73 import java.util.concurrent.TimeUnit;
74 
75 public class EabControllerTest {
76 
77     private static final String TAG = "EabControllerTest";
78     private static final String COMMAND_BASE = "cmd phone ";
79     private static final String COMMAND_GET_EAB_CONTACT = "uce get-eab-capability ";
80 
81     private static int sTestSlot = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
82     private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
83     private static ImsServiceConnector sServiceConnector;
84     private static CarrierConfigReceiver sReceiver;
85     private static String sTestPhoneNumber;
86     private static Uri sTestNumberUri;
87     private static boolean sDeviceUceEnabled;
88 
89     private static final String TEST_SERVICE_DESCRIPTION = "description_test1";
90     private static final int EXPIRATION_TIME_IN_SEC = 1;
91     private static final int WAITING_IN_MILLI_SEC = 1000;
92     private static final int POLLING_RETRY_TIMES = 3;
93 
94     BlockingQueue<Long> mErrorQueue = new LinkedBlockingQueue<>();
95     BlockingQueue<Boolean> mCompleteQueue = new LinkedBlockingQueue<>();
96     BlockingQueue<RcsContactUceCapability> mCapabilityQueue = new LinkedBlockingQueue<>();
97     RcsUceAdapter.CapabilitiesCallback mCallback = new RcsUceAdapter.CapabilitiesCallback() {
98         @Override
99         public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
100             capabilities.forEach(c -> mCapabilityQueue.offer(c));
101         }
102 
103         @Override
104         public void onComplete() {
105             mCompleteQueue.offer(true);
106         }
107 
108         @Override
109         public void onError(int errorCode, long retryAfterMilliseconds) {
110             mErrorQueue.offer(new Long(errorCode));
111             mErrorQueue.offer(retryAfterMilliseconds);
112         }
113     };
114 
115     private static class CarrierConfigReceiver extends BroadcastReceiver {
116         private CountDownLatch mLatch = new CountDownLatch(1);
117         private final int mSubId;
118 
CarrierConfigReceiver(int subId)119         CarrierConfigReceiver(int subId) {
120             mSubId = subId;
121         }
122 
123         @Override
onReceive(Context context, Intent intent)124         public void onReceive(Context context, Intent intent) {
125             if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
126                 int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1);
127                 if (mSubId == subId) {
128                     mLatch.countDown();
129                 }
130             }
131         }
132 
clearQueue()133         void clearQueue() {
134             mLatch = new CountDownLatch(1);
135         }
136 
waitForCarrierConfigChanged()137         void waitForCarrierConfigChanged() throws Exception {
138             mLatch.await(5000, TimeUnit.MILLISECONDS);
139         }
140     }
141 
142     @BeforeClass
beforeAllTests()143     public static void beforeAllTests() throws Exception {
144         if (!ImsUtils.shouldTestImsService()) {
145             return;
146         }
147 
148         sTestPhoneNumber = generateRandomPhoneNumber();
149         sTestNumberUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, sTestPhoneNumber, null);
150 
151         sTestSub = ImsUtils.getPreferredActiveSubId();
152         sTestSlot = SubscriptionManager.getSlotIndex(sTestSub);
153 
154         sServiceConnector = new ImsServiceConnector(InstrumentationRegistry.getInstrumentation());
155         sServiceConnector.clearAllActiveImsServices(sTestSlot);
156         sDeviceUceEnabled = sServiceConnector.getDeviceUceEnabled();
157         sServiceConnector.setDeviceUceEnabled(true);
158 
159         sReceiver = new CarrierConfigReceiver(sTestSub);
160         IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
161         // ACTION_CARRIER_CONFIG_CHANGED is sticky, so we will get a callback right away.
162         InstrumentationRegistry.getInstrumentation().getContext()
163                 .registerReceiver(sReceiver, filter);
164 
165         overrideCarrierConfig();
166 
167         connectTestImsService();
168     }
169 
generateRandomPhoneNumber()170     private static String generateRandomPhoneNumber() {
171         Random random = new Random();
172         StringBuilder builder = new StringBuilder();
173         for (int i = 0; i < 10; i++) {
174             builder.append(random.nextInt(10));
175         }
176         return builder.toString();
177     }
178 
179     @AfterClass
afterAllTests()180     public static void afterAllTests() throws Exception {
181         if (!ImsUtils.shouldTestImsService()) {
182             return;
183         }
184         // Restore all ImsService configurations that existed before the test.
185         if (sServiceConnector != null) {
186             sServiceConnector.disconnectCarrierImsService();
187             sServiceConnector.disconnectDeviceImsService();
188             sServiceConnector.disconnectServices();
189             sServiceConnector.setDeviceUceEnabled(sDeviceUceEnabled);
190         }
191         sServiceConnector = null;
192 
193         overrideCarrierConfig(null);
194 
195         if (sReceiver != null) {
196             InstrumentationRegistry.getInstrumentation().getContext().unregisterReceiver(sReceiver);
197             sReceiver = null;
198         }
199     }
200 
201     @Before
beforeTest()202     public void beforeTest() {
203         if (!ImsUtils.shouldTestImsService()) {
204             return;
205         }
206         if (!SubscriptionManager.isValidSubscriptionId(sTestSub)) {
207             fail("This test requires that there is a SIM in the device!");
208         }
209     }
210 
211     @After
afterTest()212     public void afterTest() {
213         if (!ImsUtils.shouldTestImsService()) {
214             return;
215         }
216         // Remove all the test contacts from EAB database
217         removeTestContactFromEab();
218 
219         mErrorQueue.clear();
220         mCompleteQueue.clear();
221         mCapabilityQueue.clear();
222     }
223 
224     @Test
testRequestCapabilities()225     public void testRequestCapabilities() throws Exception {
226         if (!ImsUtils.shouldTestImsService()) {
227             return;
228         }
229         ArrayList<Uri> contacts = new ArrayList<>(1);
230         contacts.add(sTestNumberUri);
231         fakeNetworkResult(getPidfXmlData(
232                 sTestNumberUri,
233                 TEST_SERVICE_DESCRIPTION,
234                 TUPLE_BASIC_STATUS_OPEN,
235                 false,
236                 true,
237                 DUPLEX_MODE_RECEIVE_ONLY,
238                 DUPLEX_MODE_SEND_ONLY));
239         // Request capabilities for saving capability to EAB provider
240         requestCapabilities(contacts);
241         mErrorQueue.clear();
242         mCompleteQueue.clear();
243         mCapabilityQueue.clear();
244 
245         // Request capabilities again to get the capabilities in EAB provider
246         RcsContactUceCapability capability = requestCapabilities(contacts);
247 
248         // Verify that the capability in EAB is the same as expected
249         verifyCapabilityResult(capability,
250                 sTestNumberUri,
251                 TEST_SERVICE_DESCRIPTION,
252                 TUPLE_BASIC_STATUS_OPEN,
253                 REQUEST_RESULT_FOUND,
254                 RcsContactUceCapability.SOURCE_TYPE_CACHED,
255                 false,
256                 true,
257                 DUPLEX_MODE_RECEIVE_ONLY,
258                 DUPLEX_MODE_SEND_ONLY);
259 
260         // Verify the onCompleted is called
261         waitForResult(mCompleteQueue);
262     }
263 
264     @Test
testRequestAvailabilities()265     public void testRequestAvailabilities() throws Exception {
266         if (!ImsUtils.shouldTestImsService()) {
267             return;
268         }
269         fakeNetworkResult(getPidfXmlData(
270                 sTestNumberUri,
271                 TEST_SERVICE_DESCRIPTION,
272                 TUPLE_BASIC_STATUS_OPEN,
273                 false,
274                 true,
275                 DUPLEX_MODE_RECEIVE_ONLY,
276                 DUPLEX_MODE_SEND_ONLY));
277         // Request capabilities for saving capability to EAB provider
278         requestAvailability(sTestNumberUri);
279         mErrorQueue.clear();
280         mCompleteQueue.clear();
281         mCapabilityQueue.clear();
282 
283         // Request capabilities again to get the capabilities in EAB provider
284         RcsContactUceCapability capability = requestAvailability(sTestNumberUri);
285 
286         // Verify that the capability in EAB is the same as expected
287         verifyCapabilityResult(capability,
288                 sTestNumberUri,
289                 TEST_SERVICE_DESCRIPTION,
290                 TUPLE_BASIC_STATUS_OPEN,
291                 REQUEST_RESULT_FOUND,
292                 RcsContactUceCapability.SOURCE_TYPE_CACHED,
293                 false,
294                 true,
295                 DUPLEX_MODE_RECEIVE_ONLY,
296                 DUPLEX_MODE_SEND_ONLY);
297 
298         // Verify the onCompleted is called
299         waitForResult(mCompleteQueue);
300     }
301 
302     @Test
testRequestExpiredCapabilities()303     public void testRequestExpiredCapabilities() throws Exception {
304         if (!ImsUtils.shouldTestImsService()) {
305             return;
306         }
307 
308         // Set capabilities expiration time
309         setProvisioningIntValue(ProvisioningManager.KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC,
310                 EXPIRATION_TIME_IN_SEC);
311 
312         ArrayList<Uri> contacts = new ArrayList<>(1);
313         contacts.add(sTestNumberUri);
314         fakeNetworkResult(getPidfXmlData(
315                 sTestNumberUri,
316                 TEST_SERVICE_DESCRIPTION,
317                 TUPLE_BASIC_STATUS_OPEN,
318                 false,
319                 true,
320                 DUPLEX_MODE_RECEIVE_ONLY,
321                 DUPLEX_MODE_SEND_ONLY));
322         // Request capabilities for saving expired capability to EAB provider
323         requestCapabilities(contacts);
324         mErrorQueue.clear();
325         mCompleteQueue.clear();
326         mCapabilityQueue.clear();
327 
328         waitingEabCapabilityExpire();
329 
330         // Request capabilities again
331         RcsContactUceCapability capability = requestCapabilities(contacts);
332 
333         // Verify that return the availabilities from network instead of the EAB provider
334         verifyCapabilityResult(capability,
335                 sTestNumberUri,
336                 TEST_SERVICE_DESCRIPTION,
337                 TUPLE_BASIC_STATUS_OPEN,
338                 REQUEST_RESULT_FOUND,
339                 RcsContactUceCapability.SOURCE_TYPE_NETWORK,
340                 false,
341                 true,
342                 DUPLEX_MODE_RECEIVE_ONLY,
343                 DUPLEX_MODE_SEND_ONLY);
344 
345         // Verify the onCompleted is called
346         waitForResult(mCompleteQueue);
347     }
348 
349     @Test
testRequestExpiredAvailabilities()350     public void testRequestExpiredAvailabilities() throws Exception {
351         if (!ImsUtils.shouldTestImsService()) {
352             return;
353         }
354 
355         // Set availability expiration time
356         setProvisioningIntValue(ProvisioningManager.KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC,
357                 EXPIRATION_TIME_IN_SEC);
358 
359         fakeNetworkResult(getPidfXmlData(
360                 sTestNumberUri,
361                 TEST_SERVICE_DESCRIPTION,
362                 TUPLE_BASIC_STATUS_OPEN,
363                 true,
364                 false,
365                 DUPLEX_MODE_RECEIVE_ONLY,
366                 DUPLEX_MODE_SEND_ONLY));
367         // Request availabilities for saving availabilities to EAB provider
368         requestAvailability(sTestNumberUri);
369         mErrorQueue.clear();
370         mCompleteQueue.clear();
371         mCapabilityQueue.clear();
372 
373         // Waiting availabilities expire
374         waitingEabCapabilityExpire();
375 
376         // Request availabilities again
377         RcsContactUceCapability capability = requestAvailability(sTestNumberUri);
378 
379         // Verify that return the availabilities from network instead of the EAB provider
380         verifyCapabilityResult(capability,
381                 sTestNumberUri,
382                 TEST_SERVICE_DESCRIPTION,
383                 TUPLE_BASIC_STATUS_OPEN,
384                 REQUEST_RESULT_FOUND,
385                 RcsContactUceCapability.SOURCE_TYPE_NETWORK,
386                 true,
387                 false,
388                 DUPLEX_MODE_RECEIVE_ONLY,
389                 DUPLEX_MODE_SEND_ONLY);
390 
391         // Verify the onCompleted is called
392         waitForResult(mCompleteQueue);
393     }
394 
requestAvailability(Uri contact)395     private RcsContactUceCapability requestAvailability(Uri contact) throws Exception {
396         // Request capabilities by calling the API requestCapabilities.
397         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
398         RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
399 
400         try {
401             ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
402                     uceAdapter,
403                     adapter -> adapter.requestAvailability(contact, Runnable::run,
404                             mCallback),
405                     ImsException.class,
406                     "android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE");
407         } catch (SecurityException e) {
408             fail("requestCapabilities should succeed with ACCESS_RCS_USER_CAPABILITY_EXCHANGE."
409                  + e);
410         } catch (ImsException e) {
411             fail("requestCapabilities failed " + e);
412         }
413 
414         // Verify that all the contact's capabilities are received
415         return waitForResult(mCapabilityQueue);
416     }
417 
requestCapabilities(List<Uri> contact)418     private RcsContactUceCapability requestCapabilities(List<Uri> contact) throws Exception {
419         // Request capabilities by calling the API requestCapabilities.
420         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
421         RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
422 
423         try {
424             ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
425                     uceAdapter,
426                     adapter -> adapter.requestCapabilities(contact, Runnable::run, mCallback),
427                     ImsException.class,
428                     "android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE");
429         } catch (SecurityException e) {
430             fail("requestCapabilities should succeed with ACCESS_RCS_USER_CAPABILITY_EXCHANGE."
431                  + e);
432         } catch (ImsException e) {
433             fail("requestCapabilities failed " + e);
434         }
435 
436         // Verify that all the contact's capabilities are received
437         return waitForResult(mCapabilityQueue);
438     }
439 
overrideCarrierConfig()440     private static void overrideCarrierConfig() throws Exception {
441         ImsManager imsManager = getContext().getSystemService(ImsManager.class);
442         RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
443         assertNotNull("UCE adapter should not be null!", uceAdapter);
444 
445 
446         // Trigger carrier config changed
447         PersistableBundle bundle = new PersistableBundle();
448         bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL, true);
449         bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL,
450                 true);
451         overrideCarrierConfig(bundle);
452     }
453 
fakeNetworkResult(String pidfXml)454     private void fakeNetworkResult(String pidfXml) {
455         TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
456                 .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
457 
458         ArrayList<String> pidfXmlList = new ArrayList<>(1);
459         pidfXmlList.add(pidfXml);
460 
461         // Setup the network response is 200 OK and notify capabilities update
462         int networkRespCode = 200;
463         String networkRespReason = "OK";
464         capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
465             cb.onNetworkResponse(networkRespCode, networkRespReason);
466             cb.onNotifyCapabilitiesUpdate(pidfXmlList);
467             cb.onTerminated("", 0L);
468         });
469     }
470 
getPidfXmlData(Uri contact, String serviceDescription, String serviceStatus, boolean audioSupported, boolean videoSupported, String supportedDuplexMode, String unSupportedDuplexMode)471     private String getPidfXmlData(Uri contact,
472             String serviceDescription,
473             String serviceStatus,
474             boolean audioSupported,
475             boolean videoSupported,
476             String supportedDuplexMode,
477             String unSupportedDuplexMode) {
478         GregorianCalendar date = new GregorianCalendar();
479         String timeStamp = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX")
480                 .format(date.getTime());
481 
482         String pidfBuilder = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
483                 + "<presence entity=\"" + contact + "\""
484                 + " xmlns=\"urn:ietf:params:xml:ns:pidf\""
485                 + " xmlns:op=\"urn:oma:xml:prs:pidf:oma-pres\""
486                 + " xmlns:caps=\"urn:ietf:params:xml:ns:pidf:caps\">"
487                 + "<tuple id=\"tid0\">"
488                 // status
489                 + "<status><basic>" + serviceStatus + "</basic></status>"
490                 // timestamp
491                 + "<timestamp>" + timeStamp + "</timestamp>"
492 
493                 // service description
494                 + "<op:service-description>"
495                 + "<op:service-id>service_id_01</op:service-id>"
496                 + "<op:version>1.0</op:version>"
497                 + "<op:description>" + serviceDescription + "</op:description>"
498                 + "</op:service-description>"
499 
500                 // service capabilities
501                 + "<caps:servcaps>"
502                 // audio capabilities
503                 + "<caps:audio>" + audioSupported + "</caps:audio>"
504                 // video capabilities
505                 + "<caps:video>" + videoSupported + "</caps:video>"
506 
507                 // duplex mode
508                 + "<caps:duplex>"
509                 // support duplex mode
510                 + "<caps:supported>"
511                 + "<caps:" + supportedDuplexMode + "/>"
512                 + "</caps:supported>"
513 
514                 // unsupported duplex mode
515                 + "<caps:notsupported>"
516                 + "<caps:" + unSupportedDuplexMode + "/>"
517                 + "</caps:notsupported>"
518                 + "</caps:duplex>"
519                 + "</caps:servcaps>"
520                 + "<contact>" + contact + "</contact>"
521                 + "</tuple>"
522                 + "</presence>";
523         return pidfBuilder;
524     }
525 
verifyCapabilityResult(RcsContactUceCapability resultCapability, Uri expectedUri, String serviceDescription, String serviceStatus, int expectedResult, int expectedSourceType, boolean expectedAudioSupported, boolean expectedVideoSupported, String expectedSupportedDuplexMode, String expectedUnSupportedDuplexMode)526     private void verifyCapabilityResult(RcsContactUceCapability resultCapability,
527             Uri expectedUri,
528             String serviceDescription,
529             String serviceStatus,
530             int expectedResult,
531             int expectedSourceType,
532             boolean expectedAudioSupported,
533             boolean expectedVideoSupported,
534             String expectedSupportedDuplexMode,
535             String expectedUnSupportedDuplexMode) {
536         // Verify the contact URI
537         assertEquals(expectedUri, resultCapability.getContactUri());
538 
539         // Verify the source type is the network type.
540         assertEquals(expectedSourceType, resultCapability.getSourceType());
541 
542         // Verify the request result is expected.
543         final int requestResult = resultCapability.getRequestResult();
544         assertEquals(requestResult, expectedResult);
545 
546         // Verify the mechanism is presence
547         assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_PRESENCE,
548                 resultCapability.getCapabilityMechanism());
549 
550         RcsContactPresenceTuple presenceTuple =
551                 resultCapability.getCapabilityTuple("service_id_01");
552         assertNotNull("Contact Presence tuple should not be null!", presenceTuple);
553 
554         RcsContactPresenceTuple.ServiceCapabilities capabilities =
555                 presenceTuple.getServiceCapabilities();
556         assertNotNull("Service capabilities should not be null!", capabilities);
557 
558         // Verify timestamp
559         assertNotNull("Timestamp should not be null!", presenceTuple.getTime());
560 
561         // Verify service id
562         assertEquals("service_id_01", presenceTuple.getServiceId());
563 
564         // Verify service status
565         assertEquals(serviceStatus, presenceTuple.getStatus());
566 
567         // Verify service description
568         assertEquals(serviceDescription, presenceTuple.getServiceDescription());
569 
570         // Verify audio
571         assertEquals(expectedAudioSupported, capabilities.isAudioCapable());
572 
573         // Verify video
574         assertEquals(expectedVideoSupported, capabilities.isVideoCapable());
575 
576         // Verify Supported Duplex Mode
577         assertEquals(expectedSupportedDuplexMode, capabilities.getSupportedDuplexModes().get(0));
578 
579         // Verify UnSupported Duplex Mode
580         assertEquals(expectedUnSupportedDuplexMode,
581                 capabilities.getUnsupportedDuplexModes().get(0));
582     }
583 
waitForResult(BlockingQueue<T> queue)584     private <T> T waitForResult(BlockingQueue<T> queue) throws Exception {
585         return queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
586     }
587 
getContext()588     private static Context getContext() {
589         return InstrumentationRegistry.getInstrumentation().getContext();
590     }
591 
connectTestImsService()592     private static void connectTestImsService() throws Exception {
593         assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
594                 .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
595                 .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
596                 .build()));
597 
598         // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
599         // Framework did not call it.
600         assertTrue("Did not receive createRcsFeature", sServiceConnector.getCarrierService()
601                 .waitForLatchCountdown(TestImsService.LATCH_CREATE_RCS));
602         assertTrue("Did not receive RcsFeature#onReady", sServiceConnector.getCarrierService()
603                 .waitForLatchCountdown(TestImsService.LATCH_RCS_READY));
604         // Make sure the RcsFeature was created in the test service.
605         assertNotNull("Device ImsService created, but TestDeviceImsService#createRcsFeature was not"
606                 + "called!", sServiceConnector.getCarrierService().getRcsFeature());
607         assertTrue("Did not receive RcsFeature#setCapabilityExchangeEventListener",
608                 sServiceConnector.getCarrierService().waitForLatchCountdown(
609                         TestImsService.LATCH_UCE_LISTENER_SET));
610         int serviceSlot = sServiceConnector.getCarrierService().getRcsFeature().getSlotIndex();
611         assertEquals("The slot specified for the test (" + sTestSlot + ") does not match the "
612                         + "assigned slot (" + serviceSlot + "+ for the associated RcsFeature",
613                 sTestSlot, serviceSlot);
614     }
615 
overrideCarrierConfig(PersistableBundle bundle)616     private static void overrideCarrierConfig(PersistableBundle bundle) throws Exception {
617         CarrierConfigManager carrierConfigManager = InstrumentationRegistry.getInstrumentation()
618                 .getContext().getSystemService(CarrierConfigManager.class);
619         sReceiver.clearQueue();
620         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(carrierConfigManager,
621                 (m) -> m.overrideConfig(sTestSub, bundle));
622         sReceiver.waitForCarrierConfigChanged();
623     }
624 
removeTestContactFromEab()625     private static void removeTestContactFromEab() {
626         try {
627             sServiceConnector.removeEabContacts(sTestSlot, sTestPhoneNumber);
628         } catch (Exception e) {
629             Log.w("RcsUceAdapterTest", "Cannot remove test contacts from eab database: " + e);
630         }
631     }
632 
formatNumber(Context context, String number)633     private static String formatNumber(Context context, String number) {
634         TelephonyManager manager = context.getSystemService(TelephonyManager.class);
635         String simCountryIso = manager.getSimCountryIso();
636         if (simCountryIso != null) {
637             simCountryIso = simCountryIso.toUpperCase();
638             PhoneNumberUtil util = PhoneNumberUtil.getInstance();
639             try {
640                 Phonenumber.PhoneNumber phoneNumber = util.parse(number, simCountryIso);
641                 return util.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
642             } catch (NumberParseException e) {
643                 Log.w(TAG, "formatNumber: could not format " + number + ", error: " + e);
644             }
645         }
646         return number;
647     }
648 
getEabCapabilities(String phoneNum)649     private String getEabCapabilities(String phoneNum) throws Exception {
650         StringBuilder cmdBuilder = new StringBuilder();
651         cmdBuilder.append(COMMAND_BASE).append(COMMAND_GET_EAB_CONTACT)
652                 .append(" ").append(phoneNum);
653         return TelephonyUtils.executeShellCommand(InstrumentationRegistry.getInstrumentation(),
654                 cmdBuilder.toString());
655     }
656 
setProvisioningIntValue(int key, int value)657     private void setProvisioningIntValue(int key, int value) {
658         final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
659         try {
660             automan.adoptShellPermissionIdentity();
661             ProvisioningManager provisioningManager =
662                     ProvisioningManager.createForSubscriptionId(sTestSub);
663             provisioningManager.setProvisioningIntValue(key, value);
664         } finally {
665             automan.dropShellPermissionIdentity();
666         }
667     }
668 
waitingEabCapabilityExpire()669     private void waitingEabCapabilityExpire() throws Exception {
670         int retryTimes = POLLING_RETRY_TIMES;
671         long expirationTime;
672         do {
673             String capabilities = getEabCapabilities(formatNumber(getContext(), sTestPhoneNumber));
674             String[] capabilityInfo = capabilities.split(",");
675             assertTrue(capabilityInfo.length > 4);
676             Thread.sleep(WAITING_IN_MILLI_SEC);
677             expirationTime = Long.parseLong(capabilityInfo[2]);
678             retryTimes--;
679         } while (retryTimes > 0 && Instant.now().getEpochSecond() < expirationTime);
680     }
681 }
682