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