1 /*
2  * Copyright (C) 2019 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 android.app.Instrumentation;
20 import android.app.role.RoleManager;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.os.IBinder;
26 import android.telephony.cts.TelephonyUtils;
27 import android.telephony.cts.externalimsservice.ITestExternalImsService;
28 import android.telephony.cts.externalimsservice.TestExternalImsService;
29 import android.telephony.ims.feature.ImsFeature;
30 import android.telephony.ims.stub.ImsFeatureConfiguration;
31 import android.text.TextUtils;
32 import android.util.Log;
33 import android.util.SparseArray;
34 
35 import androidx.test.platform.app.InstrumentationRegistry;
36 
37 import com.android.compatibility.common.util.ShellIdentityUtils;
38 
39 import java.util.List;
40 import java.util.concurrent.CountDownLatch;
41 import java.util.concurrent.LinkedBlockingQueue;
42 import java.util.concurrent.TimeUnit;
43 
44 /**
45  * Connects The CTS test ImsService to the Telephony Framework.
46  */
47 class ImsServiceConnector {
48 
49     private static final String TAG = "CtsImsServiceConnector";
50 
51     private static final String PACKAGE_NAME =
52             InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName();
53     private static final String EXTERNAL_PACKAGE_NAME =
54             TestExternalImsService.class.getPackage().getName();
55 
56     private static final String COMMAND_BASE = "cmd phone ";
57     private static final String COMMAND_SET_IMS_SERVICE = "ims set-ims-service ";
58     private static final String COMMAND_GET_IMS_SERVICE = "ims get-ims-service ";
59     private static final String COMMAND_CLEAR_SERVICE_OVERRIDE = "ims clear-ims-service-override";
60     private static final String COMMAND_CARRIER_SERVICE_IDENTIFIER = "-c ";
61     private static final String COMMAND_DEVICE_SERVICE_IDENTIFIER = "-d ";
62     private static final String COMMAND_SLOT_IDENTIFIER = "-s ";
63     private static final String COMMAND_FEATURE_IDENTIFIER = "-f ";
64     private static final String COMMAND_ENABLE_IMS = "ims enable ";
65     private static final String COMMAND_DISABLE_IMS = "ims disable ";
66     private static final String COMMAND_SET_DEVICE_SINGLE_REGISTRATION_ENABLED =
67             "src set-device-enabled ";
68     private static final String COMMAND_GET_DEVICE_SINGLE_REGISTRATION_ENABLED =
69             "src get-device-enabled";
70     private static final String COMMAND_SET_CARRIER_SINGLE_REGISTRATION_ENABLED =
71             "src set-carrier-enabled ";
72     private static final String COMMAND_GET_CARRIER_SINGLE_REGISTRATION_ENABLED =
73             "src get-carrier-enabled";
74     private static final String COMMAND_REMOVE_EAB_CONTACT = "uce remove-eab-contact ";
75     private static final String COMMAND_GET_UCE_ENABLED = "uce get-device-enabled";
76     private static final String COMMAND_SET_UCE_ENABLED = "uce set-device-enabled ";
77     private static final String COMMAND_REMOVE_UCE_REQUEST_DISALLOWED_STATUS =
78             "uce remove-request-disallowed-status ";
79     private static final String COMMAND_SET_CAPABILITY_REQUEST_TIMEOUT =
80             "uce set-capabilities-request-timeout ";
81     private static final String COMMAND_SET_TEST_MODE_ENABLED = "src set-test-enabled ";
82     private static final String COMMAND_SET_D2D_ENABLED = "d2d set-device-support ";
83 
84     private class TestCarrierServiceConnection implements ServiceConnection {
85 
86         private final CountDownLatch mLatch;
87 
TestCarrierServiceConnection(CountDownLatch latch)88         TestCarrierServiceConnection(CountDownLatch latch) {
89             mLatch = latch;
90         }
91 
92         @Override
onServiceConnected(ComponentName name, IBinder service)93         public void onServiceConnected(ComponentName name, IBinder service) {
94             mCarrierService = ((TestImsService.LocalBinder) service).getService();
95             mLatch.countDown();
96         }
97 
98         @Override
onServiceDisconnected(ComponentName name)99         public void onServiceDisconnected(ComponentName name) {
100             mCarrierService = null;
101         }
102     }
103 
104     private class TestDeviceServiceConnection implements ServiceConnection {
105 
106         private final CountDownLatch mLatch;
107 
TestDeviceServiceConnection(CountDownLatch latch)108         TestDeviceServiceConnection(CountDownLatch latch) {
109             mLatch = latch;
110         }
111 
112         @Override
onServiceConnected(ComponentName name, IBinder service)113         public void onServiceConnected(ComponentName name, IBinder service) {
114             mExternalService = ITestExternalImsService.Stub.asInterface(service);
115             mLatch.countDown();
116         }
117 
118         @Override
onServiceDisconnected(ComponentName name)119         public void onServiceDisconnected(ComponentName name) {
120             mCarrierService = null;
121         }
122     }
123 
124     public class Connection {
125 
126         private static final int CONNECTION_TYPE_IMS_SERVICE_DEVICE = 1;
127         private static final int CONNECTION_TYPE_IMS_SERVICE_CARRIER = 2;
128         private static final int CONNECTION_TYPE_DEFAULT_SMS_APP = 3;
129 
130         private boolean mIsServiceOverridden = false;
131         private String mOrigMmTelServicePackage;
132         private String mOrigRcsServicePackage;
133         private String mOrigSmsPackage;
134         private int mConnectionType;
135         private int mSlotId;
136         private SparseArray<String> mFeatureTypeToPackageOverrideMap = new SparseArray<>(2);
Connection(int connectionType, int slotId)137         Connection(int connectionType, int slotId) {
138             mConnectionType = connectionType;
139             mSlotId = slotId;
140         }
141 
clearPackage()142         void clearPackage() throws Exception {
143             mIsServiceOverridden = true;
144             switch (mConnectionType) {
145                 case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
146                     setCarrierImsService("none");
147                     break;
148                 }
149                 case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
150                     setDeviceImsService("");
151                     break;
152                 }
153                 case CONNECTION_TYPE_DEFAULT_SMS_APP: {
154                     // We don't need to clear anything for default SMS app.
155                     break;
156                 }
157             }
158         }
159 
overrideService(ImsFeatureConfiguration config)160         boolean overrideService(ImsFeatureConfiguration config) throws Exception {
161             mIsServiceOverridden = true;
162             switch (mConnectionType) {
163                 case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
164                     return bindCarrierImsService(config, PACKAGE_NAME);
165                 }
166                 case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
167                     return bindDeviceImsService(config, EXTERNAL_PACKAGE_NAME);
168                 }
169                 case CONNECTION_TYPE_DEFAULT_SMS_APP: {
170                     return setDefaultSmsApp(PACKAGE_NAME);
171                 }
172             }
173             return false;
174         }
175 
restoreOriginalPackage()176         void restoreOriginalPackage() throws Exception {
177             if (!mIsServiceOverridden) {
178                 return;
179             }
180             mIsServiceOverridden = false;
181 
182             if (mOrigRcsServicePackage == null) {
183                 mOrigRcsServicePackage = "";
184             }
185 
186             if (mOrigMmTelServicePackage == null) {
187                 mOrigMmTelServicePackage = "";
188             }
189 
190             switch (mConnectionType) {
191                 case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
192                     clearCarrierImsServiceOverride();
193                     break;
194                 }
195                 case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
196                     setDeviceImsService(mOrigMmTelServicePackage, ImsFeature.FEATURE_MMTEL);
197                     setDeviceImsService(mOrigRcsServicePackage, ImsFeature.FEATURE_RCS);
198                     break;
199                 }
200                 case CONNECTION_TYPE_DEFAULT_SMS_APP: {
201                     setDefaultSmsApp(mOrigSmsPackage);
202                     break;
203                 }
204             }
205         }
206 
207         /**
208          * @return true if the configuration set here still exists in telephony or false if it was
209          * changed (due to something like a Phone process crash).
210          */
checkConfigurationExists()211         boolean checkConfigurationExists() throws Exception {
212             boolean result = true;
213             String mmTelPackage = mFeatureTypeToPackageOverrideMap.get(ImsFeature.FEATURE_MMTEL);
214             String rcsPackage = mFeatureTypeToPackageOverrideMap.get(ImsFeature.FEATURE_RCS);
215             switch (mConnectionType) {
216                 case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
217                     result &= isPackageTheSame(mmTelPackage, getMmTelCarrierService());
218                     result &= isPackageTheSame(rcsPackage, getRcsCarrierService());
219                     break;
220                 }
221                 case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
222                     result &= isPackageTheSame(mmTelPackage, getMmTelDeviceService());
223                     result &= isPackageTheSame(rcsPackage, getRcsDeviceService());
224                     break;
225                 }
226                 case CONNECTION_TYPE_DEFAULT_SMS_APP: {
227                     break;
228                 }
229             }
230             return result;
231         }
232 
isPackageTheSame(String pkgA, String pkgB)233         private boolean isPackageTheSame(String pkgA, String pkgB) {
234             if (TextUtils.isEmpty(pkgA) && TextUtils.isEmpty(pkgB)) {
235                 return true;
236             }
237             return TextUtils.equals(pkgA, pkgB);
238         }
239 
storeOriginalPackage()240         private void storeOriginalPackage() throws Exception {
241             switch (mConnectionType) {
242                 case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
243                     mOrigMmTelServicePackage = getMmTelCarrierService();
244                     mOrigRcsServicePackage = getRcsCarrierService();
245                     break;
246                 }
247                 case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
248                     mOrigMmTelServicePackage = getMmTelDeviceService();
249                     mOrigRcsServicePackage = getRcsDeviceService();
250                     break;
251                 }
252                 case CONNECTION_TYPE_DEFAULT_SMS_APP: {
253                     mOrigSmsPackage = getDefaultSmsApp();
254                     break;
255                 }
256             }
257         }
258 
setDeviceImsService(String packageName)259         private boolean setDeviceImsService(String packageName) throws Exception {
260             mFeatureTypeToPackageOverrideMap.put(ImsFeature.FEATURE_MMTEL, packageName);
261             mFeatureTypeToPackageOverrideMap.put(ImsFeature.FEATURE_RCS, packageName);
262             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
263                     constructSetImsServiceOverrideCommand(false, packageName, new int[] {
264                             ImsFeature.FEATURE_MMTEL, ImsFeature.FEATURE_RCS}));
265             if (ImsUtils.VDBG) {
266                 Log.d(TAG, "setDeviceMmTelImsService result: " + result);
267             }
268             return "true".equals(result);
269         }
270 
setCarrierImsService(String packageName)271         private boolean setCarrierImsService(String packageName) throws Exception {
272             mFeatureTypeToPackageOverrideMap.put(ImsFeature.FEATURE_MMTEL, packageName);
273             mFeatureTypeToPackageOverrideMap.put(ImsFeature.FEATURE_RCS, packageName);
274             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
275                     constructSetImsServiceOverrideCommand(true, packageName, new int[] {
276                             ImsFeature.FEATURE_EMERGENCY_MMTEL, ImsFeature.FEATURE_MMTEL,
277                             ImsFeature.FEATURE_RCS}));
278             if (ImsUtils.VDBG) {
279                 Log.d(TAG, "setCarrierMmTelImsService result: " + result);
280             }
281             return "true".equals(result);
282         }
283 
setDeviceImsService(String packageName, int featureType)284         private boolean setDeviceImsService(String packageName, int featureType) throws Exception {
285             mFeatureTypeToPackageOverrideMap.put(featureType, packageName);
286             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
287                     constructSetImsServiceOverrideCommand(false, packageName,
288                             new int[]{featureType}));
289             if (ImsUtils.VDBG) {
290                 Log.d(TAG, "setDeviceMmTelImsService result: " + result);
291             }
292             return "true".equals(result);
293         }
294 
setCarrierImsService(String packageName, int featureType)295         private boolean setCarrierImsService(String packageName, int featureType) throws Exception {
296             mFeatureTypeToPackageOverrideMap.put(featureType, packageName);
297             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
298                     constructSetImsServiceOverrideCommand(true, packageName,
299                             new int[]{featureType}));
300             if (ImsUtils.VDBG) {
301                 Log.d(TAG, "setCarrierMmTelImsService result: " + result);
302             }
303             return "true".equals(result);
304         }
305 
clearCarrierImsServiceOverride()306         private boolean clearCarrierImsServiceOverride() throws Exception {
307             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
308                     constructClearCarrierImsServiceOverrideCommand());
309             if (ImsUtils.VDBG) {
310                 Log.d(TAG, "clearCarrierImsServiceOverride result: " + result);
311             }
312             return "true".equals(result);
313         }
314 
setDefaultSmsApp(String packageName)315         private boolean setDefaultSmsApp(String packageName) throws Exception {
316             RoleManager roleManager = mInstrumentation.getContext()
317                     .getSystemService(RoleManager.class);
318             Boolean result;
319             LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
320             if (TextUtils.isEmpty(packageName)) {
321                 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(roleManager,
322                         (m) -> m.clearRoleHoldersAsUser(RoleManager.ROLE_SMS,
323                                 RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
324                                 android.os.Process.myUserHandle(),
325                                 // Run on calling binder thread.
326                                 Runnable::run, queue::offer));
327             } else {
328                 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(roleManager,
329                         (m) -> m.addRoleHolderAsUser(RoleManager.ROLE_SMS, packageName, 0,
330                                 android.os.Process.myUserHandle(),
331                                 // Run on calling binder thread.
332                                 Runnable::run, queue::offer));
333             }
334             result = queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
335             if (ImsUtils.VDBG) {
336                 Log.d(TAG, "setDefaultSmsApp result: " + result);
337             }
338             return result;
339         }
340 
getDefaultSmsApp()341         private String getDefaultSmsApp() throws Exception {
342             RoleManager roleManager = mInstrumentation.getContext()
343                     .getSystemService(RoleManager.class);
344             List<String> result = ShellIdentityUtils.invokeMethodWithShellPermissions(roleManager,
345                     (m) -> m.getRoleHolders(RoleManager.ROLE_SMS));
346             if (ImsUtils.VDBG) {
347                 Log.d(TAG, "getDefaultSmsApp result: " + result);
348             }
349             if (result.isEmpty()) {
350                 // No default SMS app.
351                 return null;
352             }
353             // There should only be one default sms app
354             return result.get(0);
355         }
356 
bindCarrierImsService(ImsFeatureConfiguration config, String packageName)357         private boolean bindCarrierImsService(ImsFeatureConfiguration config, String packageName)
358                 throws Exception {
359             getCarrierService().setFeatureConfig(config);
360             return setCarrierImsService(packageName) && getCarrierService().waitForLatchCountdown(
361                             TestImsService.LATCH_FEATURES_READY);
362         }
363 
bindDeviceImsService(ImsFeatureConfiguration config, String packageName)364         private boolean bindDeviceImsService(ImsFeatureConfiguration config, String packageName)
365                 throws Exception {
366             getExternalService().setFeatureConfig(config);
367             return setDeviceImsService(packageName) && getExternalService().waitForLatchCountdown(
368                     TestImsService.LATCH_FEATURES_READY);
369         }
370 
getMmTelCarrierService()371         private String getMmTelCarrierService() throws Exception {
372             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
373                     constructGetImsServiceCommand(true, ImsFeature.FEATURE_MMTEL));
374             if (ImsUtils.VDBG) {
375                 Log.d(TAG, "getMmTelCarrierService result: " + result);
376             }
377             return result;
378         }
379 
getRcsCarrierService()380         private String getRcsCarrierService() throws Exception {
381             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
382                     constructGetImsServiceCommand(true, ImsFeature.FEATURE_RCS));
383             if (ImsUtils.VDBG) {
384                 Log.d(TAG, "getRcsCarrierService result: " + result);
385             }
386             return result;
387         }
388 
getMmTelDeviceService()389         private String getMmTelDeviceService() throws Exception {
390             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
391                     constructGetImsServiceCommand(false, ImsFeature.FEATURE_MMTEL));
392             if (ImsUtils.VDBG) {
393                 Log.d(TAG, "getMmTelDeviceService result: " + result);
394             }
395             return result;
396         }
397 
getRcsDeviceService()398         private String getRcsDeviceService() throws Exception {
399             String result = TelephonyUtils.executeShellCommand(mInstrumentation,
400                     constructGetImsServiceCommand(false, ImsFeature.FEATURE_RCS));
401             if (ImsUtils.VDBG) {
402                 Log.d(TAG, "getRcsDeviceService result: " + result);
403             }
404             return result;
405         }
406 
constructSetImsServiceOverrideCommand(boolean isCarrierService, String packageName, int[] featureTypes)407         private String constructSetImsServiceOverrideCommand(boolean isCarrierService,
408                 String packageName, int[] featureTypes) {
409             return COMMAND_BASE + COMMAND_SET_IMS_SERVICE + COMMAND_SLOT_IDENTIFIER + mSlotId + " "
410                     + (isCarrierService
411                         ? COMMAND_CARRIER_SERVICE_IDENTIFIER : COMMAND_DEVICE_SERVICE_IDENTIFIER)
412                     + COMMAND_FEATURE_IDENTIFIER + getFeatureTypesString(featureTypes) + " "
413                     + packageName;
414         }
415 
constructGetImsServiceCommand(boolean isCarrierService, int featureType)416         private String constructGetImsServiceCommand(boolean isCarrierService, int featureType) {
417             return COMMAND_BASE + COMMAND_GET_IMS_SERVICE + COMMAND_SLOT_IDENTIFIER + mSlotId + " "
418                     + (isCarrierService
419                         ? COMMAND_CARRIER_SERVICE_IDENTIFIER : COMMAND_DEVICE_SERVICE_IDENTIFIER)
420                     + COMMAND_FEATURE_IDENTIFIER + featureType;
421         }
422 
constructClearCarrierImsServiceOverrideCommand()423         private String constructClearCarrierImsServiceOverrideCommand() {
424             return COMMAND_BASE + COMMAND_CLEAR_SERVICE_OVERRIDE + COMMAND_SLOT_IDENTIFIER
425                     + mSlotId;
426         }
427 
getFeatureTypesString(int[] featureTypes)428         private String getFeatureTypesString(int[] featureTypes) {
429             if (featureTypes.length == 0) return "";
430             StringBuilder builder = new StringBuilder();
431             builder.append(featureTypes[0]);
432             for (int i = 1; i < featureTypes.length; i++) {
433                 builder.append(",");
434                 builder.append(featureTypes[i]);
435             }
436             return builder.toString();
437         }
438     }
439 
440     private Instrumentation mInstrumentation;
441 
442     private TestImsService mCarrierService;
443     private TestCarrierServiceConnection mCarrierServiceConn;
444     private ITestExternalImsService mExternalService;
445     private TestDeviceServiceConnection mExternalServiceConn;
446 
447     private Connection mDeviceServiceConnection;
448     private Connection mCarrierServiceConnection;
449     private Connection mDefaultSmsAppConnection;
450 
ImsServiceConnector(Instrumentation instrumentation)451     ImsServiceConnector(Instrumentation instrumentation) {
452         mInstrumentation = instrumentation;
453     }
454 
clearAllActiveImsServices(int slotId)455     void clearAllActiveImsServices(int slotId) throws Exception {
456         mDeviceServiceConnection = new Connection(Connection.CONNECTION_TYPE_IMS_SERVICE_DEVICE,
457                 slotId);
458         mDeviceServiceConnection.storeOriginalPackage();
459         mDeviceServiceConnection.clearPackage();
460 
461         mCarrierServiceConnection = new Connection(Connection.CONNECTION_TYPE_IMS_SERVICE_CARRIER,
462                 slotId);
463         mCarrierServiceConnection.storeOriginalPackage();
464         mCarrierServiceConnection.clearPackage();
465 
466         mDefaultSmsAppConnection = new Connection(Connection.CONNECTION_TYPE_DEFAULT_SMS_APP,
467                 slotId);
468         mDefaultSmsAppConnection.storeOriginalPackage();
469         // No need to clear SMS App, only replace when necessary.
470     }
471 
472     /**
473      * Binds to the local implementation of ImsService but does not trigger ImsService bind from
474      * telephony to allow additional configuration steps.
475      * @return true if this request succeeded, false otherwise.
476      */
connectCarrierImsServiceLocally()477     boolean connectCarrierImsServiceLocally() {
478         if (!setupLocalCarrierImsService()) {
479             Log.w(TAG, "connectCarrierImsService: couldn't set up service.");
480             return false;
481         }
482         mCarrierService.resetState();
483         return true;
484     }
485 
486     /**
487      * Trigger the telephony framework to bind to the local ImsService implementation.
488      * @return true if this request succeeded, false otherwise.
489      */
triggerFrameworkConnectionToCarrierImsService( ImsFeatureConfiguration config)490     boolean triggerFrameworkConnectionToCarrierImsService(
491             ImsFeatureConfiguration config) throws Exception {
492         return mCarrierServiceConnection.overrideService(config);
493     }
494 
connectCarrierImsService(ImsFeatureConfiguration config)495     boolean connectCarrierImsService(ImsFeatureConfiguration config) throws Exception {
496         if (!connectCarrierImsServiceLocally()) return false;
497         return triggerFrameworkConnectionToCarrierImsService(config);
498     }
499 
connectDeviceImsService(ImsFeatureConfiguration config)500     boolean connectDeviceImsService(ImsFeatureConfiguration config) throws Exception {
501         if (!setupExternalImsService()) {
502             Log.w(TAG, "connectDeviceImsService: couldn't set up service.");
503             return false;
504         }
505         mExternalService.resetState();
506         return mDeviceServiceConnection.overrideService(config);
507     }
508 
setDefaultSmsApp()509     boolean setDefaultSmsApp() throws Exception {
510         return mDefaultSmsAppConnection.overrideService(null);
511     }
512 
restoreDefaultSmsApp()513     void restoreDefaultSmsApp() throws Exception {
514         mDefaultSmsAppConnection.restoreOriginalPackage();
515     }
516 
disconnectCarrierImsService()517     void disconnectCarrierImsService() throws Exception {
518         mCarrierServiceConnection.clearPackage();
519     }
520 
disconnectDeviceImsService()521     void disconnectDeviceImsService() throws Exception {
522         mDeviceServiceConnection.clearPackage();
523     }
524 
isCarrierServiceStillConfigured()525     boolean isCarrierServiceStillConfigured() throws Exception {
526         return mCarrierServiceConnection.checkConfigurationExists();
527     }
528 
setupLocalCarrierImsService()529     private boolean setupLocalCarrierImsService() {
530         if (mCarrierService != null) {
531             return true;
532         }
533         CountDownLatch latch = new CountDownLatch(1);
534         mCarrierServiceConn = new TestCarrierServiceConnection(latch);
535         mInstrumentation.getContext().bindService(new Intent(mInstrumentation.getContext(),
536                         TestImsService.class), mCarrierServiceConn, Context.BIND_AUTO_CREATE);
537         try {
538             return latch.await(5000, TimeUnit.MILLISECONDS);
539         } catch (InterruptedException e) {
540             return false;
541         }
542     }
543 
setupExternalImsService()544     private boolean setupExternalImsService() {
545         if (mExternalService != null) {
546             return true;
547         }
548         CountDownLatch latch = new CountDownLatch(1);
549         mExternalServiceConn = new TestDeviceServiceConnection(latch);
550         Intent deviceIntent = new Intent();
551         deviceIntent.setComponent(new ComponentName(EXTERNAL_PACKAGE_NAME,
552                 TestExternalImsService.class.getName()));
553         mInstrumentation.getContext().bindService(deviceIntent, mExternalServiceConn,
554                 Context.BIND_AUTO_CREATE);
555         try {
556             return latch.await(5000, TimeUnit.MILLISECONDS);
557         } catch (InterruptedException e) {
558             return false;
559         }
560     }
561 
562     // Detect and disconnect all active services.
disconnectServices()563     void disconnectServices() throws Exception {
564         // Remove local connection
565         if (mCarrierServiceConn != null) {
566             mInstrumentation.getContext().unbindService(mCarrierServiceConn);
567             mCarrierService = null;
568         }
569         if (mExternalServiceConn != null) {
570             mInstrumentation.getContext().unbindService(mExternalServiceConn);
571             mExternalService = null;
572         }
573         mDeviceServiceConnection.restoreOriginalPackage();
574         mCarrierServiceConnection.restoreOriginalPackage();
575         mDefaultSmsAppConnection.restoreOriginalPackage();
576 
577         // Remove any overrides for single registration state
578         setDeviceSingleRegistrationEnabled(null);
579     }
580 
enableImsService(int slot)581     void enableImsService(int slot) throws Exception {
582         TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE + COMMAND_ENABLE_IMS
583                 + COMMAND_SLOT_IDENTIFIER + slot);
584     }
585 
disableImsService(int slot)586     void disableImsService(int slot) throws Exception {
587         TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE + COMMAND_DISABLE_IMS
588                 + COMMAND_SLOT_IDENTIFIER + slot);
589     }
590 
setDeviceSingleRegistrationEnabled(Boolean enabled)591     void setDeviceSingleRegistrationEnabled(Boolean enabled) throws Exception {
592         TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE
593                 + COMMAND_SET_DEVICE_SINGLE_REGISTRATION_ENABLED
594                 // if "null" is sent, it will remove override
595                 + (enabled != null ? enabled : "null"));
596     }
597 
getDeviceSingleRegistrationEnabled()598     boolean getDeviceSingleRegistrationEnabled() throws Exception {
599         return Boolean.parseBoolean(TelephonyUtils.executeShellCommand(mInstrumentation,
600                 COMMAND_BASE + COMMAND_GET_DEVICE_SINGLE_REGISTRATION_ENABLED));
601     }
602 
getCarrierSingleRegistrationEnabled()603     boolean getCarrierSingleRegistrationEnabled() throws Exception {
604         return Boolean.parseBoolean(TelephonyUtils.executeShellCommand(mInstrumentation,
605                 COMMAND_BASE + COMMAND_GET_CARRIER_SINGLE_REGISTRATION_ENABLED));
606     }
607 
getDeviceUceEnabled()608     boolean getDeviceUceEnabled() throws Exception {
609         return Boolean.parseBoolean(TelephonyUtils.executeShellCommand(mInstrumentation,
610                 COMMAND_BASE + COMMAND_GET_UCE_ENABLED));
611     }
612 
setDeviceUceEnabled(boolean isEnabled)613     void setDeviceUceEnabled(boolean isEnabled) throws Exception {
614         TelephonyUtils.executeShellCommand(mInstrumentation,
615                 COMMAND_BASE + COMMAND_SET_UCE_ENABLED + isEnabled);
616     }
617 
removeEabContacts(int slotId, String phoneNum)618     void removeEabContacts(int slotId, String phoneNum) throws Exception {
619         StringBuilder cmdBuilder = new StringBuilder();
620         cmdBuilder.append(COMMAND_BASE).append(COMMAND_REMOVE_EAB_CONTACT)
621                 .append(COMMAND_SLOT_IDENTIFIER).append(slotId).append(" ").append(phoneNum);
622         TelephonyUtils.executeShellCommand(mInstrumentation, cmdBuilder.toString());
623     }
624 
getCarrierService()625     TestImsService getCarrierService() {
626         return mCarrierService;
627     }
628 
getExternalService()629     ITestExternalImsService getExternalService() {
630         return mExternalService;
631     }
632 
setSingleRegistrationTestModeEnabled(boolean enabled)633     void setSingleRegistrationTestModeEnabled(boolean enabled) throws Exception {
634         TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE
635                 + COMMAND_SET_TEST_MODE_ENABLED  + (enabled ? "true" : "false"));
636     }
637 
removeUceRequestDisallowedStatus(int slotId)638     void removeUceRequestDisallowedStatus(int slotId) throws Exception {
639         StringBuilder cmdBuilder = new StringBuilder();
640         cmdBuilder.append(COMMAND_BASE).append(COMMAND_REMOVE_UCE_REQUEST_DISALLOWED_STATUS)
641                 .append(COMMAND_SLOT_IDENTIFIER).append(slotId);
642         TelephonyUtils.executeShellCommand(mInstrumentation, cmdBuilder.toString());
643     }
644 
setCapabilitiesRequestTimeout(int slotId, long timeoutAfterMs)645     void setCapabilitiesRequestTimeout(int slotId, long timeoutAfterMs) throws Exception {
646         StringBuilder cmdBuilder = new StringBuilder();
647         cmdBuilder.append(COMMAND_BASE).append(COMMAND_SET_CAPABILITY_REQUEST_TIMEOUT)
648                 .append(COMMAND_SLOT_IDENTIFIER).append(slotId).append(" ").append(timeoutAfterMs);
649         TelephonyUtils.executeShellCommand(mInstrumentation, cmdBuilder.toString());
650     }
651 
setDeviceToDeviceCommunicationEnabled(boolean enabled)652     void setDeviceToDeviceCommunicationEnabled(boolean enabled) throws Exception {
653         TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE
654                 + COMMAND_SET_D2D_ENABLED  + (enabled ? "true" : "default"));
655     }
656 }
657