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 a change to the current call's phone number.
129      * Use the {@link #EXTRA_NUMBER} extra to specify the new phone number.
130      */
131     private static final String ACTION_TEST_CHANGE_NUMBER =
132             "com.android.internal.telephony.TestChangeNumber";
133 
134     private static final String ACTION_TEST_SERVICE_STATE =
135             "com.android.internal.telephony.TestServiceState";
136 
137     private static final String EXTRA_ACTION = "action";
138     private static final String EXTRA_VOICE_RAT = "voice_rat";
139     private static final String EXTRA_DATA_RAT = "data_rat";
140     private static final String EXTRA_VOICE_REG_STATE = "voice_reg_state";
141     private static final String EXTRA_DATA_REG_STATE = "data_reg_state";
142     private static final String EXTRA_VOICE_ROAMING_TYPE = "voice_roaming_type";
143     private static final String EXTRA_DATA_ROAMING_TYPE = "data_roaming_type";
144     private static final String EXTRA_NR_FREQUENCY_RANGE = "nr_frequency_range";
145     private static final String EXTRA_NR_STATE = "nr_state";
146     private static final String EXTRA_OPERATOR = "operator";
147     private static final String EXTRA_OPERATOR_RAW = "operator_raw";
148 
149     private static final String ACTION_RESET = "reset";
150 
151     private static List<ImsExternalCallState> mImsExternalCallStates = null;
152 
153     private Intent mServiceStateTestIntent;
154 
155     private Phone mPhone;
156 
157     // The static intent receiver one for all instances and we assume this
158     // is running on the same thread as Dcc.
159     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
160             @Override
161         public void onReceive(Context context, Intent intent) {
162             String action = intent.getAction();
163             try {
164                 if (DBG) log("sIntentReceiver.onReceive: action=" + action);
165                 if (action.equals(mPhone.getActionDetached())) {
166                     log("simulate detaching");
167                     mPhone.getServiceStateTracker().mDetachedRegistrants.get(
168                             AccessNetworkConstants.TRANSPORT_TYPE_WWAN).notifyRegistrants();
169                 } else if (action.equals(mPhone.getActionAttached())) {
170                     log("simulate attaching");
171                     mPhone.getServiceStateTracker().mAttachedRegistrants.get(
172                             AccessNetworkConstants.TRANSPORT_TYPE_WWAN).notifyRegistrants();
173                 } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) {
174                     log("inject simulated conference event package");
175                     handleTestConferenceEventPackage(context,
176                             intent.getStringExtra(EXTRA_FILENAME),
177                             intent.getBooleanExtra(EXTRA_BYPASS_IMSCALL, false));
178                 } else if (action.equals(ACTION_TEST_DIALOG_EVENT_PACKAGE)) {
179                     log("handle test dialog event package intent");
180                     handleTestDialogEventPackageIntent(intent);
181                 } else if (action.equals(ACTION_TEST_SUPP_SRVC_FAIL)) {
182                     log("handle test supp svc failed intent");
183                     handleSuppServiceFailedIntent(intent);
184                 } else if (action.equals(ACTION_TEST_HANDOVER_FAIL)) {
185                     log("handle handover fail test intent");
186                     handleHandoverFailedIntent();
187                 } else if (action.equals(ACTION_TEST_SUPP_SRVC_NOTIFICATION)) {
188                     log("handle supp service notification test intent");
189                     sendTestSuppServiceNotification(intent);
190                 } else if (action.equals(ACTION_TEST_SERVICE_STATE)) {
191                     log("handle test service state changed intent");
192                     // Trigger the service state update. The replacement will be done in
193                     // overrideServiceState().
194                     mServiceStateTestIntent = intent;
195                     mPhone.getServiceStateTracker().sendEmptyMessage(
196                             ServiceStateTracker.EVENT_NETWORK_STATE_CHANGED);
197                 } else if (action.equals(ACTION_TEST_IMS_E_CALL)) {
198                     log("handle test IMS ecall intent");
199                     testImsECall();
200                 } else if (action.equals(ACTION_TEST_CHANGE_NUMBER)) {
201                     log("handle test change number intent");
202                     testChangeNumber(intent);
203                 } else {
204                     if (DBG) log("onReceive: unknown action=" + action);
205                 }
206             } catch (BadParcelableException e) {
207                 Rlog.w(LOG_TAG, e);
208             }
209         }
210     };
211 
TelephonyTester(Phone phone)212     TelephonyTester(Phone phone) {
213         mPhone = phone;
214 
215         if (TelephonyUtils.IS_DEBUGGABLE) {
216             IntentFilter filter = new IntentFilter();
217 
218             filter.addAction(mPhone.getActionDetached());
219             log("register for intent action=" + mPhone.getActionDetached());
220 
221             filter.addAction(mPhone.getActionAttached());
222             log("register for intent action=" + mPhone.getActionAttached());
223 
224             if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
225                 log("register for intent action=" + ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
226                 filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
227                 filter.addAction(ACTION_TEST_DIALOG_EVENT_PACKAGE);
228                 filter.addAction(ACTION_TEST_SUPP_SRVC_FAIL);
229                 filter.addAction(ACTION_TEST_HANDOVER_FAIL);
230                 filter.addAction(ACTION_TEST_SUPP_SRVC_NOTIFICATION);
231                 filter.addAction(ACTION_TEST_IMS_E_CALL);
232                 mImsExternalCallStates = new ArrayList<ImsExternalCallState>();
233             }
234 
235             filter.addAction(ACTION_TEST_SERVICE_STATE);
236             log("register for intent action=" + ACTION_TEST_SERVICE_STATE);
237 
238             filter.addAction(ACTION_TEST_CHANGE_NUMBER);
239             log("register for intent action=" + ACTION_TEST_CHANGE_NUMBER);
240             phone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone.getHandler());
241         }
242     }
243 
dispose()244     void dispose() {
245         if (TelephonyUtils.IS_DEBUGGABLE) {
246             mPhone.getContext().unregisterReceiver(mIntentReceiver);
247         }
248     }
249 
log(String s)250     private static void log(String s) {
251         Rlog.d(LOG_TAG, s);
252     }
253 
handleSuppServiceFailedIntent(Intent intent)254     private void handleSuppServiceFailedIntent(Intent intent) {
255         ImsPhone imsPhone = (ImsPhone) mPhone;
256         if (imsPhone == null) {
257             return;
258         }
259         int code = intent.getIntExtra(EXTRA_FAILURE_CODE, 0);
260         imsPhone.notifySuppServiceFailed(PhoneInternalInterface.SuppService.values()[code]);
261     }
262 
handleHandoverFailedIntent()263     private void handleHandoverFailedIntent() {
264         // Attempt to get the active IMS call
265         ImsPhone imsPhone = (ImsPhone) mPhone;
266         if (imsPhone == null) {
267             return;
268         }
269 
270         ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
271         if (imsPhoneCall == null) {
272             return;
273         }
274 
275         ImsCall imsCall = imsPhoneCall.getImsCall();
276         if (imsCall == null) {
277             return;
278         }
279 
280         imsCall.getImsCallSessionListenerProxy().callSessionHandoverFailed(imsCall.getCallSession(),
281                 TelephonyManager.NETWORK_TYPE_LTE, TelephonyManager.NETWORK_TYPE_IWLAN,
282                 new ImsReasonInfo());
283     }
284 
285     /**
286      * Handles request to send a test conference event package to the active Ims call.
287      *
288      * @see com.android.internal.telephony.test.TestConferenceEventPackageParser
289      * @param context The context.
290      * @param fileName The name of the test conference event package file to read.
291      */
handleTestConferenceEventPackage(Context context, String fileName, boolean isBypassingImsCall)292     private void handleTestConferenceEventPackage(Context context, String fileName,
293             boolean isBypassingImsCall) {
294         // Attempt to get the active IMS call before parsing the test XML file.
295         ImsPhone imsPhone = (ImsPhone) mPhone;
296         if (imsPhone == null) {
297             return;
298         }
299 
300         ImsPhoneCallTracker tracker = (ImsPhoneCallTracker) imsPhone.getCallTracker();
301 
302         File packageFile = new File(context.getFilesDir(), fileName);
303         final FileInputStream is;
304         try {
305             is = new FileInputStream(packageFile);
306         } catch (FileNotFoundException ex) {
307             log("Test conference event package file not found: " + packageFile.getAbsolutePath());
308             return;
309         }
310 
311         TestConferenceEventPackageParser parser = new TestConferenceEventPackageParser(is);
312         ImsConferenceState imsConferenceState = parser.parse();
313         if (imsConferenceState == null) {
314             return;
315         }
316 
317         if (isBypassingImsCall) {
318             tracker.injectTestConferenceState(imsConferenceState);
319         } else {
320             ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
321             if (imsPhoneCall == null) {
322                 return;
323             }
324 
325             ImsCall imsCall = imsPhoneCall.getImsCall();
326             if (imsCall == null) {
327                 return;
328             }
329 
330             imsCall.conferenceStateUpdated(imsConferenceState);
331         }
332     }
333 
334     /**
335      * Handles intents containing test dialog event package data.
336      *
337      * @param intent
338      */
handleTestDialogEventPackageIntent(Intent intent)339     private void handleTestDialogEventPackageIntent(Intent intent) {
340         ImsPhone imsPhone = (ImsPhone) mPhone;
341         if (imsPhone == null) {
342             return;
343         }
344         ImsExternalCallTracker externalCallTracker = imsPhone.getExternalCallTracker();
345         if (externalCallTracker == null) {
346             return;
347         }
348 
349         if (intent.hasExtra(EXTRA_STARTPACKAGE)) {
350             mImsExternalCallStates.clear();
351         } else if (intent.hasExtra(EXTRA_SENDPACKAGE)) {
352             externalCallTracker.refreshExternalCallState(mImsExternalCallStates);
353             mImsExternalCallStates.clear();
354         } else if (intent.hasExtra(EXTRA_DIALOGID)) {
355             ImsExternalCallState state = new ImsExternalCallState(
356                     intent.getIntExtra(EXTRA_DIALOGID, 0),
357                     Uri.parse(intent.getStringExtra(EXTRA_NUMBER)),
358                     intent.getBooleanExtra(EXTRA_CANPULL, true),
359                     intent.getIntExtra(EXTRA_STATE,
360                             ImsExternalCallState.CALL_STATE_CONFIRMED),
361                     ImsCallProfile.CALL_TYPE_VOICE,
362                     false /* isHeld */
363                     );
364             mImsExternalCallStates.add(state);
365         }
366     }
367 
sendTestSuppServiceNotification(Intent intent)368     private void sendTestSuppServiceNotification(Intent intent) {
369         if (intent.hasExtra(EXTRA_CODE) && intent.hasExtra(EXTRA_TYPE)) {
370             int code = intent.getIntExtra(EXTRA_CODE, -1);
371             int type = intent.getIntExtra(EXTRA_TYPE, -1);
372             ImsPhone imsPhone = (ImsPhone) mPhone;
373             if (imsPhone == null) {
374                 return;
375             }
376             log("Test supp service notification:" + code);
377             SuppServiceNotification suppServiceNotification = new SuppServiceNotification();
378             suppServiceNotification.code = code;
379             suppServiceNotification.notificationType = type;
380             imsPhone.notifySuppSvcNotification(suppServiceNotification);
381         }
382     }
383 
overrideServiceState(ServiceState ss)384     void overrideServiceState(ServiceState ss) {
385         if (mServiceStateTestIntent == null || ss == null) return;
386         if (mServiceStateTestIntent.hasExtra(EXTRA_ACTION)
387                 && ACTION_RESET.equals(mServiceStateTestIntent.getStringExtra(EXTRA_ACTION))) {
388             log("Service state override reset");
389             return;
390         }
391 
392         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_REG_STATE)) {
393             ss.setVoiceRegState(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_REG_STATE,
394                     ServiceState.STATE_OUT_OF_SERVICE));
395             log("Override voice service state with " + ss.getState());
396         }
397         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_REG_STATE)) {
398             ss.setDataRegState(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_REG_STATE,
399                     ServiceState.STATE_OUT_OF_SERVICE));
400             log("Override data service state with " + ss.getDataRegistrationState());
401         }
402         if (mServiceStateTestIntent.hasExtra(EXTRA_OPERATOR)) {
403             String operator = mServiceStateTestIntent.getStringExtra(EXTRA_OPERATOR);
404             ss.setOperatorName(operator, operator, "");
405             log("Override operator with " + operator);
406         }
407         if (mServiceStateTestIntent.hasExtra(EXTRA_OPERATOR_RAW)) {
408             String operator_raw = mServiceStateTestIntent.getStringExtra(EXTRA_OPERATOR_RAW);
409             ss.setOperatorAlphaLongRaw(operator_raw);
410             ss.setOperatorAlphaShortRaw(operator_raw);
411             log("Override operator_raw with " + operator_raw);
412         }
413         if (mServiceStateTestIntent.hasExtra(EXTRA_NR_FREQUENCY_RANGE)) {
414             ss.setNrFrequencyRange(mServiceStateTestIntent.getIntExtra(EXTRA_NR_FREQUENCY_RANGE,
415                     ServiceState.FREQUENCY_RANGE_UNKNOWN));
416             log("Override NR frequency range with " + ss.getNrFrequencyRange());
417         }
418         if (mServiceStateTestIntent.hasExtra(EXTRA_NR_STATE)) {
419             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
420                     NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
421             if (nri == null) {
422                 nri = new NetworkRegistrationInfo.Builder()
423                         .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
424                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
425                         .build();
426             }
427             nri.setNrState(mServiceStateTestIntent.getIntExtra(EXTRA_NR_STATE,
428                     NetworkRegistrationInfo.NR_STATE_NONE));
429             ss.addNetworkRegistrationInfo(nri);
430             log("Override NR state with " + ss.getNrState());
431         }
432         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_RAT)) {
433             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
434                     NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
435             if (nri == null) {
436                 nri = new NetworkRegistrationInfo.Builder()
437                         .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
438                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
439                         .build();
440             }
441             nri.setAccessNetworkTechnology(ServiceState.rilRadioTechnologyToNetworkType(
442                     mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_RAT,
443                     ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)));
444             ss.addNetworkRegistrationInfo(nri);
445             log("Override voice rat with " + ss.getRilVoiceRadioTechnology());
446         }
447         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_RAT)) {
448             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
449                     NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
450             if (nri == null) {
451                 nri = new NetworkRegistrationInfo.Builder()
452                         .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
453                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
454                         .build();
455             }
456             nri.setAccessNetworkTechnology(ServiceState.rilRadioTechnologyToNetworkType(
457                     mServiceStateTestIntent.getIntExtra(EXTRA_DATA_RAT,
458                     ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)));
459             ss.addNetworkRegistrationInfo(nri);
460             log("Override data rat with " + ss.getRilDataRadioTechnology());
461         }
462         if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_ROAMING_TYPE)) {
463             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
464                     NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
465             if (nri == null) {
466                 nri = new NetworkRegistrationInfo.Builder()
467                         .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
468                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
469                         .build();
470             }
471             nri.setRoamingType(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_ROAMING_TYPE,
472                     ServiceState.ROAMING_TYPE_UNKNOWN));
473             ss.addNetworkRegistrationInfo(nri);
474             log("Override voice roaming type with " + ss.getVoiceRoamingType());
475         }
476         if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_ROAMING_TYPE)) {
477             NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
478                     NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
479             if (nri == null) {
480                 nri = new NetworkRegistrationInfo.Builder()
481                         .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
482                         .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
483                         .build();
484             }
485             nri.setRoamingType(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_ROAMING_TYPE,
486                     ServiceState.ROAMING_TYPE_UNKNOWN));
487             ss.addNetworkRegistrationInfo(nri);
488             log("Override data roaming type with " + ss.getDataRoamingType());
489         }
490     }
491 
testImsECall()492     void testImsECall() {
493         // Attempt to get the active IMS call before parsing the test XML file.
494         ImsPhone imsPhone = (ImsPhone) mPhone;
495         if (imsPhone == null) {
496             return;
497         }
498 
499         ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
500         if (imsPhoneCall == null) {
501             return;
502         }
503 
504         ImsCall imsCall = imsPhoneCall.getImsCall();
505         if (imsCall == null) {
506             return;
507         }
508 
509         ImsCallProfile callProfile = imsCall.getCallProfile();
510         Bundle extras = callProfile.getCallExtras();
511         if (extras == null) {
512             extras = new Bundle();
513         }
514         extras.putBoolean(ImsCallProfile.EXTRA_EMERGENCY_CALL, true);
515         callProfile.mCallExtras = extras;
516         imsCall.getImsCallSessionListenerProxy().callSessionUpdated(imsCall.getSession(),
517                 callProfile);
518     }
519 
testChangeNumber(Intent intent)520     void testChangeNumber(Intent intent) {
521         if (!intent.hasExtra(EXTRA_NUMBER)) {
522             return;
523         }
524 
525         String newNumber = intent.getStringExtra(EXTRA_NUMBER);
526 
527         // Update all the calls.
528         mPhone.getForegroundCall().getConnections()
529                 .stream()
530                 .forEach(c -> {
531                     c.setAddress(newNumber, PhoneConstants.PRESENTATION_ALLOWED);
532                     c.setDialString(newNumber);
533                 });
534 
535         // <sigh>
536         if (mPhone instanceof GsmCdmaPhone) {
537             ((GsmCdmaPhone) mPhone).notifyPhoneStateChanged();
538             ((GsmCdmaPhone) mPhone).notifyPreciseCallStateChanged();
539         } else if (mPhone instanceof ImsPhone) {
540             ((ImsPhone) mPhone).notifyPhoneStateChanged();
541             ((ImsPhone) mPhone).notifyPreciseCallStateChanged();
542         }
543     }
544 }
545