• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.telephony.ims.cts;
18 
19 import static junit.framework.Assert.assertNotNull;
20 import static junit.framework.Assert.assertTrue;
21 
22 import static org.junit.Assert.assertEquals;
23 
24 import android.app.Instrumentation;
25 import android.app.UiAutomation;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.content.pm.PackageManager;
31 import android.os.Bundle;
32 import android.os.PersistableBundle;
33 import android.telecom.Call;
34 import android.telephony.CarrierConfigManager;
35 import android.telephony.SubscriptionManager;
36 import android.telephony.cts.InCallServiceStateValidator;
37 import android.telephony.cts.InCallServiceStateValidator.InCallServiceCallbacks;
38 import android.telephony.cts.util.TelephonyUtils;
39 import android.telephony.ims.feature.ImsFeature;
40 import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities;
41 import android.telephony.ims.stub.ImsFeatureConfiguration;
42 import android.telephony.ims.stub.ImsRegistrationImplBase;
43 import android.util.Log;
44 
45 import androidx.test.platform.app.InstrumentationRegistry;
46 
47 import com.android.compatibility.common.util.ShellIdentityUtils;
48 
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Objects;
52 import java.util.concurrent.ConcurrentHashMap;
53 import java.util.concurrent.CountDownLatch;
54 import java.util.concurrent.TimeUnit;
55 
56 /** Base class for ImsCall test. */
57 public class ImsCallingBase {
58 
59     protected static ImsServiceConnector sServiceConnector;
60 
61     private static final String LOG_TAG = "ImsCallingBase";
62 
63     protected static final String PACKAGE = "android.telephony.ims.cts";
64     protected static final String PACKAGE_CTS_DIALER = "android.telephony.cts";
65     protected static final String COMMAND_SET_DEFAULT_DIALER = "telecom set-default-dialer ";
66     protected static final String COMMAND_GET_DEFAULT_DIALER = "telecom get-default-dialer";
67 
68     // The timeout to wait in current state in milliseconds
69     protected static final int WAIT_IN_CURRENT_STATE = 100;
70     // The timeout to wait in current state after conference call merge failed in milliseconds
71     protected static final int WAIT_IN_CURRENT_STATE_MERGE_FAILED = 500;
72 
73     public static final int WAIT_FOR_SERVICE_TO_UNBOUND = 40000;
74     public static final int WAIT_FOR_CONDITION = 3000;
75     public static final int WAIT_FOR_CALL_STATE = 10000;
76     public static final int WAIT_FOR_CALL_STATE_ACTIVE = 15000;
77     public static final int LATCH_INCALL_SERVICE_BOUND = 1;
78     public static final int LATCH_INCALL_SERVICE_UNBOUND = 2;
79     public static final int LATCH_IS_ON_CALL_ADDED = 3;
80     public static final int LATCH_IS_ON_CALL_REMOVED = 4;
81     public static final int LATCH_IS_CALL_DIALING = 5;
82     public static final int LATCH_IS_CALL_ACTIVE = 6;
83     public static final int LATCH_IS_CALL_DISCONNECTING = 7;
84     public static final int LATCH_IS_CALL_DISCONNECTED = 8;
85     public static final int LATCH_IS_CALL_RINGING = 9;
86     public static final int LATCH_IS_CALL_HOLDING = 10;
87     public static final int LATCH_IS_ON_CALL_REMOTELY_HELD = 11;
88     public static final int LATCH_IS_ON_CALL_REMOTELY_UNHELD = 12;
89     public static final int LATCH_IS_ON_CHILDREN_CHANGED = 13;
90     public static final int LATCH_IS_ON_MERGE_START = 14;
91     public static final int LATCH_IS_ON_MERGE_COMPLETE = 15;
92     public static final int LATCH_IS_ON_CONFERENCE_CALL_ADDED = 16;
93     public static final int LATCH_MAX = 17;
94     public static final int TEST_RTP_THRESHOLD_PACKET_LOSS_RATE = 47;
95     public static final int TEST_RTP_THRESHOLD_JITTER_MILLIS = 150;
96     public static final long TEST_RTP_THRESHOLD_INACTIVITY_TIME_MILLIS = 3000;
97 
98     protected static boolean sIsBound = false;
99     protected static int sCounter = 5553639;
100     protected static int sTestSlot = 0;
101     protected static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
102     protected static long sPreviousOptInStatus = 0;
103     protected static long sPreviousEn4GMode = 0;
104     protected static String sPreviousDefaultDialer;
105 
106     private static CarrierConfigReceiver sReceiver;
107     private static SubscriptionManager sSubscriptionManager;
108 
109     protected int mParticipantCount = 0;
110     protected static final Object mLock = new Object();
111     protected InCallServiceCallbacks mServiceCallBack;
112     protected Context mContext;
113     protected ConcurrentHashMap<String, Call> mCalls = new ConcurrentHashMap<String, Call>();
114     protected String mCurrentCallId = null;
115 
116     protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX];
117 
initializeLatches()118     protected static void initializeLatches() {
119         synchronized (mLock) {
120             for (int i = 0; i < LATCH_MAX; i++) {
121                 sLatches[i] = new CountDownLatch(1);
122             }
123         }
124     }
125 
overrideLatchCount(int latchIndex, int count)126     protected static void overrideLatchCount(int latchIndex, int count) {
127         synchronized (mLock) {
128             sLatches[latchIndex] = new CountDownLatch(count);
129         }
130     }
131 
132 
callingTestLatchCountdown(int latchIndex, int waitMs)133     public boolean callingTestLatchCountdown(int latchIndex, int waitMs) {
134         boolean complete = false;
135         try {
136             CountDownLatch latch;
137             synchronized (mLock) {
138                 latch = sLatches[latchIndex];
139             }
140             complete = latch.await(waitMs, TimeUnit.MILLISECONDS);
141         } catch (InterruptedException e) {
142             // complete == false
143         }
144         synchronized (mLock) {
145             sLatches[latchIndex] = new CountDownLatch(1);
146         }
147         return complete;
148     }
149 
countDownLatch(int latchIndex)150     public void countDownLatch(int latchIndex) {
151         synchronized (mLock) {
152             sLatches[latchIndex].countDown();
153         }
154     }
155 
156     protected abstract static class BaseReceiver extends BroadcastReceiver {
157         protected CountDownLatch mLatch = new CountDownLatch(1);
158 
clearQueue()159         void clearQueue() {
160             mLatch = new CountDownLatch(1);
161         }
162 
waitForChanged()163         void waitForChanged() throws Exception {
164             mLatch.await(5000, TimeUnit.MILLISECONDS);
165         }
166     }
167 
168     protected static class CarrierConfigReceiver extends BaseReceiver {
169         private final int mSubId;
170 
CarrierConfigReceiver(int subId)171         CarrierConfigReceiver(int subId) {
172             mSubId = subId;
173         }
174 
175         @Override
onReceive(Context context, Intent intent)176         public void onReceive(Context context, Intent intent) {
177             if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
178                 int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1);
179                 if (mSubId == subId) {
180                     mLatch.countDown();
181                 }
182             }
183         }
184     }
185 
186     public interface Condition {
expected()187         Object expected();
actual()188         Object actual();
189     }
190 
sleep(long ms)191     protected void sleep(long ms) {
192         try {
193             Thread.sleep(ms);
194         } catch (Exception e) {
195             Log.d(LOG_TAG, "InterruptedException");
196         }
197     }
198 
waitUntilConditionIsTrueOrTimeout( Condition condition, long timeout, String description)199     protected void waitUntilConditionIsTrueOrTimeout(
200             Condition condition, long timeout, String description) {
201         final long start = System.currentTimeMillis();
202         while (!Objects.equals(condition.expected(), condition.actual())
203                 && System.currentTimeMillis() - start < timeout) {
204             sleep(50);
205         }
206         assertEquals(description, condition.expected(), condition.actual());
207     }
208 
beforeAllTestsBase()209     public static void beforeAllTestsBase() throws Exception {
210         sServiceConnector = new ImsServiceConnector(InstrumentationRegistry.getInstrumentation());
211         // Remove all live ImsServices until after these tests are done
212         sServiceConnector.clearAllActiveImsServices(sTestSlot);
213 
214         sReceiver = new CarrierConfigReceiver(sTestSub);
215         IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
216         // ACTION_CARRIER_CONFIG_CHANGED is sticky, so we will get a callback right away.
217         InstrumentationRegistry.getInstrumentation()
218                 .getContext()
219                 .registerReceiver(sReceiver, filter);
220 
221         UiAutomation ui = InstrumentationRegistry.getInstrumentation().getUiAutomation();
222         try {
223             ui.adoptShellPermissionIdentity();
224             // Get the default dialer and save it to restore after test ends.
225             sPreviousDefaultDialer = getDefaultDialer(InstrumentationRegistry.getInstrumentation());
226             // Set dialer as "android.telephony.cts"
227             setDefaultDialer(InstrumentationRegistry.getInstrumentation(), PACKAGE_CTS_DIALER);
228 
229             sSubscriptionManager =
230                     InstrumentationRegistry.getInstrumentation()
231                             .getContext()
232                             .getSystemService(SubscriptionManager.class);
233             // Get the default Subscription values and save it to restore after test ends.
234             sPreviousOptInStatus =
235                     sSubscriptionManager.getLongSubscriptionProperty(
236                             sTestSub, SubscriptionManager.VOIMS_OPT_IN_STATUS, 0, getContext());
237             sPreviousEn4GMode =
238                     sSubscriptionManager.getLongSubscriptionProperty(
239                             sTestSub,
240                             SubscriptionManager.ENHANCED_4G_MODE_ENABLED,
241                             0,
242                             getContext());
243             // Set the new Sunbscription values
244             sSubscriptionManager.setSubscriptionProperty(
245                     sTestSub, SubscriptionManager.VOIMS_OPT_IN_STATUS, String.valueOf(1));
246             sSubscriptionManager.setSubscriptionProperty(
247                     sTestSub, SubscriptionManager.ENHANCED_4G_MODE_ENABLED, String.valueOf(1));
248 
249             // Override the carrier configurartions
250             CarrierConfigManager configurationManager =
251                     InstrumentationRegistry.getInstrumentation()
252                             .getContext()
253                             .getSystemService(CarrierConfigManager.class);
254             PersistableBundle bundle = new PersistableBundle(1);
255             bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL, true);
256             bundle.putBoolean(CarrierConfigManager.KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL, true);
257             bundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, false);
258             bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
259             bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false);
260 
261             sReceiver.clearQueue();
262             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
263                     configurationManager, (m) -> m.overrideConfig(sTestSub, bundle));
264         } finally {
265             ui.dropShellPermissionIdentity();
266         }
267         sReceiver.waitForChanged();
268     }
269 
afterAllTestsBase()270     public static void afterAllTestsBase() throws Exception {
271         UiAutomation ui = InstrumentationRegistry.getInstrumentation().getUiAutomation();
272         try {
273             ui.adoptShellPermissionIdentity();
274             // Set the default Sunbscription values.
275             sSubscriptionManager.setSubscriptionProperty(
276                     sTestSub,
277                     SubscriptionManager.VOIMS_OPT_IN_STATUS,
278                     String.valueOf(sPreviousOptInStatus));
279             sSubscriptionManager.setSubscriptionProperty(
280                     sTestSub,
281                     SubscriptionManager.ENHANCED_4G_MODE_ENABLED,
282                     String.valueOf(sPreviousEn4GMode));
283             // Set default dialer
284             setDefaultDialer(InstrumentationRegistry.getInstrumentation(), sPreviousDefaultDialer);
285 
286             // Restore all ImsService configurations that existed before the test.
287             if (sServiceConnector != null && sIsBound) {
288                 sServiceConnector.disconnectServices();
289                 sIsBound = false;
290             }
291             sServiceConnector = null;
292             overrideCarrierConfig(null);
293 
294             if (sReceiver != null) {
295                 InstrumentationRegistry.getInstrumentation()
296                         .getContext()
297                         .unregisterReceiver(sReceiver);
298                 sReceiver = null;
299             }
300         } finally {
301             ui.dropShellPermissionIdentity();
302         }
303     }
304 
bindImsService()305     public void bindImsService() throws Exception {
306         bindImsService(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
307     }
308 
bindImsService(int radioTech)309     public void bindImsService(int radioTech) throws Exception {
310         MmTelCapabilities capabilities =
311                 new MmTelCapabilities(MmTelCapabilities.CAPABILITY_TYPE_VOICE);
312         // Set Registered and VoLTE capable
313         bindImsServiceForCapabilities(radioTech, capabilities);
314     }
315 
bindImsServiceForCapabilities(int radioTech, MmTelCapabilities capabilities)316     public void bindImsServiceForCapabilities(int radioTech, MmTelCapabilities capabilities)
317             throws Exception {
318         // Connect to the ImsService with the MmTel feature.
319         assertTrue(
320                 sServiceConnector.connectCarrierImsService(
321                         new ImsFeatureConfiguration.Builder()
322                                 .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
323                                 .addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
324                                 .build()));
325         sIsBound = true;
326         // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
327         // Framework did not call it.
328         sServiceConnector
329                 .getCarrierService()
330                 .waitForLatchCountdown(TestImsService.LATCH_CREATE_MMTEL);
331         assertNotNull(
332                 "ImsService created, but ImsService#createMmTelFeature was not called!",
333                 sServiceConnector.getCarrierService().getMmTelFeature());
334 
335         sServiceConnector
336                 .getCarrierService()
337                 .waitForLatchCountdown(TestImsService.LATCH_MMTEL_CAP_SET);
338 
339         // Set Registered with given capabilities
340         sServiceConnector
341                 .getCarrierService()
342                 .getImsService()
343                 .getRegistrationForSubscription(sTestSlot, sTestSub)
344                 .onRegistered(radioTech);
345         sServiceConnector.getCarrierService().getMmTelFeature().setCapabilities(capabilities);
346         sServiceConnector
347                 .getCarrierService()
348                 .getMmTelFeature()
349                 .notifyCapabilitiesStatusChanged(capabilities);
350 
351         // Wait a second for the notifyCapabilitiesStatusChanged indication to be processed on the
352         // main telephony thread - currently no better way of knowing that telephony has processed
353         // this command. SmsManager#isImsSmsSupported() is @hide and must be updated to use new API.
354         Thread.sleep(3000);
355     }
356 
waitForUnboundService()357     public void waitForUnboundService() {
358         waitUntilConditionIsTrueOrTimeout(
359                 new Condition() {
360                     @Override
361                     public Object expected() {
362                         return true;
363                     }
364 
365                     @Override
366                     public Object actual() {
367                         InCallServiceStateValidator inCallService = mServiceCallBack.getService();
368                         return (inCallService.isServiceUnBound()) ? true : false;
369                     }
370                 },
371                 WAIT_FOR_SERVICE_TO_UNBOUND,
372                 "Service Unbound");
373     }
374 
isCallActive(Call call, TestImsCallSessionImpl callsession)375     public void isCallActive(Call call, TestImsCallSessionImpl callsession) {
376         if (call.getDetails().getState() != Call.STATE_ACTIVE) {
377             assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_ACTIVE, WAIT_FOR_CALL_STATE));
378         }
379         assertNotNull("Unable to get callSession, its null", callsession);
380 
381         waitUntilConditionIsTrueOrTimeout(
382                 new Condition() {
383                     @Override
384                     public Object expected() {
385                         return true;
386                     }
387 
388                     @Override
389                     public Object actual() {
390                         return (callsession.isInCall()
391                                         && call.getDetails().getState() == Call.STATE_ACTIVE)
392                                 ? true
393                                 : false;
394                     }
395                 },
396                 WAIT_FOR_CONDITION,
397                 "Call Active");
398     }
399 
isCallDisconnected(Call call, TestImsCallSessionImpl callsession)400     public void isCallDisconnected(Call call, TestImsCallSessionImpl callsession) {
401         assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_DISCONNECTED, WAIT_FOR_CALL_STATE));
402         assertNotNull("Unable to get callSession, its null", callsession);
403 
404         waitUntilConditionIsTrueOrTimeout(
405                 new Condition() {
406                     @Override
407                     public Object expected() {
408                         return true;
409                     }
410 
411                     @Override
412                     public Object actual() {
413                         return (callsession.isInTerminated()
414                                         && call.getDetails().getState() == Call.STATE_DISCONNECTED)
415                                 ? true
416                                 : false;
417                     }
418                 }, WAIT_FOR_CONDITION,
419                 "session " + callsession.getState() + ", call "
420                         + call.getDetails().getState() + ", Call Disconnected");
421     }
422 
isCallHolding(Call call, TestImsCallSessionImpl callsession)423     public void isCallHolding(Call call, TestImsCallSessionImpl callsession) {
424         assertTrue(callingTestLatchCountdown(LATCH_IS_CALL_HOLDING, WAIT_FOR_CALL_STATE));
425         assertNotNull("Unable to get callSession, its null", callsession);
426         waitUntilConditionIsTrueOrTimeout(
427                 new Condition() {
428                     @Override
429                     public Object expected() {
430                         return true;
431                     }
432 
433                     @Override
434                     public Object actual() {
435                         return (callsession.isSessionOnHold()
436                                 && call.getDetails().getState() == Call.STATE_HOLDING) ? true
437                                 : false;
438                     }
439                 }, WAIT_FOR_CONDITION, "Call Holding");
440     }
441 
setCallID(String callid)442     protected void setCallID(String callid) {
443         assertNotNull("Call Id is set to null", callid);
444         mCurrentCallId = callid;
445     }
446 
addCall(Call call)447     public void addCall(Call call) {
448         String callid = getCallId(call);
449         setCallID(callid);
450         synchronized (mCalls) {
451             mCalls.put(callid, call);
452         }
453     }
454 
getCallId(Call call)455     public String getCallId(Call call) {
456         String str = call.toString();
457         String[] arrofstr = str.split(",", 3);
458         int index = arrofstr[0].indexOf(":");
459         String callId = arrofstr[0].substring(index + 1);
460         return callId;
461     }
462 
getCall(String callId)463     public Call getCall(String callId) {
464         synchronized (mCalls) {
465             if (mCalls.isEmpty()) {
466                 return null;
467             }
468 
469             for (Map.Entry<String, Call> entry : mCalls.entrySet()) {
470                 if (entry.getKey().equals(callId)) {
471                     Call call = entry.getValue();
472                     assertNotNull("Call is not added, its null", call);
473                     return call;
474                 }
475             }
476         }
477         return null;
478     }
479 
removeCall(Call call)480     protected void removeCall(Call call) {
481         if (mCalls.isEmpty()) {
482             return;
483         }
484 
485         String callid = getCallId(call);
486         Map.Entry<String, Call>[] entries = mCalls.entrySet().toArray(new Map.Entry[mCalls.size()]);
487         for (Map.Entry<String, Call> entry : entries) {
488             if (entry.getKey().equals(callid)) {
489                 mCalls.remove(entry.getKey());
490                 mCurrentCallId = null;
491             }
492         }
493     }
494 
495     protected class ServiceCallBack extends InCallServiceCallbacks {
496 
497         @Override
onCallAdded(Call call, int numCalls)498         public void onCallAdded(Call call, int numCalls) {
499             Log.i(LOG_TAG, "onCallAdded, Call: " + call + ", Num Calls: " + numCalls);
500             addCall(call);
501             countDownLatch(LATCH_IS_ON_CALL_ADDED);
502             if (call.getDetails().hasProperty(Call.Details.PROPERTY_CONFERENCE)) {
503                 countDownLatch(LATCH_IS_ON_CONFERENCE_CALL_ADDED);
504             }
505         }
506 
507         @Override
onCallRemoved(Call call, int numCalls)508         public void onCallRemoved(Call call, int numCalls) {
509             Log.i(LOG_TAG, "onCallRemoved, Call: " + call + ", Num Calls: " + numCalls);
510             removeCall(call);
511             countDownLatch(LATCH_IS_ON_CALL_REMOVED);
512         }
513 
514         @Override
onCallStateChanged(Call call, int state)515         public void onCallStateChanged(Call call, int state) {
516             Log.i(LOG_TAG, "onCallStateChanged " + state + "Call: " + call);
517 
518             switch (state) {
519                 case Call.STATE_DIALING:
520                     countDownLatch(LATCH_IS_CALL_DIALING);
521                     break;
522                 case Call.STATE_ACTIVE:
523                     countDownLatch(LATCH_IS_CALL_ACTIVE);
524                     break;
525                 case Call.STATE_DISCONNECTING:
526                     countDownLatch(LATCH_IS_CALL_DISCONNECTING);
527                     break;
528                 case Call.STATE_DISCONNECTED:
529                     countDownLatch(LATCH_IS_CALL_DISCONNECTED);
530                     break;
531                 case Call.STATE_RINGING:
532                     countDownLatch(LATCH_IS_CALL_RINGING);
533                     break;
534                 case Call.STATE_HOLDING:
535                     countDownLatch(LATCH_IS_CALL_HOLDING);
536                     break;
537                 default:
538                     break;
539             }
540         }
541 
542         @Override
onChildrenChanged(Call call, List<Call> children)543         public void onChildrenChanged(Call call, List<Call> children) {
544             if (call.getDetails().hasProperty(Call.Details.PROPERTY_CONFERENCE)) {
545                 Log.i(LOG_TAG, "onChildrenChanged, Call: " + call + " , size " + children.size());
546                 mParticipantCount = children.size();
547                 countDownLatch(LATCH_IS_ON_CHILDREN_CHANGED);
548             }
549         }
550 
551         @Override
onConnectionEvent(Call call, String event, Bundle extras)552         public void onConnectionEvent(Call call, String event, Bundle extras) {
553             Log.i(LOG_TAG, "onConnectionEvent, Call: " + call + " , event " + event);
554             if (event.equals(android.telecom.Connection.EVENT_CALL_REMOTELY_HELD)) {
555                 countDownLatch(LATCH_IS_ON_CALL_REMOTELY_HELD);
556             } else if (event.equals(android.telecom.Connection.EVENT_CALL_REMOTELY_UNHELD)) {
557                 countDownLatch(LATCH_IS_ON_CALL_REMOTELY_UNHELD);
558             } else if (event.equals(android.telecom.Connection.EVENT_MERGE_START)) {
559                 countDownLatch(LATCH_IS_ON_MERGE_START);
560             } else if (event.equals(android.telecom.Connection.EVENT_MERGE_COMPLETE)) {
561                 countDownLatch(LATCH_IS_ON_MERGE_COMPLETE);
562             }
563         }
564     }
565 
getContext()566     protected static Context getContext() {
567         return InstrumentationRegistry.getInstrumentation().getContext();
568     }
569 
570     /** Checks whether the system feature is supported. */
hasFeature(String feature)571     protected static boolean hasFeature(String feature) {
572         final PackageManager pm = getContext().getPackageManager();
573         if (!pm.hasSystemFeature(feature)) {
574             Log.d(LOG_TAG, "Skipping test that requires " + feature);
575             return false;
576         }
577         return true;
578     }
579 
setDefaultDialer(Instrumentation instrumentation, String packageName)580     protected static String setDefaultDialer(Instrumentation instrumentation, String packageName)
581             throws Exception {
582         String str =
583                 TelephonyUtils.executeShellCommand(
584                         instrumentation, COMMAND_SET_DEFAULT_DIALER + packageName);
585         return str;
586     }
587 
getDefaultDialer(Instrumentation instrumentation)588     protected static String getDefaultDialer(Instrumentation instrumentation) throws Exception {
589         String str =
590                 TelephonyUtils.executeShellCommand(instrumentation, COMMAND_GET_DEFAULT_DIALER);
591         return str;
592     }
593 
overrideCarrierConfig(PersistableBundle bundle)594     protected static void overrideCarrierConfig(PersistableBundle bundle) throws Exception {
595         CarrierConfigManager carrierConfigManager =
596                 InstrumentationRegistry.getInstrumentation()
597                         .getContext()
598                         .getSystemService(CarrierConfigManager.class);
599         sReceiver.clearQueue();
600         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
601                 carrierConfigManager, (m) -> m.overrideConfig(sTestSub, bundle));
602         sReceiver.waitForChanged();
603     }
604 }
605