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