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