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