1 /*
2  * Copyright (C) 2013 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 com.android.internal.telephony;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.net.Uri;
24 import android.os.BadParcelableException;
25 import android.os.Bundle;
26 import android.telephony.AccessNetworkConstants;
27 import android.telephony.NetworkRegistrationInfo;
28 import android.telephony.ServiceState;
29 import android.telephony.TelephonyManager;
30 import android.telephony.ims.ImsCallProfile;
31 import android.telephony.ims.ImsConferenceState;
32 import android.telephony.ims.ImsExternalCallState;
33 import android.telephony.ims.ImsReasonInfo;
34 
35 import com.android.ims.ImsCall;
36 import com.android.internal.telephony.gsm.SuppServiceNotification;
37 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
38 import com.android.internal.telephony.imsphone.ImsPhone;
39 import com.android.internal.telephony.imsphone.ImsPhoneCall;
40 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
41 import com.android.internal.telephony.test.TestConferenceEventPackageParser;
42 import com.android.internal.telephony.util.TelephonyUtils;
43 import com.android.telephony.Rlog;
44 
45 import java.io.File;
46 import java.io.FileInputStream;
47 import java.io.FileNotFoundException;
48 import java.util.ArrayList;
49 import java.util.List;
50 
51 /**
52  * Telephony tester receives the following intents where {name} is the phone name
53  *
54  * adb shell am broadcast -a com.android.internal.telephony.{name}.action_detached
55  * adb shell am broadcast -a com.android.internal.telephony.{name}.action_attached
56  * adb shell am broadcast -a com.android.internal.telephony.TestConferenceEventPackage -e filename
57  *      test_filename.xml
58  * adb shell am broadcast -a com.android.internal.telephony.TestServiceState --ei data_rat 10 --ei
59  *      data_roaming_type 3
60  * adb shell am broadcast -a com.android.internal.telephony.TestServiceState --es action reset
61  *
62  */
63 public class TelephonyTester {
64     private static final String LOG_TAG = "TelephonyTester";
65     private static final boolean DBG = true;
66 
67     /**
68      * Test-only intent used to send a test conference event package to the IMS framework.
69      */
70     private static final String ACTION_TEST_CONFERENCE_EVENT_PACKAGE =
71             "com.android.internal.telephony.TestConferenceEventPackage";
72 
73     /**
74      * Test-only intent used to send a test dialog event package to the IMS framework.
75      */
76     private static final String ACTION_TEST_DIALOG_EVENT_PACKAGE =
77             "com.android.internal.telephony.TestDialogEventPackage";
78 
79     private static final String EXTRA_FILENAME = "filename";
80     /**
81      * Used to inject the conference event package by bypassing the ImsCall and doing the
82      * injection via ImsPhoneCallTracker.  This is useful in scenarios where the
83      * adb shell cmd phone ims conference-event-package disable
84      * command is used to disable network CEP data and it is desired to still inject CEP data.
85      * Where the network CEP data is not explicitly disabled using the command above, it is not
86      * necessary to bypass the ImsCall.
87      */
88     private static final String EXTRA_BYPASS_IMSCALL = "bypassImsCall";
89     private static final String EXTRA_STARTPACKAGE = "startPackage";
90     private static final String EXTRA_SENDPACKAGE = "sendPackage";
91     private static final String EXTRA_DIALOGID = "dialogId";
92     private static final String EXTRA_NUMBER = "number";
93     private static final String EXTRA_STATE = "state";
94     private static final String EXTRA_CANPULL = "canPull";
95 
96     /**
97      * Test-only intent used to trigger supp service notification failure.
98      */
99     private static final String ACTION_TEST_SUPP_SRVC_FAIL =
100             "com.android.internal.telephony.TestSuppSrvcFail";
101     private static final String EXTRA_FAILURE_CODE = "failureCode";
102 
103     /**
104      * Test-only intent used to trigger the signalling which occurs when a handover to WIFI fails.
105      */
106     private static final String ACTION_TEST_HANDOVER_FAIL =
107             "com.android.internal.telephony.TestHandoverFail";
108 
109     /**
110      * Test-only intent used to trigger signalling of a
111      * {@link com.android.internal.telephony.gsm.SuppServiceNotification} to the {@link ImsPhone}.
112      * Use {@link #EXTRA_CODE} to specify the
113      * {@link com.android.internal.telephony.gsm.SuppServiceNotification#code}.
114      */
115     private static final String ACTION_TEST_SUPP_SRVC_NOTIFICATION =
116             "com.android.internal.telephony.TestSuppSrvcNotification";
117 
118     private static final String EXTRA_CODE = "code";
119     private static final String EXTRA_TYPE = "type";
120 
121     /**
122      * Test-only intent used to trigger signalling that an IMS call is an emergency call.
123      */
124     private static final String ACTION_TEST_IMS_E_CALL =
125             "com.android.internal.telephony.TestImsECall";
126 
127     /**
128      * Test-only intent used to trigger signalling that an IMS call received a DTMF tone.
129      */
130     private static final String ACTION_TEST_RECEIVE_DTMF =
131             "com.android.internal.telephony.TestReceiveDtmf";
132 
133     private static final String EXTRA_DIGIT = "digit";
134 
135     /**
136      * Test-only intent used to trigger a change to the current call's phone number.
137      * Use the {@link #EXTRA_NUMBER} extra to specify the new phone number.
138      */
139     private static final String ACTION_TEST_CHANGE_NUMBER =
140             "com.android.internal.telephony.TestChangeNumber";
141 
142     private static final String ACTION_TEST_SERVICE_STATE =
143             "com.android.internal.telephony.TestServiceState";
144 
145     private static final String EXTRA_ACTION = "action";
146     private static final String EXTRA_VOICE_RAT = "voice_rat";
147     private static final String EXTRA_DATA_RAT = "data_rat";
148     private static final String EXTRA_VOICE_REG_STATE = "voice_reg_state";
149     private static final String EXTRA_DATA_REG_STATE = "data_reg_state";
150     private static final String EXTRA_VOICE_ROAMING_TYPE = "voice_roaming_type";
151     private static final String EXTRA_DATA_ROAMING_TYPE = "data_roaming_type";
152     private static final String EXTRA_NR_FREQUENCY_RANGE = "nr_frequency_range";
153     private static final String EXTRA_NR_STATE = "nr_state";
154     private static final String EXTRA_OPERATOR = "operator";
155     private static final String EXTRA_OPERATOR_RAW = "operator_raw";
156 
157     private static final String ACTION_RESET = "reset";
158 
159     private static List<ImsExternalCallState> mImsExternalCallStates = null;
160 
161     private Intent mServiceStateTestIntent;
162 
163     private Phone mPhone;
164 
165     // The static intent receiver one for all instances and we assume this
166     // is running on the same thread as Dcc.
167     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
168             @Override
169         public void onReceive(Context context, Intent intent) {
170             String action = intent.getAction();
171             try {
172                 if (DBG) log("sIntentReceiver.onReceive: action=" + action);
173                 if (action.equals(mPhone.getActionDetached())) {
174                     log("simulate detaching");
175                     mPhone.getServiceStateTracker().mDetachedRegistrants.get(
176                             AccessNetworkConstants.TRANSPORT_TYPE_WWAN).notifyRegistrants();
177                 } else if (action.equals(mPhone.getActionAttached())) {
178                     log("simulate attaching");
179                     mPhone.getServiceStateTracker().mAttachedRegistrants.get(
180                             AccessNetworkConstants.TRANSPORT_TYPE_WWAN).notifyRegistrants();
181                 } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) {
182                     log("inject simulated conference event package");
183                     handleTestConferenceEventPackage(context,
184                             intent.getStringExtra(EXTRA_FILENAME),
185                             intent.getBooleanExtra(EXTRA_BYPASS_IMSCALL, false));
186                 } else if (action.equals(ACTION_TEST_DIALOG_EVENT_PACKAGE)) {
187                     log("handle test dialog event package intent");
188                     handleTestDialogEventPackageIntent(intent);
189                 } else if (action.equals(ACTION_TEST_SUPP_SRVC_FAIL)) {
190                     log("handle test supp svc failed intent");
191                     handleSuppServiceFailedIntent(intent);
192                 } else if (action.equals(ACTION_TEST_HANDOVER_FAIL)) {
193                     log("handle handover fail test intent");
194                     handleHandoverFailedIntent();
195                 } else if (action.equals(ACTION_TEST_SUPP_SRVC_NOTIFICATION)) {
196                     log("handle supp service notification test intent");
197                     sendTestSuppServiceNotification(intent);
198                 } else if (action.equals(ACTION_TEST_SERVICE_STATE)) {
199                     log("handle test service state changed intent");
200                     // Trigger the service state update. The replacement will be done in
201                     // overrideServiceState().
202                     mServiceStateTestIntent = intent;
203                     mPhone.getServiceStateTracker().sendEmptyMessage(
204                             ServiceStateTracker.EVENT_NETWORK_STATE_CHANGED);
205                 } else if (action.equals(ACTION_TEST_IMS_E_CALL)) {
206                     log("handle test IMS ecall intent");
207                     testImsECall();
208                 } else if (action.equals(ACTION_TEST_RECEIVE_DTMF)) {
209                     log("handle test DTMF intent");
210                     testImsReceiveDtmf(intent);
211                 } else if (action.equals(ACTION_TEST_CHANGE_NUMBER)) {
212                     log("handle test change number intent");
213                     testChangeNumber(intent);
214                 } else {
215                     if (DBG) log("onReceive: unknown action=" + action);
216                 }
217             } catch (BadParcelableException e) {
218                 Rlog.w(LOG_TAG, e);
219             }
220         }
221     };
222 
TelephonyTester(Phone phone)223     TelephonyTester(Phone phone) {
224         mPhone = phone;
225 
226         if (TelephonyUtils.IS_DEBUGGABLE) {
227             IntentFilter filter = new IntentFilter();
228 
229             filter.addAction(mPhone.getActionDetached());
230             log("register for intent action=" + mPhone.getActionDetached());
231 
232             filter.addAction(mPhone.getActionAttached());
233             log("register for intent action=" + mPhone.getActionAttached());
234 
235             if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
236                 log("register for intent action=" + ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
237                 filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
238                 filter.addAction(ACTION_TEST_DIALOG_EVENT_PACKAGE);
239                 filter.addAction(ACTION_TEST_SUPP_SRVC_FAIL);
240                 filter.addAction(ACTION_TEST_HANDOVER_FAIL);
241                 filter.addAction(ACTION_TEST_SUPP_SRVC_NOTIFICATION);
242                 filter.addAction(ACTION_TEST_IMS_E_CALL);
243                 filter.addAction(ACTION_TEST_RECEIVE_DTMF);
244                 mImsExternalCallStates = new ArrayList<ImsExternalCallState>();
245             }
246 
247             filter.addAction(ACTION_TEST_SERVICE_STATE);
248             log("register for intent action=" + ACTION_TEST_SERVICE_STATE);
249 
250             filter.addAction(ACTION_TEST_CHANGE_NUMBER);
251             log("register for intent action=" + ACTION_TEST_CHANGE_NUMBER);
252             phone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone.getHandler());
253         }
254     }
255 
dispose()256     void dispose() {
257         if (TelephonyUtils.IS_DEBUGGABLE) {
258             mPhone.getContext().unregisterReceiver(mIntentReceiver);
259         }
260     }
261 
log(String s)262     private static void log(String s) {
263         Rlog.d(LOG_TAG, s);
264     }
265 
handleSuppServiceFailedIntent(Intent intent)266     private void handleSuppServiceFailedIntent(Intent intent) {
267         ImsPhone imsPhone = (ImsPhone) mPhone;
268         if (imsPhone == null) {
269             return;
270         }
271         int code = intent.getIntExtra(EXTRA_FAILURE_CODE, 0);
272         imsPhone.notifySuppServiceFailed(PhoneInternalInterface.SuppService.values()[code]);
273     }
274 
handleHandoverFailedIntent()275     private void handleHandoverFailedIntent() {
276         // Attempt to get the active IMS call
277         ImsCall imsCall = getImsCall();
278         if (imsCall == null) {
279             return;
280         }
281 
282         imsCall.getImsCallSessionListenerProxy().callSessionHandoverFailed(imsCall.getCallSession(),
283                 TelephonyManager.NETWORK_TYPE_LTE, TelephonyManager.NETWORK_TYPE_IWLAN,
284                 new ImsReasonInfo());
285     }
286 
287     /**
288      * Handles request to send a test conference event package to the active Ims call.
289      *
290      * @see com.android.internal.telephony.test.TestConferenceEventPackageParser
291      * @param context The context.
292      * @param fileName The name of the test conference event package file to read.
293      */
handleTestConferenceEventPackage(Context context, String fileName, boolean isBypassingImsCall)294     private void handleTestConferenceEventPackage(Context context, String fileName,
295             boolean isBypassingImsCall) {
296         // Attempt to get the active IMS call before parsing the test XML file.
297         ImsPhone imsPhone = (ImsPhone) mPhone;
298         if (imsPhone == null) {
299             return;
300         }
301 
302         ImsPhoneCallTracker tracker = (ImsPhoneCallTracker) imsPhone.getCallTracker();
303 
304         File packageFile = new File(context.getFilesDir(), fileName);
305         final FileInputStream is;
306         try {
307             is = new FileInputStream(packageFile);
308         } catch (FileNotFoundException ex) {
309             log("Test conference event package file not found: " + packageFile.getAbsolutePath());
310             return;
311         }
312 
313         TestConferenceEventPackageParser parser = new TestConferenceEventPackageParser(is);
314         ImsConferenceState imsConferenceState = parser.parse();
315         if (imsConferenceState == null) {
316             return;
317         }
318 
319         if (isBypassingImsCall) {
320             tracker.injectTestConferenceState(imsConferenceState);
321         } else {
322             ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
323             if (imsPhoneCall == null) {
324                 return;
325             }
326 
327             ImsCall imsCall = imsPhoneCall.getImsCall();
328             if (imsCall == null) {
329                 return;
330             }
331 
332             imsCall.conferenceStateUpdated(imsConferenceState);
333         }
334     }
335 
336     /**
337      * Handles intents containing test dialog event package data.
338      *
339      * @param intent
340      */
handleTestDialogEventPackageIntent(Intent intent)341     private void handleTestDialogEventPackageIntent(Intent intent) {
342         ImsPhone imsPhone = (ImsPhone) mPhone;
343         if (imsPhone == null) {
344             return;
345         }
346         ImsExternalCallTracker externalCallTracker = imsPhone.getExternalCallTracker();
347         if (externalCallTracker == null) {
348             return;
349         }
350 
351         if (intent.hasExtra(EXTRA_STARTPACKAGE)) {
352             mImsExternalCallStates.clear();
353         } else if (intent.hasExtra(EXTRA_SENDPACKAGE)) {
354             externalCallTracker.refreshExternalCallState(mImsExternalCallStates);
355             mImsExternalCallStates.clear();
356         } else if (intent.hasExtra(EXTRA_DIALOGID)) {
357             ImsExternalCallState state = new ImsExternalCallState(
358                     intent.getIntExtra(EXTRA_DIALOGID, 0),
359                     Uri.parse(intent.getStringExtra(EXTRA_NUMBER)),
360                     intent.getBooleanExtra(EXTRA_CANPULL, true),
361                     intent.getIntExtra(EXTRA_STATE,
362                             ImsExternalCallState.CALL_STATE_CONFIRMED),
363                     ImsCallProfile.CALL_TYPE_VOICE,
364                     false /* isHeld */
365                     );
366             mImsExternalCallStates.add(state);
367         }
368     }
369 
sendTestSuppServiceNotification(Intent intent)370     private void sendTestSuppServiceNotification(Intent intent) {
371         if (intent.hasExtra(EXTRA_CODE) && intent.hasExtra(EXTRA_TYPE)) {
372             int code = intent.getIntExtra(EXTRA_CODE, -1);
373             int type = intent.getIntExtra(EXTRA_TYPE, -1);
374             ImsPhone imsPhone = (ImsPhone) mPhone;
375             if (imsPhone == null) {
376                 return;
377             }
378             log("Test supp service notification:" + code);
379             SuppServiceNotification suppServiceNotification = new SuppServiceNotification();
380             suppServiceNotification.code = code;
381             suppServiceNotification.notificationType = type;
382             imsPhone.notifySuppSvcNotification(suppServiceNotification);
383         }
384     }
385 
overrideServiceState(ServiceState ss)386     void overrideServiceState(ServiceState ss) {
387         if (mServiceStateTestIntent == null || ss == null) return;
388         if (mServiceStateTestIntent.hasExtra(EXTRA_ACTION)
389                 && ACTION_RESET.equals(mServiceStateTestIntent.getStringExtra(EXTRA_ACTION))) {
390             log("Service state override reset");
391             return;
392         }
393 
394         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_REG_STATE)) {
395             ss.setVoiceRegState(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_REG_STATE,
396                     ServiceState.STATE_OUT_OF_SERVICE));
397             log("Override voice service state with " + ss.getState());
398         }
399         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_REG_STATE)) {
400             ss.setDataRegState(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_REG_STATE,
401                     ServiceState.STATE_OUT_OF_SERVICE));
402             log("Override data service state with " + ss.getDataRegistrationState());
403         }
404         if (mServiceStateTestIntent.hasExtra(EXTRA_OPERATOR)) {
405             String operator = mServiceStateTestIntent.getStringExtra(EXTRA_OPERATOR);
406             ss.setOperatorName(operator, operator, "");
407             log("Override operator with " + operator);
408         }
409         if (mServiceStateTestIntent.hasExtra(EXTRA_OPERATOR_RAW)) {
410             String operator_raw = mServiceStateTestIntent.getStringExtra(EXTRA_OPERATOR_RAW);
411             ss.setOperatorAlphaLongRaw(operator_raw);
412             ss.setOperatorAlphaShortRaw(operator_raw);
413             log("Override operator_raw with " + operator_raw);
414         }
415         if (mServiceStateTestIntent.hasExtra(EXTRA_NR_FREQUENCY_RANGE)) {
416             ss.setNrFrequencyRange(mServiceStateTestIntent.getIntExtra(EXTRA_NR_FREQUENCY_RANGE,
417                     ServiceState.FREQUENCY_RANGE_UNKNOWN));
418             log("Override NR frequency range with " + ss.getNrFrequencyRange());
419         }
420         if (mServiceStateTestIntent.hasExtra(EXTRA_NR_STATE)) {
421             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
422                     NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
423             if (nri == null) {
424                 nri = new NetworkRegistrationInfo.Builder()
425                         .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
426                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
427                         .build();
428             }
429             nri.setNrState(mServiceStateTestIntent.getIntExtra(EXTRA_NR_STATE,
430                     NetworkRegistrationInfo.NR_STATE_NONE));
431             ss.addNetworkRegistrationInfo(nri);
432             log("Override NR state with " + ss.getNrState());
433         }
434         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_RAT)) {
435             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
436                     NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
437             if (nri == null) {
438                 nri = new NetworkRegistrationInfo.Builder()
439                         .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
440                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
441                         .build();
442             }
443             nri.setAccessNetworkTechnology(ServiceState.rilRadioTechnologyToNetworkType(
444                     mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_RAT,
445                     ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)));
446             ss.addNetworkRegistrationInfo(nri);
447             log("Override voice rat with " + ss.getRilVoiceRadioTechnology());
448         }
449         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_RAT)) {
450             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
451                     NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
452             if (nri == null) {
453                 nri = new NetworkRegistrationInfo.Builder()
454                         .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
455                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
456                         .build();
457             }
458             nri.setAccessNetworkTechnology(ServiceState.rilRadioTechnologyToNetworkType(
459                     mServiceStateTestIntent.getIntExtra(EXTRA_DATA_RAT,
460                     ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)));
461             ss.addNetworkRegistrationInfo(nri);
462             log("Override data rat with " + ss.getRilDataRadioTechnology());
463         }
464         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_ROAMING_TYPE)) {
465             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
466                     NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
467             if (nri == null) {
468                 nri = new NetworkRegistrationInfo.Builder()
469                         .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
470                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
471                         .build();
472             }
473             nri.setRoamingType(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_ROAMING_TYPE,
474                     ServiceState.ROAMING_TYPE_UNKNOWN));
475             ss.addNetworkRegistrationInfo(nri);
476             log("Override voice roaming type with " + ss.getVoiceRoamingType());
477         }
478         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_ROAMING_TYPE)) {
479             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
480                     NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
481             if (nri == null) {
482                 nri = new NetworkRegistrationInfo.Builder()
483                         .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
484                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
485                         .build();
486             }
487             nri.setRoamingType(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_ROAMING_TYPE,
488                     ServiceState.ROAMING_TYPE_UNKNOWN));
489             ss.addNetworkRegistrationInfo(nri);
490             log("Override data roaming type with " + ss.getDataRoamingType());
491         }
492     }
493 
testImsECall()494     void testImsECall() {
495         // Attempt to get the active IMS call before parsing the test XML file.
496         ImsCall imsCall = getImsCall();
497         if (imsCall == null) return;
498 
499         ImsCallProfile callProfile = imsCall.getCallProfile();
500         Bundle extras = callProfile.getCallExtras();
501         if (extras == null) {
502             extras = new Bundle();
503         }
504         extras.putBoolean(ImsCallProfile.EXTRA_EMERGENCY_CALL, true);
505         callProfile.mCallExtras = extras;
506         imsCall.getImsCallSessionListenerProxy().callSessionUpdated(imsCall.getSession(),
507                 callProfile);
508     }
509 
getImsCall()510     private ImsCall getImsCall() {
511         ImsPhone imsPhone = (ImsPhone) mPhone;
512         if (imsPhone == null) {
513             return null;
514         }
515 
516         ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
517         if (imsPhoneCall == null) {
518             return null;
519         }
520 
521         ImsCall imsCall = imsPhoneCall.getImsCall();
522         if (imsCall == null) {
523             return null;
524         }
525         return imsCall;
526     }
527 
testImsReceiveDtmf(Intent intent)528     void testImsReceiveDtmf(Intent intent) {
529         if (!intent.hasExtra(EXTRA_DIGIT)) {
530             return;
531         }
532         char digit = intent.getStringExtra(EXTRA_DIGIT).charAt(0);
533 
534         ImsCall imsCall = getImsCall();
535         if (imsCall == null) {
536             return;
537         }
538 
539         imsCall.getImsCallSessionListenerProxy().callSessionDtmfReceived(digit);
540     }
541 
testChangeNumber(Intent intent)542     void testChangeNumber(Intent intent) {
543         if (!intent.hasExtra(EXTRA_NUMBER)) {
544             return;
545         }
546 
547         String newNumber = intent.getStringExtra(EXTRA_NUMBER);
548 
549         // Update all the calls.
550         mPhone.getForegroundCall().getConnections()
551                 .stream()
552                 .forEach(c -> {
553                     c.setAddress(newNumber, PhoneConstants.PRESENTATION_ALLOWED);
554                     c.setDialString(newNumber);
555                 });
556 
557         // <sigh>
558         if (mPhone instanceof GsmCdmaPhone) {
559             ((GsmCdmaPhone) mPhone).notifyPhoneStateChanged();
560             ((GsmCdmaPhone) mPhone).notifyPreciseCallStateChanged();
561         } else if (mPhone instanceof ImsPhone) {
562             ((ImsPhone) mPhone).notifyPhoneStateChanged();
563             ((ImsPhone) mPhone).notifyPreciseCallStateChanged();
564         }
565     }
566 }
567