1 /*
2  * Copyright (C) 2015 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 static com.android.internal.telephony.CommandException.Error.GENERIC_FAILURE;
20 import static com.android.internal.telephony.CommandException.Error.SIM_BUSY;
21 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
22 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
23 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
24 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
25 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
26 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
27 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
28 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
29 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
30 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
31 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
32 
33 import android.annotation.NonNull;
34 import android.annotation.Nullable;
35 import android.app.ActivityManager;
36 import android.compat.annotation.UnsupportedAppUsage;
37 import android.content.BroadcastReceiver;
38 import android.content.ContentValues;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.IntentFilter;
42 import android.content.SharedPreferences;
43 import android.database.SQLException;
44 import android.net.Uri;
45 import android.os.AsyncResult;
46 import android.os.Bundle;
47 import android.os.Handler;
48 import android.os.Message;
49 import android.os.PersistableBundle;
50 import android.os.PowerManager;
51 import android.os.Registrant;
52 import android.os.RegistrantList;
53 import android.os.ResultReceiver;
54 import android.os.SystemProperties;
55 import android.os.UserHandle;
56 import android.os.WorkSource;
57 import android.preference.PreferenceManager;
58 import android.provider.Settings;
59 import android.provider.Telephony;
60 import android.sysprop.TelephonyProperties;
61 import android.telecom.PhoneAccount;
62 import android.telecom.PhoneAccountHandle;
63 import android.telecom.TelecomManager;
64 import android.telecom.VideoProfile;
65 import android.telephony.AccessNetworkConstants;
66 import android.telephony.BarringInfo;
67 import android.telephony.CarrierConfigManager;
68 import android.telephony.CellIdentity;
69 import android.telephony.DataFailCause;
70 import android.telephony.ImsiEncryptionInfo;
71 import android.telephony.NetworkScanRequest;
72 import android.telephony.PhoneNumberUtils;
73 import android.telephony.PreciseDataConnectionState;
74 import android.telephony.ServiceState;
75 import android.telephony.ServiceState.RilRadioTechnology;
76 import android.telephony.SignalThresholdInfo;
77 import android.telephony.SubscriptionInfo;
78 import android.telephony.SubscriptionManager;
79 import android.telephony.TelephonyManager;
80 import android.telephony.UssdResponse;
81 import android.telephony.data.ApnSetting;
82 import android.text.TextUtils;
83 import android.util.Log;
84 import android.util.Pair;
85 
86 import com.android.ims.ImsManager;
87 import com.android.internal.annotations.VisibleForTesting;
88 import com.android.internal.telephony.CommandException;
89 import com.android.internal.telephony.cdma.CdmaMmiCode;
90 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
91 import com.android.internal.telephony.dataconnection.DataEnabledSettings;
92 import com.android.internal.telephony.dataconnection.DcTracker;
93 import com.android.internal.telephony.dataconnection.TransportManager;
94 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
95 import com.android.internal.telephony.gsm.GsmMmiCode;
96 import com.android.internal.telephony.gsm.SuppServiceNotification;
97 import com.android.internal.telephony.imsphone.ImsPhoneMmiCode;
98 import com.android.internal.telephony.metrics.VoiceCallSessionStats;
99 import com.android.internal.telephony.test.SimulatedRadioControl;
100 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
101 import com.android.internal.telephony.uicc.IccCardStatus;
102 import com.android.internal.telephony.uicc.IccException;
103 import com.android.internal.telephony.uicc.IccRecords;
104 import com.android.internal.telephony.uicc.IccUtils;
105 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
106 import com.android.internal.telephony.uicc.IsimRecords;
107 import com.android.internal.telephony.uicc.IsimUiccRecords;
108 import com.android.internal.telephony.uicc.RuimRecords;
109 import com.android.internal.telephony.uicc.SIMRecords;
110 import com.android.internal.telephony.uicc.UiccCard;
111 import com.android.internal.telephony.uicc.UiccCardApplication;
112 import com.android.internal.telephony.uicc.UiccController;
113 import com.android.internal.telephony.uicc.UiccProfile;
114 import com.android.internal.telephony.uicc.UiccSlot;
115 import com.android.internal.telephony.util.ArrayUtils;
116 import com.android.telephony.Rlog;
117 
118 import java.io.FileDescriptor;
119 import java.io.PrintWriter;
120 import java.util.ArrayList;
121 import java.util.Iterator;
122 import java.util.List;
123 import java.util.regex.Matcher;
124 import java.util.regex.Pattern;
125 
126 /**
127  * {@hide}
128  */
129 public class GsmCdmaPhone extends Phone {
130     // NOTE that LOG_TAG here is "GsmCdma", which means that log messages
131     // from this file will go into the radio log rather than the main
132     // log.  (Use "adb logcat -b radio" to see them.)
133     public static final String LOG_TAG = "GsmCdmaPhone";
134     private static final boolean DBG = true;
135     private static final boolean VDBG = false; /* STOPSHIP if true */
136 
137     /** Required magnitude change between unsolicited SignalStrength reports. */
138     private static final int REPORTING_HYSTERESIS_DB = 2;
139     /** Required throughput change between unsolicited LinkCapacityEstimate reports. */
140     private static final int REPORTING_HYSTERESIS_KBPS = 50;
141     /** Minimum time between unsolicited SignalStrength and LinkCapacityEstimate reports. */
142     private static final int REPORTING_HYSTERESIS_MILLIS = 3000;
143 
144     //GSM
145     // Key used to read/write voice mail number
146     private static final String VM_NUMBER = "vm_number_key";
147     // Key used to read/write the SIM IMSI used for storing the voice mail
148     private static final String VM_SIM_IMSI = "vm_sim_imsi_key";
149     /** List of Registrants to receive Supplementary Service Notifications. */
150     private RegistrantList mSsnRegistrants = new RegistrantList();
151 
152     //CDMA
153     // Default Emergency Callback Mode exit timer
154     private static final long DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
155     private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
156     public static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
157     public static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
158     private static final String PREFIX_WPS = "*272";
159     private CdmaSubscriptionSourceManager mCdmaSSM;
160     public int mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
161     private PowerManager.WakeLock mWakeLock;
162     // mEcmExitRespRegistrant is informed after the phone has been exited
163     @UnsupportedAppUsage
164     private Registrant mEcmExitRespRegistrant;
165     private String mEsn;
166     private String mMeid;
167     // string to define how the carrier specifies its own ota sp number
168     private String mCarrierOtaSpNumSchema;
169     private Boolean mUiccApplicationsEnabled = null;
170     // keeps track of when we have triggered an emergency call due to the ril.test.emergencynumber
171     // param being set and we should generate a simulated exit from the modem upon exit of ECbM.
172     private boolean mIsTestingEmergencyCallbackMode = false;
173     @VisibleForTesting
174     public static int ENABLE_UICC_APPS_MAX_RETRIES = 3;
175     private static final int REAPPLY_UICC_APPS_SETTING_RETRY_TIME_GAP_IN_MS = 5000;
176 
177     // A runnable which is used to automatically exit from Ecm after a period of time.
178     private Runnable mExitEcmRunnable = new Runnable() {
179         @Override
180         public void run() {
181             exitEmergencyCallbackMode();
182         }
183     };
184     public static final String PROPERTY_CDMA_HOME_OPERATOR_NUMERIC =
185             "ro.cdma.home.operator.numeric";
186 
187     //CDMALTE
188     /** PHONE_TYPE_CDMA_LTE in addition to RuimRecords needs access to SIMRecords and
189      * IsimUiccRecords
190      */
191     private SIMRecords mSimRecords;
192 
193     //Common
194     // Instance Variables
195     @UnsupportedAppUsage
196     private IsimUiccRecords mIsimUiccRecords;
197     @UnsupportedAppUsage
198     public GsmCdmaCallTracker mCT;
199     @UnsupportedAppUsage
200     public ServiceStateTracker mSST;
201     public EmergencyNumberTracker mEmergencyNumberTracker;
202     @UnsupportedAppUsage
203     private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
204     private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
205 
206     private int mPrecisePhoneType;
207 
208     // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
209     private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
210 
211     private final RegistrantList mVolteSilentRedialRegistrants = new RegistrantList();
212     private DialArgs mDialArgs = null;
213 
214     private String mImei;
215     private String mImeiSv;
216     private String mVmNumber;
217 
218     // Create Cfu (Call forward unconditional) so that dialing number &
219     // mOnComplete (Message object passed by client) can be packed &
220     // given as a single Cfu object as user data to RIL.
221     private static class Cfu {
222         final String mSetCfNumber;
223         final Message mOnComplete;
224 
225         @UnsupportedAppUsage
Cfu(String cfNumber, Message onComplete)226         Cfu(String cfNumber, Message onComplete) {
227             mSetCfNumber = cfNumber;
228             mOnComplete = onComplete;
229         }
230     }
231 
232     @UnsupportedAppUsage
233     private IccSmsInterfaceManager mIccSmsInterfaceManager;
234 
235     private boolean mResetModemOnRadioTechnologyChange = false;
236 
237     private int mRilVersion;
238     private boolean mBroadcastEmergencyCallStateChanges = false;
239     private CarrierKeyDownloadManager mCDM;
240     private CarrierInfoManager mCIM;
241 
242     private final SettingsObserver mSettingsObserver;
243 
244     // Constructors
245 
GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory)246     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId,
247                         int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) {
248         this(context, ci, notifier, false, phoneId, precisePhoneType, telephonyComponentFactory);
249     }
250 
GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory)251     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
252                         boolean unitTestMode, int phoneId, int precisePhoneType,
253                         TelephonyComponentFactory telephonyComponentFactory) {
254         super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA",
255                 notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory);
256 
257         // phone type needs to be set before other initialization as other objects rely on it
258         mPrecisePhoneType = precisePhoneType;
259         mVoiceCallSessionStats = new VoiceCallSessionStats(mPhoneId, this);
260         initOnce(ci);
261         initRatSpecific(precisePhoneType);
262         // CarrierSignalAgent uses CarrierActionAgent in construction so it needs to be created
263         // after CarrierActionAgent.
264         mCarrierActionAgent = mTelephonyComponentFactory.inject(CarrierActionAgent.class.getName())
265                 .makeCarrierActionAgent(this);
266         mCarrierSignalAgent = mTelephonyComponentFactory.inject(CarrierSignalAgent.class.getName())
267                 .makeCarrierSignalAgent(this);
268         mTransportManager = mTelephonyComponentFactory.inject(TransportManager.class.getName())
269                 .makeTransportManager(this);
270         mSST = mTelephonyComponentFactory.inject(ServiceStateTracker.class.getName())
271                 .makeServiceStateTracker(this, this.mCi);
272         mEmergencyNumberTracker = mTelephonyComponentFactory
273                 .inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker(
274                 this, this.mCi);
275         mDataEnabledSettings = mTelephonyComponentFactory
276                 .inject(DataEnabledSettings.class.getName()).makeDataEnabledSettings(this);
277         mDeviceStateMonitor = mTelephonyComponentFactory.inject(DeviceStateMonitor.class.getName())
278                 .makeDeviceStateMonitor(this);
279 
280         // DisplayInfoController creates an OverrideNetworkTypeController, which uses
281         // DeviceStateMonitor so needs to be crated after it is instantiated.
282         mDisplayInfoController = mTelephonyComponentFactory.inject(
283                 DisplayInfoController.class.getName()).makeDisplayInfoController(this);
284 
285         // DcTracker uses ServiceStateTracker and DisplayInfoController so needs to be created
286         // after they are instantiated
287         for (int transport : mTransportManager.getAvailableTransports()) {
288             mDcTrackers.put(transport, mTelephonyComponentFactory.inject(DcTracker.class.getName())
289                     .makeDcTracker(this, transport));
290         }
291 
292         mCarrierResolver = mTelephonyComponentFactory.inject(CarrierResolver.class.getName())
293                 .makeCarrierResolver(this);
294 
295         getCarrierActionAgent().registerForCarrierAction(
296                 CarrierActionAgent.CARRIER_ACTION_SET_METERED_APNS_ENABLED, this,
297                 EVENT_SET_CARRIER_DATA_ENABLED, null, false);
298 
299         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
300         mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null);
301 
302         mSettingsObserver = new SettingsObserver(context, this);
303         mSettingsObserver.observe(
304                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
305                 EVENT_DEVICE_PROVISIONED_CHANGE);
306         mSettingsObserver.observe(
307                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED),
308                 EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE);
309 
310         SubscriptionController.getInstance().registerForUiccAppsEnabled(this,
311                 EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false);
312 
313         loadTtyMode();
314         logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
315     }
316 
317     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
318         @Override
319         public void onReceive(Context context, Intent intent) {
320             Rlog.d(LOG_TAG, "mBroadcastReceiver: action " + intent.getAction());
321             String action = intent.getAction();
322             if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) {
323                 // Only handle carrier config changes for this phone id.
324                 if (mPhoneId == intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, -1)) {
325                     sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED));
326                 }
327             } else if (TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED.equals(action)) {
328                 int ttyMode = intent.getIntExtra(
329                         TelecomManager.EXTRA_CURRENT_TTY_MODE, TelecomManager.TTY_MODE_OFF);
330                 updateTtyMode(ttyMode);
331             } else if (TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED.equals(action)) {
332                 int newPreferredTtyMode = intent.getIntExtra(
333                         TelecomManager.EXTRA_TTY_PREFERRED_MODE, TelecomManager.TTY_MODE_OFF);
334                 updateUiTtyMode(newPreferredTtyMode);
335             }
336         }
337     };
338 
initOnce(CommandsInterface ci)339     private void initOnce(CommandsInterface ci) {
340         if (ci instanceof SimulatedRadioControl) {
341             mSimulatedRadioControl = (SimulatedRadioControl) ci;
342         }
343 
344         mCT = mTelephonyComponentFactory.inject(GsmCdmaCallTracker.class.getName())
345                 .makeGsmCdmaCallTracker(this);
346         mIccPhoneBookIntManager = mTelephonyComponentFactory
347                 .inject(IccPhoneBookInterfaceManager.class.getName())
348                 .makeIccPhoneBookInterfaceManager(this);
349         PowerManager pm
350                 = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
351         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
352         mIccSmsInterfaceManager = mTelephonyComponentFactory
353                 .inject(IccSmsInterfaceManager.class.getName())
354                 .makeIccSmsInterfaceManager(this);
355 
356         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
357         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
358         mCi.registerForOn(this, EVENT_RADIO_ON, null);
359         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
360         mCi.registerUiccApplicationEnablementChanged(this,
361                 EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED,
362                 null);
363         mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
364         mCi.setOnRegistrationFailed(this, EVENT_REGISTRATION_FAILED, null);
365         mCi.registerForBarringInfoChanged(this, EVENT_BARRING_INFO_CHANGED, null);
366 
367         //GSM
368         mCi.setOnUSSD(this, EVENT_USSD, null);
369         mCi.setOnSs(this, EVENT_SS, null);
370 
371         //CDMA
372         mCdmaSSM = mTelephonyComponentFactory.inject(CdmaSubscriptionSourceManager.class.getName())
373                 .getCdmaSubscriptionSourceManagerInstance(mContext,
374                 mCi, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
375         mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
376         mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE,
377                 null);
378         mCi.registerForModemReset(this, EVENT_MODEM_RESET, null);
379         // get the string that specifies the carrier OTA Sp number
380         mCarrierOtaSpNumSchema = TelephonyManager.from(mContext).getOtaSpNumberSchemaForPhone(
381                 getPhoneId(), "");
382 
383         mResetModemOnRadioTechnologyChange = TelephonyProperties.reset_on_radio_tech_change()
384                 .orElse(false);
385 
386         mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
387         mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
388         IntentFilter filter = new IntentFilter(
389                 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
390         filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
391         filter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
392         mContext.registerReceiver(mBroadcastReceiver, filter);
393 
394         mCDM = new CarrierKeyDownloadManager(this);
395         mCIM = new CarrierInfoManager();
396     }
397 
initRatSpecific(int precisePhoneType)398     private void initRatSpecific(int precisePhoneType) {
399         mPendingMMIs.clear();
400         mIccPhoneBookIntManager.updateIccRecords(null);
401         mEsn = null;
402         mMeid = null;
403 
404         mPrecisePhoneType = precisePhoneType;
405         logd("Precise phone type " + mPrecisePhoneType);
406 
407         TelephonyManager tm = TelephonyManager.from(mContext);
408         UiccProfile uiccProfile = getUiccProfile();
409         if (isPhoneTypeGsm()) {
410             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
411             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_GSM);
412             if (uiccProfile != null) {
413                 uiccProfile.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
414             }
415         } else {
416             mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
417             // This is needed to handle phone process crashes
418             mIsPhoneInEcmState = getInEcmMode();
419             if (mIsPhoneInEcmState) {
420                 // Send a message which will invoke handleExitEmergencyCallbackMode
421                 mCi.exitEmergencyCallbackMode(null);
422             }
423 
424             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
425             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_CDMA);
426             if (uiccProfile != null) {
427                 uiccProfile.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
428             }
429             // Sets operator properties by retrieving from build-time system property
430             String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
431             String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
432             logd("init: operatorAlpha='" + operatorAlpha
433                     + "' operatorNumeric='" + operatorNumeric + "'");
434             if (!TextUtils.isEmpty(operatorAlpha)) {
435                 logd("init: set 'gsm.sim.operator.alpha' to operator='" + operatorAlpha + "'");
436                 tm.setSimOperatorNameForPhone(mPhoneId, operatorAlpha);
437             }
438             if (!TextUtils.isEmpty(operatorNumeric)) {
439                 logd("init: set 'gsm.sim.operator.numeric' to operator='" + operatorNumeric +
440                         "'");
441                 logd("update icc_operator_numeric=" + operatorNumeric);
442                 tm.setSimOperatorNumericForPhone(mPhoneId, operatorNumeric);
443 
444                 SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId());
445 
446                 // Sets iso country property by retrieving from build-time system property
447                 String iso = "";
448                 try {
449                     iso = MccTable.countryCodeForMcc(operatorNumeric.substring(0, 3));
450                 } catch (StringIndexOutOfBoundsException ex) {
451                     Rlog.e(LOG_TAG, "init: countryCodeForMcc error", ex);
452                 }
453 
454                 logd("init: set 'gsm.sim.operator.iso-country' to iso=" + iso);
455                 tm.setSimCountryIsoForPhone(mPhoneId, iso);
456                 SubscriptionController.getInstance().setCountryIso(iso, getSubId());
457 
458                 // Updates MCC MNC device configuration information
459                 logd("update mccmnc=" + operatorNumeric);
460                 MccTable.updateMccMncConfiguration(mContext, operatorNumeric);
461             }
462 
463             // Sets current entry in the telephony carrier table
464             updateCurrentCarrierInProvider(operatorNumeric);
465         }
466     }
467 
468     @UnsupportedAppUsage
isPhoneTypeGsm()469     public boolean isPhoneTypeGsm() {
470         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM;
471     }
472 
isPhoneTypeCdma()473     public boolean isPhoneTypeCdma() {
474         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA;
475     }
476 
isPhoneTypeCdmaLte()477     public boolean isPhoneTypeCdmaLte() {
478         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA_LTE;
479     }
480 
switchPhoneType(int precisePhoneType)481     private void switchPhoneType(int precisePhoneType) {
482         removeCallbacks(mExitEcmRunnable);
483 
484         initRatSpecific(precisePhoneType);
485 
486         mSST.updatePhoneType();
487         setPhoneName(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA");
488         onUpdateIccAvailability();
489         // if is possible that onUpdateIccAvailability() does not unregister and re-register for
490         // ICC events, for example if mUiccApplication does not change which can happen if phone
491         // type is transitioning from CDMA to GSM but 3gpp2 application was not available.
492         // To handle such cases, unregister and re-register here. They still need to be called in
493         // onUpdateIccAvailability(), since in normal cases register/unregister calls can be on
494         // different IccRecords objects. Here they are on the same IccRecords object.
495         unregisterForIccRecordEvents();
496         registerForIccRecordEvents();
497 
498         mCT.updatePhoneType();
499 
500         int radioState = mCi.getRadioState();
501         if (radioState != TelephonyManager.RADIO_POWER_UNAVAILABLE) {
502             handleRadioAvailable();
503             if (radioState == TelephonyManager.RADIO_POWER_ON) {
504                 handleRadioOn();
505             }
506         }
507         if (radioState != TelephonyManager.RADIO_POWER_ON) {
508             handleRadioOffOrNotAvailable();
509         }
510     }
511 
512     @Override
finalize()513     protected void finalize() {
514         if(DBG) logd("GsmCdmaPhone finalized");
515         if (mWakeLock != null && mWakeLock.isHeld()) {
516             Rlog.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
517             mWakeLock.release();
518         }
519     }
520 
521     @UnsupportedAppUsage
522     @Override
523     @NonNull
getServiceState()524     public ServiceState getServiceState() {
525         if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) {
526             if (mImsPhone != null) {
527                 return mergeServiceStates((mSST == null) ? new ServiceState() : mSST.mSS,
528                         mImsPhone.getServiceState());
529             }
530         }
531 
532         if (mSST != null) {
533             return mSST.mSS;
534         } else {
535             // avoid potential NPE in EmergencyCallHelper during Phone switch
536             return new ServiceState();
537         }
538     }
539 
540     @Override
getCellIdentity(WorkSource workSource, Message rspMsg)541     public void getCellIdentity(WorkSource workSource, Message rspMsg) {
542         mSST.requestCellIdentity(workSource, rspMsg);
543     }
544 
545     @UnsupportedAppUsage
546     @Override
getState()547     public PhoneConstants.State getState() {
548         if (mImsPhone != null) {
549             PhoneConstants.State imsState = mImsPhone.getState();
550             if (imsState != PhoneConstants.State.IDLE) {
551                 return imsState;
552             }
553         }
554 
555         return mCT.mState;
556     }
557 
558     @UnsupportedAppUsage
559     @Override
getPhoneType()560     public int getPhoneType() {
561         if (mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM) {
562             return PhoneConstants.PHONE_TYPE_GSM;
563         } else {
564             return PhoneConstants.PHONE_TYPE_CDMA;
565         }
566     }
567 
568     @Override
getServiceStateTracker()569     public ServiceStateTracker getServiceStateTracker() {
570         return mSST;
571     }
572 
573     @Override
getEmergencyNumberTracker()574     public EmergencyNumberTracker getEmergencyNumberTracker() {
575         return mEmergencyNumberTracker;
576     }
577 
578     @UnsupportedAppUsage
579     @Override
getCallTracker()580     public CallTracker getCallTracker() {
581         return mCT;
582     }
583 
584     @Override
getTransportManager()585     public TransportManager getTransportManager() {
586         return mTransportManager;
587     }
588 
589     @Override
getDeviceStateMonitor()590     public DeviceStateMonitor getDeviceStateMonitor() {
591         return mDeviceStateMonitor;
592     }
593 
594     @Override
getDisplayInfoController()595     public DisplayInfoController getDisplayInfoController() {
596         return mDisplayInfoController;
597     }
598 
599     @Override
updateVoiceMail()600     public void updateVoiceMail() {
601         if (isPhoneTypeGsm()) {
602             int countVoiceMessages = 0;
603             IccRecords r = mIccRecords.get();
604             if (r != null) {
605                 // get voice mail count from SIM
606                 countVoiceMessages = r.getVoiceMessageCount();
607             }
608             if (countVoiceMessages == IccRecords.DEFAULT_VOICE_MESSAGE_COUNT) {
609                 countVoiceMessages = getStoredVoiceMessageCount();
610             }
611             logd("updateVoiceMail countVoiceMessages = " + countVoiceMessages
612                     + " subId " + getSubId());
613             setVoiceMessageCount(countVoiceMessages);
614         } else {
615             setVoiceMessageCount(getStoredVoiceMessageCount());
616         }
617     }
618 
619     @Override
620     public List<? extends MmiCode>
getPendingMmiCodes()621     getPendingMmiCodes() {
622         return mPendingMMIs;
623     }
624 
getActiveDcTrackerForApn(@onNull String apnType)625     private @NonNull DcTracker getActiveDcTrackerForApn(@NonNull String apnType) {
626         int currentTransport = mTransportManager.getCurrentTransport(
627                 ApnSetting.getApnTypesBitmaskFromString(apnType));
628         return getDcTracker(currentTransport);
629     }
630 
631     @Override
getPreciseDataConnectionState(String apnType)632     public PreciseDataConnectionState getPreciseDataConnectionState(String apnType) {
633         // If we are OOS, then all data connections are null.
634         // FIXME: we need to figure out how to report the EIMS PDN connectivity here, which
635         // should imply emergency attach - today emergency attach is unknown at the AP,
636         // so, we take a guess.
637         boolean isEmergencyData = isPhoneTypeGsm()
638                 && apnType.equals(PhoneConstants.APN_TYPE_EMERGENCY);
639 
640         if (mSST == null
641                 || ((mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE)
642                         && !isEmergencyData)) {
643             return new PreciseDataConnectionState(TelephonyManager.DATA_DISCONNECTED,
644                     TelephonyManager.NETWORK_TYPE_UNKNOWN,
645                     ApnSetting.getApnTypesBitmaskFromString(apnType),
646                     apnType, null, DataFailCause.NONE, null);
647         }
648 
649         // must never be null
650         final DcTracker dctForApn = getActiveDcTrackerForApn(apnType);
651 
652         int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
653         // Always non-null
654         ServiceState ss = getServiceState();
655         if (ss != null) {
656             networkType = ss.getDataNetworkType();
657         }
658 
659         return dctForApn.getPreciseDataConnectionState(apnType, isDataSuspended(), networkType);
660     }
661 
isDataSuspended()662     boolean isDataSuspended() {
663         return mCT.mState != PhoneConstants.State.IDLE && !mSST.isConcurrentVoiceAndDataAllowed();
664     }
665 
666     @Override
getDataConnectionState(String apnType)667     public PhoneConstants.DataState getDataConnectionState(String apnType) {
668         PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED;
669 
670         if (mSST == null) {
671             // Radio Technology Change is ongoing, dispose() and removeReferences() have
672             // already been called
673 
674             ret = PhoneConstants.DataState.DISCONNECTED;
675         } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE
676                 && (isPhoneTypeCdma() || isPhoneTypeCdmaLte() ||
677                 (isPhoneTypeGsm() && !apnType.equals(PhoneConstants.APN_TYPE_EMERGENCY)))) {
678             // If we're out of service, open TCP sockets may still work
679             // but no data will flow
680 
681             // Emergency APN is available even in Out Of Service
682             // Pass the actual State of EPDN
683 
684             ret = PhoneConstants.DataState.DISCONNECTED;
685         } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */
686             int currentTransport = mTransportManager.getCurrentTransport(
687                     ApnSetting.getApnTypesBitmaskFromString(apnType));
688             if (getDcTracker(currentTransport) != null) {
689                 switch (getDcTracker(currentTransport).getState(apnType)) {
690                     case CONNECTED:
691                     case DISCONNECTING:
692                         if (isDataSuspended()) {
693                             ret = PhoneConstants.DataState.SUSPENDED;
694                         } else {
695                             ret = PhoneConstants.DataState.CONNECTED;
696                         }
697                         break;
698                     case CONNECTING:
699                         ret = PhoneConstants.DataState.CONNECTING;
700                         break;
701                     default:
702                         ret = PhoneConstants.DataState.DISCONNECTED;
703                 }
704             }
705         }
706 
707         logd("getDataConnectionState apnType=" + apnType + " ret=" + ret);
708         return ret;
709     }
710 
711     @Override
getDataActivityState()712     public DataActivityState getDataActivityState() {
713         DataActivityState ret = DataActivityState.NONE;
714 
715         if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE
716                 && getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) {
717             switch (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getActivity()) {
718                 case DATAIN:
719                     ret = DataActivityState.DATAIN;
720                 break;
721 
722                 case DATAOUT:
723                     ret = DataActivityState.DATAOUT;
724                 break;
725 
726                 case DATAINANDOUT:
727                     ret = DataActivityState.DATAINANDOUT;
728                 break;
729 
730                 case DORMANT:
731                     ret = DataActivityState.DORMANT;
732                 break;
733 
734                 default:
735                     ret = DataActivityState.NONE;
736                 break;
737             }
738         }
739 
740         return ret;
741     }
742 
743     /**
744      * Notify any interested party of a Phone state change
745      * {@link com.android.internal.telephony.PhoneConstants.State}
746      */
notifyPhoneStateChanged()747     public void notifyPhoneStateChanged() {
748         mNotifier.notifyPhoneState(this);
749     }
750 
751     /**
752      * Notify registrants of a change in the call state. This notifies changes in
753      * {@link com.android.internal.telephony.Call.State}. Use this when changes
754      * in the precise call state are needed, else use notifyPhoneStateChanged.
755      */
756     @UnsupportedAppUsage
notifyPreciseCallStateChanged()757     public void notifyPreciseCallStateChanged() {
758         /* we'd love it if this was package-scoped*/
759         super.notifyPreciseCallStateChangedP();
760     }
761 
notifyNewRingingConnection(Connection c)762     public void notifyNewRingingConnection(Connection c) {
763         super.notifyNewRingingConnectionP(c);
764     }
765 
notifyDisconnect(Connection cn)766     public void notifyDisconnect(Connection cn) {
767         mDisconnectRegistrants.notifyResult(cn);
768 
769         mNotifier.notifyDisconnectCause(this, cn.getDisconnectCause(),
770                 cn.getPreciseDisconnectCause());
771     }
772 
notifyUnknownConnection(Connection cn)773     public void notifyUnknownConnection(Connection cn) {
774         super.notifyUnknownConnectionP(cn);
775     }
776 
777     @Override
isInEmergencyCall()778     public boolean isInEmergencyCall() {
779         if (isPhoneTypeGsm()) {
780             return false;
781         } else {
782             return mCT.isInEmergencyCall();
783         }
784     }
785 
786     @Override
setIsInEmergencyCall()787     protected void setIsInEmergencyCall() {
788         if (!isPhoneTypeGsm()) {
789             mCT.setIsInEmergencyCall();
790         }
791     }
792 
793     @Override
isInEmergencySmsMode()794     public boolean isInEmergencySmsMode() {
795         return super.isInEmergencySmsMode()
796                 || (mImsPhone != null && mImsPhone.isInEmergencySmsMode());
797     }
798 
799     //CDMA
sendEmergencyCallbackModeChange()800     private void sendEmergencyCallbackModeChange(){
801         //Send an Intent
802         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
803         intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, isInEcm());
804         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
805         ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
806         logi("sendEmergencyCallbackModeChange");
807     }
808 
809     @Override
sendEmergencyCallStateChange(boolean callActive)810     public void sendEmergencyCallStateChange(boolean callActive) {
811         if (!isPhoneTypeCdma()) {
812             // It possible that this method got called from ImsPhoneCallTracker#
813             logi("sendEmergencyCallStateChange - skip for non-cdma");
814             return;
815         }
816         if (mBroadcastEmergencyCallStateChanges) {
817             Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
818             intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, callActive);
819             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
820             ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
821             if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: callActive " + callActive);
822         }
823     }
824 
825     @Override
setBroadcastEmergencyCallStateChanges(boolean broadcast)826     public void setBroadcastEmergencyCallStateChanges(boolean broadcast) {
827         mBroadcastEmergencyCallStateChanges = broadcast;
828     }
829 
notifySuppServiceFailed(SuppService code)830     public void notifySuppServiceFailed(SuppService code) {
831         mSuppServiceFailedRegistrants.notifyResult(code);
832     }
833 
834     @UnsupportedAppUsage
notifyServiceStateChanged(ServiceState ss)835     public void notifyServiceStateChanged(ServiceState ss) {
836         super.notifyServiceStateChangedP(ss);
837     }
838 
839     /**
840      * Notify that the cell location has changed.
841      *
842      * @param cellIdentity the new CellIdentity
843      */
notifyLocationChanged(CellIdentity cellIdentity)844     public void notifyLocationChanged(CellIdentity cellIdentity) {
845         mNotifier.notifyCellLocation(this, cellIdentity);
846     }
847 
848     @Override
notifyCallForwardingIndicator()849     public void notifyCallForwardingIndicator() {
850         mNotifier.notifyCallForwardingChanged(this);
851     }
852 
853     @Override
registerForSuppServiceNotification( Handler h, int what, Object obj)854     public void registerForSuppServiceNotification(
855             Handler h, int what, Object obj) {
856         mSsnRegistrants.addUnique(h, what, obj);
857         if (mSsnRegistrants.size() == 1) mCi.setSuppServiceNotifications(true, null);
858     }
859 
860     @Override
unregisterForSuppServiceNotification(Handler h)861     public void unregisterForSuppServiceNotification(Handler h) {
862         mSsnRegistrants.remove(h);
863         if (mSsnRegistrants.size() == 0) mCi.setSuppServiceNotifications(false, null);
864     }
865 
866     @Override
registerForSimRecordsLoaded(Handler h, int what, Object obj)867     public void registerForSimRecordsLoaded(Handler h, int what, Object obj) {
868         mSimRecordsLoadedRegistrants.addUnique(h, what, obj);
869     }
870 
871     @Override
unregisterForSimRecordsLoaded(Handler h)872     public void unregisterForSimRecordsLoaded(Handler h) {
873         mSimRecordsLoadedRegistrants.remove(h);
874     }
875 
876     @Override
acceptCall(int videoState)877     public void acceptCall(int videoState) throws CallStateException {
878         Phone imsPhone = mImsPhone;
879         if ( imsPhone != null && imsPhone.getRingingCall().isRinging() ) {
880             imsPhone.acceptCall(videoState);
881         } else {
882             mCT.acceptCall();
883         }
884     }
885 
886     @Override
rejectCall()887     public void rejectCall() throws CallStateException {
888         mCT.rejectCall();
889     }
890 
891     @Override
switchHoldingAndActive()892     public void switchHoldingAndActive() throws CallStateException {
893         mCT.switchWaitingOrHoldingAndActive();
894     }
895 
896     @Override
getIccSerialNumber()897     public String getIccSerialNumber() {
898         IccRecords r = mIccRecords.get();
899         if (!isPhoneTypeGsm() && r == null) {
900             // to get ICCID form SIMRecords because it is on MF.
901             r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP);
902         }
903         return (r != null) ? r.getIccId() : null;
904     }
905 
906     @Override
getFullIccSerialNumber()907     public String getFullIccSerialNumber() {
908         IccRecords r = mIccRecords.get();
909         if (!isPhoneTypeGsm() && r == null) {
910             // to get ICCID form SIMRecords because it is on MF.
911             r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP);
912         }
913         return (r != null) ? r.getFullIccId() : null;
914     }
915 
916     @Override
canConference()917     public boolean canConference() {
918         if (mImsPhone != null && mImsPhone.canConference()) {
919             return true;
920         }
921         if (isPhoneTypeGsm()) {
922             return mCT.canConference();
923         } else {
924             loge("canConference: not possible in CDMA");
925             return false;
926         }
927     }
928 
929     @Override
conference()930     public void conference() {
931         if (mImsPhone != null && mImsPhone.canConference()) {
932             logd("conference() - delegated to IMS phone");
933             try {
934                 mImsPhone.conference();
935             } catch (CallStateException e) {
936                 loge(e.toString());
937             }
938             return;
939         }
940         if (isPhoneTypeGsm()) {
941             mCT.conference();
942         } else {
943             // three way calls in CDMA will be handled by feature codes
944             loge("conference: not possible in CDMA");
945         }
946     }
947 
948     @Override
dispose()949     public void dispose() {
950         // Note: this API is currently never called. We are defining actions here in case
951         // we need to dispose GsmCdmaPhone/Phone object.
952         super.dispose();
953         SubscriptionController.getInstance().unregisterForUiccAppsEnabled(this);
954     }
955 
956     @Override
enableEnhancedVoicePrivacy(boolean enable, Message onComplete)957     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
958         if (isPhoneTypeGsm()) {
959             loge("enableEnhancedVoicePrivacy: not expected on GSM");
960         } else {
961             mCi.setPreferredVoicePrivacy(enable, onComplete);
962         }
963     }
964 
965     @Override
getEnhancedVoicePrivacy(Message onComplete)966     public void getEnhancedVoicePrivacy(Message onComplete) {
967         if (isPhoneTypeGsm()) {
968             loge("getEnhancedVoicePrivacy: not expected on GSM");
969         } else {
970             mCi.getPreferredVoicePrivacy(onComplete);
971         }
972     }
973 
974     @Override
clearDisconnected()975     public void clearDisconnected() {
976         mCT.clearDisconnected();
977     }
978 
979     @Override
canTransfer()980     public boolean canTransfer() {
981         if (isPhoneTypeGsm()) {
982             return mCT.canTransfer();
983         } else {
984             loge("canTransfer: not possible in CDMA");
985             return false;
986         }
987     }
988 
989     @Override
explicitCallTransfer()990     public void explicitCallTransfer() {
991         if (isPhoneTypeGsm()) {
992             mCT.explicitCallTransfer();
993         } else {
994             loge("explicitCallTransfer: not possible in CDMA");
995         }
996     }
997 
998     @Override
getForegroundCall()999     public GsmCdmaCall getForegroundCall() {
1000         return mCT.mForegroundCall;
1001     }
1002 
1003     @Override
getBackgroundCall()1004     public GsmCdmaCall getBackgroundCall() {
1005         return mCT.mBackgroundCall;
1006     }
1007 
1008     @Override
getRingingCall()1009     public Call getRingingCall() {
1010         Phone imsPhone = mImsPhone;
1011         // It returns the ringing call of ImsPhone if the ringing call of GSMPhone isn't ringing.
1012         // In CallManager.registerPhone(), it always registers ringing call of ImsPhone, because
1013         // the ringing call of GSMPhone isn't ringing. Consequently, it can't answer GSM call
1014         // successfully by invoking TelephonyManager.answerRingingCall() since the implementation
1015         // in PhoneInterfaceManager.answerRingingCallInternal() could not get the correct ringing
1016         // call from CallManager. So we check the ringing call state of imsPhone first as
1017         // accpetCall() does.
1018         if ( imsPhone != null && imsPhone.getRingingCall().isRinging()) {
1019             return imsPhone.getRingingCall();
1020         }
1021         //It returns the ringing connections which during SRVCC handover
1022         if (!mCT.mRingingCall.isRinging()
1023                 && mCT.getRingingHandoverConnection() != null
1024                 && mCT.getRingingHandoverConnection().getCall() != null
1025                 && mCT.getRingingHandoverConnection().getCall().isRinging()) {
1026             return mCT.getRingingHandoverConnection().getCall();
1027         }
1028         return mCT.mRingingCall;
1029     }
1030 
1031     /**
1032      * ImsService reports "IN_SERVICE" for its voice registration state even if the device
1033      * has lost the physical link to the tower. This helper method merges the IMS and modem
1034      * ServiceState, only overriding the voice registration state when we are registered to IMS. In
1035      * this case the voice registration state may be "OUT_OF_SERVICE", so override the voice
1036      * registration state with the data registration state.
1037      */
mergeServiceStates(ServiceState baseSs, ServiceState imsSs)1038     private ServiceState mergeServiceStates(ServiceState baseSs, ServiceState imsSs) {
1039         // No need to merge states if the baseSs is IN_SERVICE.
1040         if (baseSs.getState() == ServiceState.STATE_IN_SERVICE) {
1041             return baseSs;
1042         }
1043         // "IN_SERVICE" in this case means IMS is registered.
1044         if (imsSs.getState() != ServiceState.STATE_IN_SERVICE) {
1045             return baseSs;
1046         }
1047 
1048         ServiceState newSs = new ServiceState(baseSs);
1049         // Voice override for IMS case. In this case, voice registration is OUT_OF_SERVICE, but
1050         // IMS is available, so use data registration state as a basis for determining
1051         // whether or not the physical link is available.
1052         newSs.setVoiceRegState(baseSs.getDataRegistrationState());
1053         newSs.setEmergencyOnly(false); // only get here if voice is IN_SERVICE
1054         return newSs;
1055     }
1056 
handleCallDeflectionIncallSupplementaryService( String dialString)1057     private boolean handleCallDeflectionIncallSupplementaryService(
1058             String dialString) {
1059         if (dialString.length() > 1) {
1060             return false;
1061         }
1062 
1063         if (getRingingCall().getState() != GsmCdmaCall.State.IDLE) {
1064             if (DBG) logd("MmiCode 0: rejectCall");
1065             try {
1066                 mCT.rejectCall();
1067             } catch (CallStateException e) {
1068                 if (DBG) Rlog.d(LOG_TAG,
1069                         "reject failed", e);
1070                 notifySuppServiceFailed(Phone.SuppService.REJECT);
1071             }
1072         } else if (getBackgroundCall().getState() != GsmCdmaCall.State.IDLE) {
1073             if (DBG) logd("MmiCode 0: hangupWaitingOrBackground");
1074             mCT.hangupWaitingOrBackground();
1075         }
1076 
1077         return true;
1078     }
1079 
1080     //GSM
handleCallWaitingIncallSupplementaryService(String dialString)1081     private boolean handleCallWaitingIncallSupplementaryService(String dialString) {
1082         int len = dialString.length();
1083 
1084         if (len > 2) {
1085             return false;
1086         }
1087 
1088         GsmCdmaCall call = getForegroundCall();
1089 
1090         try {
1091             if (len > 1) {
1092                 char ch = dialString.charAt(1);
1093                 int callIndex = ch - '0';
1094 
1095                 if (callIndex >= 1 && callIndex <= GsmCdmaCallTracker.MAX_CONNECTIONS_GSM) {
1096                     if (DBG) logd("MmiCode 1: hangupConnectionByIndex " + callIndex);
1097                     mCT.hangupConnectionByIndex(call, callIndex);
1098                 }
1099             } else {
1100                 if (call.getState() != GsmCdmaCall.State.IDLE) {
1101                     if (DBG) logd("MmiCode 1: hangup foreground");
1102                     //mCT.hangupForegroundResumeBackground();
1103                     mCT.hangup(call);
1104                 } else {
1105                     if (DBG) logd("MmiCode 1: switchWaitingOrHoldingAndActive");
1106                     mCT.switchWaitingOrHoldingAndActive();
1107                 }
1108             }
1109         } catch (CallStateException e) {
1110             if (DBG) Rlog.d(LOG_TAG,
1111                     "hangup failed", e);
1112             notifySuppServiceFailed(Phone.SuppService.HANGUP);
1113         }
1114 
1115         return true;
1116     }
1117 
handleCallHoldIncallSupplementaryService(String dialString)1118     private boolean handleCallHoldIncallSupplementaryService(String dialString) {
1119         int len = dialString.length();
1120 
1121         if (len > 2) {
1122             return false;
1123         }
1124 
1125         GsmCdmaCall call = getForegroundCall();
1126 
1127         if (len > 1) {
1128             try {
1129                 char ch = dialString.charAt(1);
1130                 int callIndex = ch - '0';
1131                 GsmCdmaConnection conn = mCT.getConnectionByIndex(call, callIndex);
1132 
1133                 // GsmCdma index starts at 1, up to 5 connections in a call,
1134                 if (conn != null && callIndex >= 1 && callIndex <= GsmCdmaCallTracker.MAX_CONNECTIONS_GSM) {
1135                     if (DBG) logd("MmiCode 2: separate call " + callIndex);
1136                     mCT.separate(conn);
1137                 } else {
1138                     if (DBG) logd("separate: invalid call index " + callIndex);
1139                     notifySuppServiceFailed(Phone.SuppService.SEPARATE);
1140                 }
1141             } catch (CallStateException e) {
1142                 if (DBG) Rlog.d(LOG_TAG, "separate failed", e);
1143                 notifySuppServiceFailed(Phone.SuppService.SEPARATE);
1144             }
1145         } else {
1146             try {
1147                 if (getRingingCall().getState() != GsmCdmaCall.State.IDLE) {
1148                     if (DBG) logd("MmiCode 2: accept ringing call");
1149                     mCT.acceptCall();
1150                 } else {
1151                     if (DBG) logd("MmiCode 2: switchWaitingOrHoldingAndActive");
1152                     mCT.switchWaitingOrHoldingAndActive();
1153                 }
1154             } catch (CallStateException e) {
1155                 if (DBG) Rlog.d(LOG_TAG, "switch failed", e);
1156                 notifySuppServiceFailed(Phone.SuppService.SWITCH);
1157             }
1158         }
1159 
1160         return true;
1161     }
1162 
handleMultipartyIncallSupplementaryService(String dialString)1163     private boolean handleMultipartyIncallSupplementaryService(String dialString) {
1164         if (dialString.length() > 1) {
1165             return false;
1166         }
1167 
1168         if (DBG) logd("MmiCode 3: merge calls");
1169         conference();
1170         return true;
1171     }
1172 
handleEctIncallSupplementaryService(String dialString)1173     private boolean handleEctIncallSupplementaryService(String dialString) {
1174 
1175         int len = dialString.length();
1176 
1177         if (len != 1) {
1178             return false;
1179         }
1180 
1181         if (DBG) logd("MmiCode 4: explicit call transfer");
1182         explicitCallTransfer();
1183         return true;
1184     }
1185 
handleCcbsIncallSupplementaryService(String dialString)1186     private boolean handleCcbsIncallSupplementaryService(String dialString) {
1187         if (dialString.length() > 1) {
1188             return false;
1189         }
1190 
1191         Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!");
1192         // Treat it as an "unknown" service.
1193         notifySuppServiceFailed(Phone.SuppService.UNKNOWN);
1194         return true;
1195     }
1196 
1197     @UnsupportedAppUsage
1198     @Override
handleInCallMmiCommands(String dialString)1199     public boolean handleInCallMmiCommands(String dialString) throws CallStateException {
1200         if (!isPhoneTypeGsm()) {
1201             loge("method handleInCallMmiCommands is NOT supported in CDMA!");
1202             return false;
1203         }
1204 
1205         Phone imsPhone = mImsPhone;
1206         if (imsPhone != null
1207                 && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) {
1208             return imsPhone.handleInCallMmiCommands(dialString);
1209         }
1210 
1211         if (!isInCall()) {
1212             return false;
1213         }
1214 
1215         if (TextUtils.isEmpty(dialString)) {
1216             return false;
1217         }
1218 
1219         boolean result = false;
1220         char ch = dialString.charAt(0);
1221         switch (ch) {
1222             case '0':
1223                 result = handleCallDeflectionIncallSupplementaryService(dialString);
1224                 break;
1225             case '1':
1226                 result = handleCallWaitingIncallSupplementaryService(dialString);
1227                 break;
1228             case '2':
1229                 result = handleCallHoldIncallSupplementaryService(dialString);
1230                 break;
1231             case '3':
1232                 result = handleMultipartyIncallSupplementaryService(dialString);
1233                 break;
1234             case '4':
1235                 result = handleEctIncallSupplementaryService(dialString);
1236                 break;
1237             case '5':
1238                 result = handleCcbsIncallSupplementaryService(dialString);
1239                 break;
1240             default:
1241                 break;
1242         }
1243 
1244         return result;
1245     }
1246 
1247     @UnsupportedAppUsage
isInCall()1248     public boolean isInCall() {
1249         GsmCdmaCall.State foregroundCallState = getForegroundCall().getState();
1250         GsmCdmaCall.State backgroundCallState = getBackgroundCall().getState();
1251         GsmCdmaCall.State ringingCallState = getRingingCall().getState();
1252 
1253        return (foregroundCallState.isAlive() ||
1254                 backgroundCallState.isAlive() ||
1255                 ringingCallState.isAlive());
1256     }
1257 
useImsForCall(DialArgs dialArgs)1258     private boolean useImsForCall(DialArgs dialArgs) {
1259         return isImsUseEnabled()
1260                 && mImsPhone != null
1261                 && (mImsPhone.isVolteEnabled() || mImsPhone.isWifiCallingEnabled() ||
1262                 (mImsPhone.isVideoEnabled() && VideoProfile.isVideo(dialArgs.videoState)))
1263                 && (mImsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
1264     }
1265 
1266     @Override
startConference(String[] participantsToDial, DialArgs dialArgs)1267     public Connection startConference(String[] participantsToDial, DialArgs dialArgs)
1268             throws CallStateException {
1269         Phone imsPhone = mImsPhone;
1270         boolean useImsForCall = useImsForCall(dialArgs);
1271         logd("useImsForCall=" + useImsForCall);
1272         if (useImsForCall) {
1273             try {
1274                 if (DBG) logd("Trying IMS PS Conference call");
1275                 return imsPhone.startConference(participantsToDial, dialArgs);
1276             } catch (CallStateException e) {
1277                 if (DBG) logd("IMS PS conference call exception " + e +
1278                         "useImsForCall =" + useImsForCall + ", imsPhone =" + imsPhone);
1279                  CallStateException ce = new CallStateException(e.getError(), e.getMessage());
1280                  ce.setStackTrace(e.getStackTrace());
1281                  throw ce;
1282             }
1283         } else {
1284             throw new CallStateException(
1285                 CallStateException.ERROR_OUT_OF_SERVICE,
1286                 "cannot dial conference call in out of service");
1287         }
1288     }
1289 
1290     @Override
dial(String dialString, @NonNull DialArgs dialArgs)1291     public Connection dial(String dialString, @NonNull DialArgs dialArgs)
1292             throws CallStateException {
1293         if (!isPhoneTypeGsm() && dialArgs.uusInfo != null) {
1294             throw new CallStateException("Sending UUS information NOT supported in CDMA!");
1295         }
1296         String possibleEmergencyNumber = checkForTestEmergencyNumber(dialString);
1297         // Record if the dialed number was swapped for a test emergency number.
1298         boolean isDialedNumberSwapped = !TextUtils.equals(dialString, possibleEmergencyNumber);
1299         if (isDialedNumberSwapped) {
1300             logi("dialString replaced for possible emergency number: " + dialString + " -> "
1301                     + possibleEmergencyNumber);
1302             dialString = possibleEmergencyNumber;
1303         }
1304         boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
1305         Phone imsPhone = mImsPhone;
1306         mDialArgs = dialArgs;
1307 
1308         CarrierConfigManager configManager =
1309                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1310         boolean alwaysTryImsForEmergencyCarrierConfig = configManager.getConfigForSubId(getSubId())
1311                 .getBoolean(CarrierConfigManager.KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL);
1312 
1313         /** Check if the call is Wireless Priority Service call */
1314         boolean isWpsCall = dialString != null ? dialString.startsWith(PREFIX_WPS) : false;
1315         boolean allowWpsOverIms = configManager.getConfigForSubId(getSubId())
1316                 .getBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL);
1317 
1318         boolean useImsForEmergency = imsPhone != null
1319                 && isEmergency
1320                 && alwaysTryImsForEmergencyCarrierConfig
1321                 && ImsManager.getInstance(mContext, mPhoneId).isNonTtyOrTtyOnVolteEnabled()
1322                 && imsPhone.isImsAvailable();
1323 
1324         String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(PhoneNumberUtils.
1325                 stripSeparators(dialString));
1326         boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#"))
1327                 && dialPart.endsWith("#");
1328         boolean isSuppServiceCode = ImsPhoneMmiCode.isSuppServiceCodes(dialPart, this);
1329         boolean isPotentialUssdCode = isMmiCode && !isSuppServiceCode;
1330         boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled();
1331         boolean useImsForCall = useImsForCall(dialArgs)
1332                 && (isWpsCall ? allowWpsOverIms : true);
1333 
1334         if (DBG) {
1335             logd("useImsForCall=" + useImsForCall
1336                     + ", isEmergency=" + isEmergency
1337                     + ", useImsForEmergency=" + useImsForEmergency
1338                     + ", useImsForUt=" + useImsForUt
1339                     + ", isUt=" + isMmiCode
1340                     + ", isSuppServiceCode=" + isSuppServiceCode
1341                     + ", isPotentialUssdCode=" + isPotentialUssdCode
1342                     + ", isWpsCall=" + isWpsCall
1343                     + ", allowWpsOverIms=" + allowWpsOverIms
1344                     + ", imsPhone=" + imsPhone
1345                     + ", imsPhone.isVolteEnabled()="
1346                     + ((imsPhone != null) ? imsPhone.isVolteEnabled() : "N/A")
1347                     + ", imsPhone.isVowifiEnabled()="
1348                     + ((imsPhone != null) ? imsPhone.isWifiCallingEnabled() : "N/A")
1349                     + ", imsPhone.isVideoEnabled()="
1350                     + ((imsPhone != null) ? imsPhone.isVideoEnabled() : "N/A")
1351                     + ", imsPhone.getServiceState().getState()="
1352                     + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A"));
1353         }
1354 
1355         Phone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mPhoneId, mContext);
1356 
1357         if ((useImsForCall && (!isMmiCode || isPotentialUssdCode))
1358                 || (isMmiCode && useImsForUt)
1359                 || useImsForEmergency) {
1360             try {
1361                 if (DBG) logd("Trying IMS PS call");
1362                 return imsPhone.dial(dialString, dialArgs);
1363             } catch (CallStateException e) {
1364                 if (DBG) logd("IMS PS call exception " + e +
1365                         "useImsForCall =" + useImsForCall + ", imsPhone =" + imsPhone);
1366                 // Do not throw a CallStateException and instead fall back to Circuit switch
1367                 // for emergency calls and MMI codes.
1368                 if (Phone.CS_FALLBACK.equals(e.getMessage()) || isEmergency) {
1369                     logi("IMS call failed with Exception: " + e.getMessage() + ". Falling back "
1370                             + "to CS.");
1371                 } else {
1372                     CallStateException ce = new CallStateException(e.getError(), e.getMessage());
1373                     ce.setStackTrace(e.getStackTrace());
1374                     throw ce;
1375                 }
1376             }
1377         }
1378 
1379         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE
1380                 && mSST.mSS.getDataRegistrationState() != ServiceState.STATE_IN_SERVICE
1381                 && !isEmergency) {
1382             throw new CallStateException("cannot dial in current state");
1383         }
1384         // Check non-emergency voice CS call - shouldn't dial when POWER_OFF
1385         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_POWER_OFF /* CS POWER_OFF */
1386                 && !VideoProfile.isVideo(dialArgs.videoState) /* voice call */
1387                 && !isEmergency /* non-emergency call */
1388                 && !(isMmiCode && useImsForUt) /* not UT */
1389                 /* If config_allow_ussd_over_ims is false, USSD is sent over the CS pipe instead */
1390                 && !isPotentialUssdCode) {
1391             throw new CallStateException(
1392                 CallStateException.ERROR_POWER_OFF,
1393                 "cannot dial voice call in airplane mode");
1394         }
1395         // Check for service before placing non emergency CS voice call.
1396         // Allow dial only if either CS is camped on any RAT (or) PS is in LTE/NR service.
1397         if (mSST != null
1398                 && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE /* CS out of service */
1399                 && !(mSST.mSS.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE
1400                 && ServiceState.isPsOnlyTech(
1401                         mSST.mSS.getRilDataRadioTechnology())) /* PS not in LTE/NR */
1402                 && !VideoProfile.isVideo(dialArgs.videoState) /* voice call */
1403                 && !isEmergency /* non-emergency call */
1404                 /* If config_allow_ussd_over_ims is false, USSD is sent over the CS pipe instead */
1405                 && !isPotentialUssdCode) {
1406             throw new CallStateException(
1407                 CallStateException.ERROR_OUT_OF_SERVICE,
1408                 "cannot dial voice call in out of service");
1409         }
1410         if (DBG) logd("Trying (non-IMS) CS call");
1411         if (isDialedNumberSwapped && isEmergency) {
1412             // Triggers ECM when CS call ends only for test emergency calls using
1413             // ril.test.emergencynumber.
1414             mIsTestingEmergencyCallbackMode = true;
1415             mCi.testingEmergencyCall();
1416         }
1417         if (isPhoneTypeGsm()) {
1418             return dialInternal(dialString, new DialArgs.Builder<>()
1419                     .setIntentExtras(dialArgs.intentExtras)
1420                     .build());
1421         } else {
1422             return dialInternal(dialString, dialArgs);
1423         }
1424     }
1425 
1426     /**
1427      * @return {@code true} if the user should be informed of an attempt to dial an international
1428      * number while on WFC only, {@code false} otherwise.
1429      */
isNotificationOfWfcCallRequired(String dialString)1430     public boolean isNotificationOfWfcCallRequired(String dialString) {
1431         CarrierConfigManager configManager =
1432                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1433         PersistableBundle config = configManager.getConfigForSubId(getSubId());
1434 
1435         // Determine if carrier config indicates that international calls over WFC should trigger a
1436         // notification to the user. This is controlled by carrier configuration and is off by
1437         // default.
1438         boolean shouldNotifyInternationalCallOnWfc = config != null
1439                 && config.getBoolean(
1440                         CarrierConfigManager.KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL);
1441 
1442         if (!shouldNotifyInternationalCallOnWfc) {
1443             return false;
1444         }
1445 
1446         Phone imsPhone = mImsPhone;
1447         boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
1448         boolean shouldConfirmCall =
1449                         // Using IMS
1450                         isImsUseEnabled()
1451                         && imsPhone != null
1452                         // VoLTE not available
1453                         && !imsPhone.isVolteEnabled()
1454                         // WFC is available
1455                         && imsPhone.isWifiCallingEnabled()
1456                         && !isEmergency
1457                         // Dialing international number
1458                         && PhoneNumberUtils.isInternationalNumber(dialString, getCountryIso());
1459         return shouldConfirmCall;
1460     }
1461 
1462     @Override
dialInternal(String dialString, DialArgs dialArgs)1463     protected Connection dialInternal(String dialString, DialArgs dialArgs)
1464             throws CallStateException {
1465         return dialInternal(dialString, dialArgs, null);
1466     }
1467 
dialInternal(String dialString, DialArgs dialArgs, ResultReceiver wrappedCallback)1468     protected Connection dialInternal(String dialString, DialArgs dialArgs,
1469             ResultReceiver wrappedCallback)
1470             throws CallStateException {
1471 
1472         // Need to make sure dialString gets parsed properly
1473         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
1474 
1475         if (isPhoneTypeGsm()) {
1476             // handle in-call MMI first if applicable
1477             if (handleInCallMmiCommands(newDialString)) {
1478                 return null;
1479             }
1480 
1481             // Only look at the Network portion for mmi
1482             String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
1483             GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
1484                     mUiccApplication.get(), wrappedCallback);
1485             if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'...");
1486 
1487             if (mmi == null) {
1488                 return mCT.dialGsm(newDialString, dialArgs.uusInfo, dialArgs.intentExtras);
1489             } else if (mmi.isTemporaryModeCLIR()) {
1490                 return mCT.dialGsm(mmi.mDialingNumber, mmi.getCLIRMode(), dialArgs.uusInfo,
1491                         dialArgs.intentExtras);
1492             } else {
1493                 mPendingMMIs.add(mmi);
1494                 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1495                 mmi.processCode();
1496                 return null;
1497             }
1498         } else {
1499             return mCT.dial(newDialString, dialArgs.intentExtras);
1500         }
1501     }
1502 
1503    @Override
handlePinMmi(String dialString)1504     public boolean handlePinMmi(String dialString) {
1505         MmiCode mmi;
1506         if (isPhoneTypeGsm()) {
1507             mmi = GsmMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
1508         } else {
1509             mmi = CdmaMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
1510         }
1511 
1512         if (mmi != null && mmi.isPinPukCommand()) {
1513             mPendingMMIs.add(mmi);
1514             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1515             try {
1516                 mmi.processCode();
1517             } catch (CallStateException e) {
1518                 //do nothing
1519             }
1520             return true;
1521         }
1522 
1523         loge("Mmi is null or unrecognized!");
1524         return false;
1525     }
1526 
sendUssdResponse(String ussdRequest, CharSequence message, int returnCode, ResultReceiver wrappedCallback)1527     private void sendUssdResponse(String ussdRequest, CharSequence message, int returnCode,
1528                                    ResultReceiver wrappedCallback) {
1529         UssdResponse response = new UssdResponse(ussdRequest, message);
1530         Bundle returnData = new Bundle();
1531         returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
1532         wrappedCallback.send(returnCode, returnData);
1533     }
1534 
1535     @Override
handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback)1536     public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
1537         if (!isPhoneTypeGsm() || mPendingMMIs.size() > 0) {
1538             //todo: replace the generic failure with specific error code.
1539             sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
1540                     wrappedCallback );
1541             return true;
1542         }
1543 
1544         // Try over IMS if possible.
1545         Phone imsPhone = mImsPhone;
1546         if ((imsPhone != null)
1547                 && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1548                 || imsPhone.isUtEnabled())) {
1549             try {
1550                 logd("handleUssdRequest: attempting over IMS");
1551                 return imsPhone.handleUssdRequest(ussdRequest, wrappedCallback);
1552             } catch (CallStateException cse) {
1553                 if (!CS_FALLBACK.equals(cse.getMessage())) {
1554                     return false;
1555                 }
1556                 // At this point we've tried over IMS but have been informed we need to handover
1557                 // back to GSM.
1558                 logd("handleUssdRequest: fallback to CS required");
1559             }
1560         }
1561 
1562         // Try USSD over GSM.
1563         try {
1564             dialInternal(ussdRequest, new DialArgs.Builder<>().build(), wrappedCallback);
1565         } catch (Exception e) {
1566             logd("handleUssdRequest: exception" + e);
1567             return false;
1568         }
1569         return true;
1570     }
1571 
1572     @Override
sendUssdResponse(String ussdMessge)1573     public void sendUssdResponse(String ussdMessge) {
1574         if (isPhoneTypeGsm()) {
1575             GsmMmiCode mmi = GsmMmiCode.newFromUssdUserInput(ussdMessge, this, mUiccApplication.get());
1576             mPendingMMIs.add(mmi);
1577             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1578             mmi.sendUssd(ussdMessge);
1579         } else {
1580             loge("sendUssdResponse: not possible in CDMA");
1581         }
1582     }
1583 
1584     @Override
sendDtmf(char c)1585     public void sendDtmf(char c) {
1586         if (!PhoneNumberUtils.is12Key(c)) {
1587             loge("sendDtmf called with invalid character '" + c + "'");
1588         } else {
1589             if (mCT.mState ==  PhoneConstants.State.OFFHOOK) {
1590                 mCi.sendDtmf(c, null);
1591             }
1592         }
1593     }
1594 
1595     @Override
startDtmf(char c)1596     public void startDtmf(char c) {
1597         if (!PhoneNumberUtils.is12Key(c)) {
1598             loge("startDtmf called with invalid character '" + c + "'");
1599         } else {
1600             mCi.startDtmf(c, null);
1601         }
1602     }
1603 
1604     @Override
stopDtmf()1605     public void stopDtmf() {
1606         mCi.stopDtmf(null);
1607     }
1608 
1609     @Override
sendBurstDtmf(String dtmfString, int on, int off, Message onComplete)1610     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
1611         if (isPhoneTypeGsm()) {
1612             loge("[GsmCdmaPhone] sendBurstDtmf() is a CDMA method");
1613         } else {
1614             boolean check = true;
1615             for (int itr = 0;itr < dtmfString.length(); itr++) {
1616                 if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
1617                     Rlog.e(LOG_TAG,
1618                             "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'");
1619                     check = false;
1620                     break;
1621                 }
1622             }
1623             if (mCT.mState == PhoneConstants.State.OFFHOOK && check) {
1624                 mCi.sendBurstDtmf(dtmfString, on, off, onComplete);
1625             }
1626         }
1627     }
1628 
1629     @Override
setRadioPower(boolean power, boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply)1630     public void setRadioPower(boolean power, boolean forEmergencyCall,
1631             boolean isSelectedPhoneForEmergencyCall, boolean forceApply) {
1632         mSST.setRadioPower(power, forEmergencyCall, isSelectedPhoneForEmergencyCall, forceApply);
1633     }
1634 
storeVoiceMailNumber(String number)1635     private void storeVoiceMailNumber(String number) {
1636         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1637         SharedPreferences.Editor editor = sp.edit();
1638         setVmSimImsi(getSubscriberId());
1639         logd("storeVoiceMailNumber: mPrecisePhoneType=" + mPrecisePhoneType + " vmNumber="
1640                 + number);
1641         if (isPhoneTypeGsm()) {
1642             editor.putString(VM_NUMBER + getPhoneId(), number);
1643             editor.apply();
1644         } else {
1645             editor.putString(VM_NUMBER_CDMA + getPhoneId(), number);
1646             editor.apply();
1647         }
1648     }
1649 
1650     @Override
getVoiceMailNumber()1651     public String getVoiceMailNumber() {
1652         String number = null;
1653         if (isPhoneTypeGsm() || mSimRecords != null) {
1654             // Read from the SIM. If its null, try reading from the shared preference area.
1655             IccRecords r = isPhoneTypeGsm() ? mIccRecords.get() : mSimRecords;
1656             number = (r != null) ? r.getVoiceMailNumber() : "";
1657             if (TextUtils.isEmpty(number)) {
1658                 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1659                 String spName = isPhoneTypeGsm() ? VM_NUMBER : VM_NUMBER_CDMA;
1660                 number = sp.getString(spName + getPhoneId(), null);
1661                 logd("getVoiceMailNumber: from " + spName + " number=" + number);
1662             } else {
1663                 logd("getVoiceMailNumber: from IccRecords number=" + number);
1664             }
1665         }
1666         if (!isPhoneTypeGsm() && TextUtils.isEmpty(number)) {
1667             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1668             number = sp.getString(VM_NUMBER_CDMA + getPhoneId(), null);
1669             logd("getVoiceMailNumber: from VM_NUMBER_CDMA number=" + number);
1670         }
1671 
1672         if (TextUtils.isEmpty(number)) {
1673             CarrierConfigManager configManager = (CarrierConfigManager)
1674                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
1675             PersistableBundle b = configManager.getConfigForSubId(getSubId());
1676             if (b != null) {
1677                 String defaultVmNumber =
1678                         b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING);
1679                 String defaultVmNumberRoaming =
1680                         b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_ROAMING_STRING);
1681                 String defaultVmNumberRoamingAndImsUnregistered = b.getString(
1682                         CarrierConfigManager
1683                                 .KEY_DEFAULT_VM_NUMBER_ROAMING_AND_IMS_UNREGISTERED_STRING);
1684 
1685                 if (!TextUtils.isEmpty(defaultVmNumber)) number = defaultVmNumber;
1686                 if (mSST.mSS.getRoaming()) {
1687                     if (!TextUtils.isEmpty(defaultVmNumberRoamingAndImsUnregistered)
1688                             && !mSST.isImsRegistered()) {
1689                         // roaming and IMS unregistered case if CC configured
1690                         number = defaultVmNumberRoamingAndImsUnregistered;
1691                     } else if (!TextUtils.isEmpty(defaultVmNumberRoaming)) {
1692                         // roaming default case if CC configured
1693                         number = defaultVmNumberRoaming;
1694                     }
1695                 }
1696             }
1697         }
1698 
1699         if (TextUtils.isEmpty(number)) {
1700             // Read platform settings for dynamic voicemail number
1701             CarrierConfigManager configManager = (CarrierConfigManager)
1702                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
1703             PersistableBundle b = configManager.getConfigForSubId(getSubId());
1704             if (b != null && b.getBoolean(
1705                     CarrierConfigManager.KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL)) {
1706                 number = getLine1Number();
1707             }
1708         }
1709 
1710         return number;
1711     }
1712 
getVmSimImsi()1713     private String getVmSimImsi() {
1714         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1715         return sp.getString(VM_SIM_IMSI + getPhoneId(), null);
1716     }
1717 
setVmSimImsi(String imsi)1718     private void setVmSimImsi(String imsi) {
1719         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1720         SharedPreferences.Editor editor = sp.edit();
1721         editor.putString(VM_SIM_IMSI + getPhoneId(), imsi);
1722         editor.apply();
1723     }
1724 
1725     @Override
getVoiceMailAlphaTag()1726     public String getVoiceMailAlphaTag() {
1727         String ret = "";
1728 
1729         if (isPhoneTypeGsm() || mSimRecords != null) {
1730             IccRecords r = isPhoneTypeGsm() ? mIccRecords.get() : mSimRecords;
1731 
1732             ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
1733         }
1734 
1735         if (ret == null || ret.length() == 0) {
1736             return mContext.getText(
1737                 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
1738         }
1739 
1740         return ret;
1741     }
1742 
1743     @Override
getDeviceId()1744     public String getDeviceId() {
1745         if (isPhoneTypeGsm()) {
1746             return mImei;
1747         } else {
1748             CarrierConfigManager configManager = (CarrierConfigManager)
1749                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1750             boolean force_imei = configManager.getConfigForSubId(getSubId())
1751                     .getBoolean(CarrierConfigManager.KEY_FORCE_IMEI_BOOL);
1752             if (force_imei) return mImei;
1753 
1754             String id = getMeid();
1755             if ((id == null) || id.matches("^0*$")) {
1756                 loge("getDeviceId(): MEID is not initialized use ESN");
1757                 id = getEsn();
1758             }
1759             return id;
1760         }
1761     }
1762 
1763     @Override
getDeviceSvn()1764     public String getDeviceSvn() {
1765         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1766             return mImeiSv;
1767         } else {
1768             loge("getDeviceSvn(): return 0");
1769             return "0";
1770         }
1771     }
1772 
1773     @Override
getIsimRecords()1774     public IsimRecords getIsimRecords() {
1775         return mIsimUiccRecords;
1776     }
1777 
1778     @Override
getImei()1779     public String getImei() {
1780         return mImei;
1781     }
1782 
1783     @UnsupportedAppUsage
1784     @Override
getEsn()1785     public String getEsn() {
1786         if (isPhoneTypeGsm()) {
1787             loge("[GsmCdmaPhone] getEsn() is a CDMA method");
1788             return "0";
1789         } else {
1790             return mEsn;
1791         }
1792     }
1793 
1794     @Override
getMeid()1795     public String getMeid() {
1796         return mMeid;
1797     }
1798 
1799     @Override
getNai()1800     public String getNai() {
1801         IccRecords r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP2);
1802         if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
1803             Rlog.v(LOG_TAG, "IccRecords is " + r);
1804         }
1805         return (r != null) ? r.getNAI() : null;
1806     }
1807 
1808     @Override
1809     @Nullable
getSubscriberId()1810     public String getSubscriberId() {
1811         String subscriberId = null;
1812         if (isPhoneTypeCdma()) {
1813             subscriberId = mSST.getImsi();
1814         } else {
1815             // Both Gsm and CdmaLte get the IMSI from Usim.
1816             IccRecords iccRecords = mUiccController.getIccRecords(
1817                     mPhoneId, UiccController.APP_FAM_3GPP);
1818             if (iccRecords != null) {
1819                 subscriberId = iccRecords.getIMSI();
1820             }
1821         }
1822         return subscriberId;
1823     }
1824 
1825     @Override
getCarrierInfoForImsiEncryption(int keyType)1826     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
1827         String operatorNumeric = TelephonyManager.from(mContext)
1828                 .getSimOperatorNumericForPhone(mPhoneId);
1829         return CarrierInfoManager.getCarrierInfoForImsiEncryption(keyType,
1830                 mContext, operatorNumeric);
1831     }
1832 
1833     @Override
setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo)1834     public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) {
1835         CarrierInfoManager.setCarrierInfoForImsiEncryption(imsiEncryptionInfo, mContext, mPhoneId);
1836     }
1837 
1838     @Override
getCarrierId()1839     public int getCarrierId() {
1840         return mCarrierResolver.getCarrierId();
1841     }
1842 
1843     @Override
getCarrierName()1844     public String getCarrierName() {
1845         return mCarrierResolver.getCarrierName();
1846     }
1847 
1848     @Override
getMNOCarrierId()1849     public int getMNOCarrierId() {
1850         return mCarrierResolver.getMnoCarrierId();
1851     }
1852 
1853     @Override
getSpecificCarrierId()1854     public int getSpecificCarrierId() {
1855         return mCarrierResolver.getSpecificCarrierId();
1856     }
1857 
1858     @Override
getSpecificCarrierName()1859     public String getSpecificCarrierName() {
1860         return mCarrierResolver.getSpecificCarrierName();
1861     }
1862 
1863     @Override
resolveSubscriptionCarrierId(String simState)1864     public void resolveSubscriptionCarrierId(String simState) {
1865         mCarrierResolver.resolveSubscriptionCarrierId(simState);
1866     }
1867 
1868     @Override
getCarrierIdListVersion()1869     public int getCarrierIdListVersion() {
1870         return mCarrierResolver.getCarrierListVersion();
1871     }
1872 
1873     @Override
getEmergencyNumberDbVersion()1874     public int getEmergencyNumberDbVersion() {
1875         return getEmergencyNumberTracker().getEmergencyNumberDbVersion();
1876     }
1877 
1878     @Override
resetCarrierKeysForImsiEncryption()1879     public void resetCarrierKeysForImsiEncryption() {
1880         mCIM.resetCarrierKeysForImsiEncryption(mContext, mPhoneId);
1881     }
1882 
1883     @Override
setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1, String gid2, String pnn, String spn, String carrierPrivilegeRules, String apn)1884     public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
1885             String gid2, String pnn, String spn, String carrierPrivilegeRules, String apn) {
1886         mCarrierResolver.setTestOverrideApn(apn);
1887         mCarrierResolver.setTestOverrideCarrierPriviledgeRule(carrierPrivilegeRules);
1888         IccRecords r = null;
1889         if (isPhoneTypeGsm()) {
1890             r = mIccRecords.get();
1891         } else if (isPhoneTypeCdmaLte()) {
1892             r = mSimRecords;
1893         } else {
1894             loge("setCarrierTestOverride fails in CDMA only");
1895         }
1896         if (r != null) {
1897             r.setCarrierTestOverride(mccmnc, imsi, iccid, gid1, gid2, pnn, spn);
1898         }
1899     }
1900 
1901     @Override
getGroupIdLevel1()1902     public String getGroupIdLevel1() {
1903         if (isPhoneTypeGsm()) {
1904             IccRecords r = mIccRecords.get();
1905             return (r != null) ? r.getGid1() : null;
1906         } else if (isPhoneTypeCdma()) {
1907             loge("GID1 is not available in CDMA");
1908             return null;
1909         } else { //isPhoneTypeCdmaLte()
1910             return (mSimRecords != null) ? mSimRecords.getGid1() : "";
1911         }
1912     }
1913 
1914     @Override
getGroupIdLevel2()1915     public String getGroupIdLevel2() {
1916         if (isPhoneTypeGsm()) {
1917             IccRecords r = mIccRecords.get();
1918             return (r != null) ? r.getGid2() : null;
1919         } else if (isPhoneTypeCdma()) {
1920             loge("GID2 is not available in CDMA");
1921             return null;
1922         } else { //isPhoneTypeCdmaLte()
1923             return (mSimRecords != null) ? mSimRecords.getGid2() : "";
1924         }
1925     }
1926 
1927     @UnsupportedAppUsage
1928     @Override
getLine1Number()1929     public String getLine1Number() {
1930         if (isPhoneTypeGsm()) {
1931             IccRecords r = mIccRecords.get();
1932             return (r != null) ? r.getMsisdnNumber() : null;
1933         } else {
1934             CarrierConfigManager configManager = (CarrierConfigManager)
1935                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1936             boolean use_usim = configManager.getConfigForSubId(getSubId()).getBoolean(
1937                     CarrierConfigManager.KEY_USE_USIM_BOOL);
1938             if (use_usim) {
1939                 return (mSimRecords != null) ? mSimRecords.getMsisdnNumber() : null;
1940             }
1941             return mSST.getMdnNumber();
1942         }
1943     }
1944 
1945     @Override
getPlmn()1946     public String getPlmn() {
1947         if (isPhoneTypeGsm()) {
1948             IccRecords r = mIccRecords.get();
1949             return (r != null) ? r.getPnnHomeName() : null;
1950         } else if (isPhoneTypeCdma()) {
1951             loge("Plmn is not available in CDMA");
1952             return null;
1953         } else { //isPhoneTypeCdmaLte()
1954             return (mSimRecords != null) ? mSimRecords.getPnnHomeName() : null;
1955         }
1956     }
1957 
1958     @Override
getCdmaPrlVersion()1959     public String getCdmaPrlVersion() {
1960         return mSST.getPrlVersion();
1961     }
1962 
1963     @Override
getCdmaMin()1964     public String getCdmaMin() {
1965         return mSST.getCdmaMin();
1966     }
1967 
1968     @Override
isMinInfoReady()1969     public boolean isMinInfoReady() {
1970         return mSST.isMinInfoReady();
1971     }
1972 
1973     @Override
getMsisdn()1974     public String getMsisdn() {
1975         if (isPhoneTypeGsm()) {
1976             IccRecords r = mIccRecords.get();
1977             return (r != null) ? r.getMsisdnNumber() : null;
1978         } else if (isPhoneTypeCdmaLte()) {
1979             return (mSimRecords != null) ? mSimRecords.getMsisdnNumber() : null;
1980         } else {
1981             loge("getMsisdn: not expected on CDMA");
1982             return null;
1983         }
1984     }
1985 
1986     @Override
getLine1AlphaTag()1987     public String getLine1AlphaTag() {
1988         if (isPhoneTypeGsm()) {
1989             IccRecords r = mIccRecords.get();
1990             return (r != null) ? r.getMsisdnAlphaTag() : null;
1991         } else {
1992             loge("getLine1AlphaTag: not possible in CDMA");
1993             return null;
1994         }
1995     }
1996 
1997     @Override
setLine1Number(String alphaTag, String number, Message onComplete)1998     public boolean setLine1Number(String alphaTag, String number, Message onComplete) {
1999         if (isPhoneTypeGsm()) {
2000             IccRecords r = mIccRecords.get();
2001             if (r != null) {
2002                 r.setMsisdnNumber(alphaTag, number, onComplete);
2003                 return true;
2004             } else {
2005                 return false;
2006             }
2007         } else {
2008             loge("setLine1Number: not possible in CDMA");
2009             return false;
2010         }
2011     }
2012 
2013     @Override
setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete)2014     public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete) {
2015         Message resp;
2016         mVmNumber = voiceMailNumber;
2017         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
2018 
2019         IccRecords r = mIccRecords.get();
2020 
2021         if (!isPhoneTypeGsm() && mSimRecords != null) {
2022             r = mSimRecords;
2023         }
2024 
2025         if (r != null) {
2026             r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
2027         }
2028     }
2029 
2030     @UnsupportedAppUsage
isValidCommandInterfaceCFReason(int commandInterfaceCFReason)2031     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
2032         switch (commandInterfaceCFReason) {
2033             case CF_REASON_UNCONDITIONAL:
2034             case CF_REASON_BUSY:
2035             case CF_REASON_NO_REPLY:
2036             case CF_REASON_NOT_REACHABLE:
2037             case CF_REASON_ALL:
2038             case CF_REASON_ALL_CONDITIONAL:
2039                 return true;
2040             default:
2041                 return false;
2042         }
2043     }
2044 
2045     @UnsupportedAppUsage
2046     @Override
getSystemProperty(String property, String defValue)2047     public String getSystemProperty(String property, String defValue) {
2048         if (getUnitTestMode()) {
2049             return null;
2050         }
2051         return TelephonyManager.getTelephonyProperty(mPhoneId, property, defValue);
2052     }
2053 
2054     @UnsupportedAppUsage
isValidCommandInterfaceCFAction(int commandInterfaceCFAction)2055     private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
2056         switch (commandInterfaceCFAction) {
2057             case CF_ACTION_DISABLE:
2058             case CF_ACTION_ENABLE:
2059             case CF_ACTION_REGISTRATION:
2060             case CF_ACTION_ERASURE:
2061                 return true;
2062             default:
2063                 return false;
2064         }
2065     }
2066 
2067     @UnsupportedAppUsage
isCfEnable(int action)2068     private boolean isCfEnable(int action) {
2069         return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
2070     }
2071 
isImsUtEnabledOverCdma()2072     private boolean isImsUtEnabledOverCdma() {
2073         return isPhoneTypeCdmaLte()
2074             && mImsPhone != null
2075             && mImsPhone.isUtEnabled();
2076     }
2077 
isCsRetry(Message onComplete)2078     private boolean isCsRetry(Message onComplete) {
2079         if (onComplete != null) {
2080             return onComplete.getData().getBoolean(CS_FALLBACK_SS, false);
2081         }
2082         return false;
2083     }
2084 
2085     @Override
useSsOverIms(Message onComplete)2086     public boolean useSsOverIms(Message onComplete) {
2087         boolean isUtEnabled = isUtEnabled();
2088 
2089         Rlog.d(LOG_TAG, "useSsOverIms: isUtEnabled()= " + isUtEnabled +
2090                 " isCsRetry(onComplete))= " + isCsRetry(onComplete));
2091 
2092         if (isUtEnabled && !isCsRetry(onComplete)) {
2093             return true;
2094         }
2095         return false;
2096     }
2097 
2098     @Override
getCallForwardingOption(int commandInterfaceCFReason, Message onComplete)2099     public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
2100         getCallForwardingOption(commandInterfaceCFReason,
2101                 CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
2102     }
2103 
2104     @Override
getCallForwardingOption(int commandInterfaceCFReason, int serviceClass, Message onComplete)2105     public void getCallForwardingOption(int commandInterfaceCFReason, int serviceClass,
2106             Message onComplete) {
2107         Phone imsPhone = mImsPhone;
2108         if (useSsOverIms(onComplete)) {
2109             imsPhone.getCallForwardingOption(commandInterfaceCFReason, serviceClass, onComplete);
2110             return;
2111         }
2112 
2113         if (isPhoneTypeGsm()) {
2114             if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
2115                 if (DBG) logd("requesting call forwarding query.");
2116                 Message resp;
2117                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
2118                     resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
2119                 } else {
2120                     resp = onComplete;
2121                 }
2122                 mCi.queryCallForwardStatus(commandInterfaceCFReason, serviceClass, null, resp);
2123             }
2124         } else {
2125             loge("getCallForwardingOption: not possible in CDMA, just return empty result");
2126             AsyncResult.forMessage(onComplete, makeEmptyCallForward(), null);
2127             onComplete.sendToTarget();
2128         }
2129     }
2130 
2131     @Override
setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int timerSeconds, Message onComplete)2132     public void setCallForwardingOption(int commandInterfaceCFAction,
2133             int commandInterfaceCFReason,
2134             String dialingNumber,
2135             int timerSeconds,
2136             Message onComplete) {
2137         setCallForwardingOption(commandInterfaceCFAction, commandInterfaceCFReason,
2138                 dialingNumber, CommandsInterface.SERVICE_CLASS_VOICE, timerSeconds, onComplete);
2139     }
2140 
2141     @Override
setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int serviceClass, int timerSeconds, Message onComplete)2142     public void setCallForwardingOption(int commandInterfaceCFAction,
2143             int commandInterfaceCFReason,
2144             String dialingNumber,
2145             int serviceClass,
2146             int timerSeconds,
2147             Message onComplete) {
2148         Phone imsPhone = mImsPhone;
2149         if (useSsOverIms(onComplete)) {
2150             imsPhone.setCallForwardingOption(commandInterfaceCFAction, commandInterfaceCFReason,
2151                     dialingNumber, serviceClass, timerSeconds, onComplete);
2152             return;
2153         }
2154 
2155         if (isPhoneTypeGsm()) {
2156             if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
2157                     (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
2158 
2159                 Message resp;
2160                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
2161                     Cfu cfu = new Cfu(dialingNumber, onComplete);
2162                     resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
2163                             isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cfu);
2164                 } else {
2165                     resp = onComplete;
2166                 }
2167                 mCi.setCallForward(commandInterfaceCFAction,
2168                         commandInterfaceCFReason,
2169                         serviceClass,
2170                         dialingNumber,
2171                         timerSeconds,
2172                         resp);
2173             }
2174         } else {
2175             String formatNumber = GsmCdmaConnection.formatDialString(dialingNumber);
2176             String cfNumber = CdmaMmiCode.getCallForwardingPrefixAndNumber(
2177                     commandInterfaceCFAction, commandInterfaceCFReason, formatNumber);
2178             loge("setCallForwardingOption: dial for set call forwarding"
2179                     + " prefixWithNumber= " + cfNumber + " number= " + dialingNumber);
2180 
2181             PhoneAccountHandle phoneAccountHandle = subscriptionIdToPhoneAccountHandle(getSubId());
2182             Bundle extras = new Bundle();
2183             extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
2184 
2185             final TelecomManager telecomManager = TelecomManager.from(mContext);
2186             telecomManager.placeCall(Uri.parse(PhoneAccount.SCHEME_TEL + cfNumber), extras);
2187 
2188             AsyncResult.forMessage(onComplete, CommandsInterface.SS_STATUS_UNKNOWN, null);
2189             onComplete.sendToTarget();
2190         }
2191     }
2192 
2193     @Override
getCallBarring(String facility, String password, Message onComplete, int serviceClass)2194     public void getCallBarring(String facility, String password, Message onComplete,
2195             int serviceClass) {
2196         Phone imsPhone = mImsPhone;
2197         if (useSsOverIms(onComplete)) {
2198             imsPhone.getCallBarring(facility, password, onComplete, serviceClass);
2199             return;
2200         }
2201 
2202         if (isPhoneTypeGsm()) {
2203             mCi.queryFacilityLock(facility, password, serviceClass, onComplete);
2204         } else {
2205             loge("getCallBarringOption: not possible in CDMA");
2206         }
2207     }
2208 
2209     @Override
setCallBarring(String facility, boolean lockState, String password, Message onComplete, int serviceClass)2210     public void setCallBarring(String facility, boolean lockState, String password,
2211             Message onComplete, int serviceClass) {
2212         Phone imsPhone = mImsPhone;
2213         if (useSsOverIms(onComplete)) {
2214             imsPhone.setCallBarring(facility, lockState, password, onComplete, serviceClass);
2215             return;
2216         }
2217 
2218         if (isPhoneTypeGsm()) {
2219             mCi.setFacilityLock(facility, lockState, password, serviceClass, onComplete);
2220         } else {
2221             loge("setCallBarringOption: not possible in CDMA");
2222         }
2223     }
2224 
2225     /**
2226      * Changes access code used for call barring
2227      *
2228      * @param facility is one of CB_FACILTY_*
2229      * @param oldPwd is old password
2230      * @param newPwd is new password
2231      * @param onComplete is callback message when the action is completed.
2232      */
changeCallBarringPassword(String facility, String oldPwd, String newPwd, Message onComplete)2233     public void changeCallBarringPassword(String facility, String oldPwd, String newPwd,
2234             Message onComplete) {
2235         if (isPhoneTypeGsm()) {
2236             mCi.changeBarringPassword(facility, oldPwd, newPwd, onComplete);
2237         } else {
2238             loge("changeCallBarringPassword: not possible in CDMA");
2239         }
2240     }
2241 
2242     @Override
getOutgoingCallerIdDisplay(Message onComplete)2243     public void getOutgoingCallerIdDisplay(Message onComplete) {
2244         Phone imsPhone = mImsPhone;
2245         if (useSsOverIms(onComplete)) {
2246             imsPhone.getOutgoingCallerIdDisplay(onComplete);
2247             return;
2248         }
2249 
2250         if (isPhoneTypeGsm()) {
2251             mCi.getCLIR(onComplete);
2252         } else {
2253             loge("getOutgoingCallerIdDisplay: not possible in CDMA");
2254             AsyncResult.forMessage(onComplete, null,
2255                     new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED));
2256             onComplete.sendToTarget();
2257         }
2258     }
2259 
2260     @Override
setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete)2261     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
2262         Phone imsPhone = mImsPhone;
2263         if (useSsOverIms(onComplete)) {
2264             imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete);
2265             return;
2266         }
2267 
2268         if (isPhoneTypeGsm()) {
2269             // Packing CLIR value in the message. This will be required for
2270             // SharedPreference caching, if the message comes back as part of
2271             // a success response.
2272             mCi.setCLIR(commandInterfaceCLIRMode,
2273                     obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
2274         } else {
2275             loge("setOutgoingCallerIdDisplay: not possible in CDMA");
2276             AsyncResult.forMessage(onComplete, null,
2277                     new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED));
2278             onComplete.sendToTarget();
2279         }
2280     }
2281 
2282     @Override
queryCLIP(Message onComplete)2283     public void queryCLIP(Message onComplete) {
2284         Phone imsPhone = mImsPhone;
2285         if (useSsOverIms(onComplete)) {
2286             imsPhone.queryCLIP(onComplete);
2287             return;
2288         }
2289 
2290         if (isPhoneTypeGsm()) {
2291             mCi.queryCLIP(onComplete);
2292         } else {
2293             loge("queryCLIP: not possible in CDMA");
2294             AsyncResult.forMessage(onComplete, null,
2295                     new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED));
2296             onComplete.sendToTarget();
2297         }
2298     }
2299 
2300     @Override
getCallWaiting(Message onComplete)2301     public void getCallWaiting(Message onComplete) {
2302         Phone imsPhone = mImsPhone;
2303         if (useSsOverIms(onComplete)) {
2304             imsPhone.getCallWaiting(onComplete);
2305             return;
2306         }
2307 
2308         if (isPhoneTypeGsm()) {
2309             //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
2310             //class parameter in call waiting interrogation  to network
2311             mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
2312         } else {
2313             int arr[] = {CommandsInterface.SS_STATUS_UNKNOWN, CommandsInterface.SERVICE_CLASS_NONE};
2314             AsyncResult.forMessage(onComplete, arr, null);
2315             onComplete.sendToTarget();
2316         }
2317     }
2318 
2319     @Override
setCallWaiting(boolean enable, Message onComplete)2320     public void setCallWaiting(boolean enable, Message onComplete) {
2321         int serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
2322         CarrierConfigManager configManager = (CarrierConfigManager)
2323             getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
2324         PersistableBundle b = configManager.getConfigForSubId(getSubId());
2325         if (b != null) {
2326             serviceClass = b.getInt(CarrierConfigManager.KEY_CALL_WAITING_SERVICE_CLASS_INT,
2327                     CommandsInterface.SERVICE_CLASS_VOICE);
2328         }
2329         setCallWaiting(enable, serviceClass, onComplete);
2330     }
2331 
2332     @Override
setCallWaiting(boolean enable, int serviceClass, Message onComplete)2333     public void setCallWaiting(boolean enable, int serviceClass, Message onComplete) {
2334         Phone imsPhone = mImsPhone;
2335         if (useSsOverIms(onComplete)) {
2336             imsPhone.setCallWaiting(enable, onComplete);
2337             return;
2338         }
2339 
2340         if (isPhoneTypeGsm()) {
2341             mCi.setCallWaiting(enable, serviceClass, onComplete);
2342         } else {
2343             String cwPrefix = CdmaMmiCode.getCallWaitingPrefix(enable);
2344             Rlog.i(LOG_TAG, "setCallWaiting in CDMA : dial for set call waiting" + " prefix= " + cwPrefix);
2345 
2346             PhoneAccountHandle phoneAccountHandle = subscriptionIdToPhoneAccountHandle(getSubId());
2347             Bundle extras = new Bundle();
2348             extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
2349 
2350             final TelecomManager telecomManager = TelecomManager.from(mContext);
2351             telecomManager.placeCall(Uri.parse(PhoneAccount.SCHEME_TEL + cwPrefix), extras);
2352 
2353             AsyncResult.forMessage(onComplete, CommandsInterface.SS_STATUS_UNKNOWN, null);
2354             onComplete.sendToTarget();
2355         }
2356     }
2357 
2358     @Override
getAvailableNetworks(Message response)2359     public void getAvailableNetworks(Message response) {
2360         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
2361             Message msg = obtainMessage(EVENT_GET_AVAILABLE_NETWORKS_DONE, response);
2362             mCi.getAvailableNetworks(msg);
2363         } else {
2364             loge("getAvailableNetworks: not possible in CDMA");
2365         }
2366     }
2367 
2368     @Override
startNetworkScan(NetworkScanRequest nsr, Message response)2369     public void startNetworkScan(NetworkScanRequest nsr, Message response) {
2370         mCi.startNetworkScan(nsr, response);
2371     }
2372 
2373     @Override
stopNetworkScan(Message response)2374     public void stopNetworkScan(Message response) {
2375         mCi.stopNetworkScan(response);
2376     }
2377 
2378     @Override
setTTYMode(int ttyMode, Message onComplete)2379     public void setTTYMode(int ttyMode, Message onComplete) {
2380         // Send out the TTY Mode change over RIL as well
2381         super.setTTYMode(ttyMode, onComplete);
2382         if (mImsPhone != null) {
2383             mImsPhone.setTTYMode(ttyMode, onComplete);
2384         }
2385     }
2386 
2387     @Override
setUiTTYMode(int uiTtyMode, Message onComplete)2388     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
2389        if (mImsPhone != null) {
2390            mImsPhone.setUiTTYMode(uiTtyMode, onComplete);
2391        }
2392     }
2393 
2394     @Override
setMute(boolean muted)2395     public void setMute(boolean muted) {
2396         mCT.setMute(muted);
2397     }
2398 
2399     @Override
getMute()2400     public boolean getMute() {
2401         return mCT.getMute();
2402     }
2403 
2404     @Override
updateServiceLocation(WorkSource workSource)2405     public void updateServiceLocation(WorkSource workSource) {
2406         mSST.enableSingleLocationUpdate(workSource);
2407     }
2408 
2409     @Override
enableLocationUpdates()2410     public void enableLocationUpdates() {
2411         mSST.enableLocationUpdates();
2412     }
2413 
2414     @Override
disableLocationUpdates()2415     public void disableLocationUpdates() {
2416         mSST.disableLocationUpdates();
2417     }
2418 
2419     @Override
getDataRoamingEnabled()2420     public boolean getDataRoamingEnabled() {
2421         if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) {
2422             return getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getDataRoamingEnabled();
2423         }
2424         return false;
2425     }
2426 
2427     @Override
setDataRoamingEnabled(boolean enable)2428     public void setDataRoamingEnabled(boolean enable) {
2429         if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) {
2430             getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
2431                     .setDataRoamingEnabledByUser(enable);
2432         }
2433     }
2434 
2435     @Override
registerForCdmaOtaStatusChange(Handler h, int what, Object obj)2436     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
2437         mCi.registerForCdmaOtaProvision(h, what, obj);
2438     }
2439 
2440     @Override
unregisterForCdmaOtaStatusChange(Handler h)2441     public void unregisterForCdmaOtaStatusChange(Handler h) {
2442         mCi.unregisterForCdmaOtaProvision(h);
2443     }
2444 
2445     @Override
registerForSubscriptionInfoReady(Handler h, int what, Object obj)2446     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
2447         mSST.registerForSubscriptionInfoReady(h, what, obj);
2448     }
2449 
2450     @Override
unregisterForSubscriptionInfoReady(Handler h)2451     public void unregisterForSubscriptionInfoReady(Handler h) {
2452         mSST.unregisterForSubscriptionInfoReady(h);
2453     }
2454 
2455     @UnsupportedAppUsage
2456     @Override
setOnEcbModeExitResponse(Handler h, int what, Object obj)2457     public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
2458         mEcmExitRespRegistrant = new Registrant(h, what, obj);
2459     }
2460 
2461     @Override
unsetOnEcbModeExitResponse(Handler h)2462     public void unsetOnEcbModeExitResponse(Handler h) {
2463         mEcmExitRespRegistrant.clear();
2464     }
2465 
2466     @Override
registerForCallWaiting(Handler h, int what, Object obj)2467     public void registerForCallWaiting(Handler h, int what, Object obj) {
2468         mCT.registerForCallWaiting(h, what, obj);
2469     }
2470 
2471     @Override
unregisterForCallWaiting(Handler h)2472     public void unregisterForCallWaiting(Handler h) {
2473         mCT.unregisterForCallWaiting(h);
2474     }
2475 
2476     /**
2477      * Whether data is enabled by user. Unlike isDataEnabled, this only
2478      * checks user setting stored in {@link android.provider.Settings.Global#MOBILE_DATA}
2479      * if not provisioning, or isProvisioningDataEnabled if provisioning.
2480      */
2481     @Override
isUserDataEnabled()2482     public boolean isUserDataEnabled() {
2483         if (mDataEnabledSettings.isProvisioning()) {
2484             return mDataEnabledSettings.isProvisioningDataEnabled();
2485         } else {
2486             return mDataEnabledSettings.isUserDataEnabled();
2487         }
2488     }
2489 
2490     /**
2491      * Removes the given MMI from the pending list and notifies
2492      * registrants that it is complete.
2493      * @param mmi MMI that is done
2494      */
onMMIDone(MmiCode mmi)2495     public void onMMIDone(MmiCode mmi) {
2496 
2497         /* Only notify complete if it's on the pending list.
2498          * Otherwise, it's already been handled (eg, previously canceled).
2499          * The exception is cancellation of an incoming USSD-REQUEST, which is
2500          * not on the list.
2501          */
2502         if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
2503                 ((GsmMmiCode)mmi).isSsInfo()))) {
2504 
2505             ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
2506             if (receiverCallback != null) {
2507                 Rlog.i(LOG_TAG, "onMMIDone: invoking callback: " + mmi);
2508                 int returnCode = (mmi.getState() ==  MmiCode.State.COMPLETE) ?
2509                     TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
2510                 sendUssdResponse(mmi.getDialString(), mmi.getMessage(), returnCode,
2511                         receiverCallback );
2512             } else {
2513                 Rlog.i(LOG_TAG, "onMMIDone: notifying registrants: " + mmi);
2514                 mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
2515             }
2516         } else {
2517             Rlog.i(LOG_TAG, "onMMIDone: invalid response or already handled; ignoring: " + mmi);
2518         }
2519     }
2520 
supports3gppCallForwardingWhileRoaming()2521     public boolean supports3gppCallForwardingWhileRoaming() {
2522         CarrierConfigManager configManager = (CarrierConfigManager)
2523                 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
2524         PersistableBundle b = configManager.getConfigForSubId(getSubId());
2525         if (b != null) {
2526             return b.getBoolean(
2527                     CarrierConfigManager.KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
2528         } else {
2529             // Default value set in CarrierConfigManager
2530             return true;
2531         }
2532     }
2533 
onNetworkInitiatedUssd(MmiCode mmi)2534     private void onNetworkInitiatedUssd(MmiCode mmi) {
2535         Rlog.v(LOG_TAG, "onNetworkInitiatedUssd: mmi=" + mmi);
2536         mMmiCompleteRegistrants.notifyRegistrants(
2537             new AsyncResult(null, mmi, null));
2538     }
2539 
2540     /** ussdMode is one of CommandsInterface.USSD_MODE_* */
onIncomingUSSD(int ussdMode, String ussdMessage)2541     private void onIncomingUSSD (int ussdMode, String ussdMessage) {
2542         if (!isPhoneTypeGsm()) {
2543             loge("onIncomingUSSD: not expected on GSM");
2544         }
2545         boolean isUssdError;
2546         boolean isUssdRequest;
2547         boolean isUssdRelease;
2548 
2549         isUssdRequest
2550             = (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
2551 
2552         isUssdError
2553             = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
2554                 && ussdMode != CommandsInterface.USSD_MODE_REQUEST);
2555 
2556         isUssdRelease = (ussdMode == CommandsInterface.USSD_MODE_NW_RELEASE);
2557 
2558 
2559         // See comments in GsmMmiCode.java
2560         // USSD requests aren't finished until one
2561         // of these two events happen
2562         GsmMmiCode found = null;
2563         for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
2564             if(((GsmMmiCode)mPendingMMIs.get(i)).isPendingUSSD()) {
2565                 found = (GsmMmiCode)mPendingMMIs.get(i);
2566                 break;
2567             }
2568         }
2569 
2570         if (found != null) {
2571             // Complete pending USSD
2572 
2573             if (isUssdRelease) {
2574                 found.onUssdRelease();
2575             } else if (isUssdError) {
2576                 found.onUssdFinishedError();
2577             } else {
2578                 found.onUssdFinished(ussdMessage, isUssdRequest);
2579             }
2580         } else if (!isUssdError && !TextUtils.isEmpty(ussdMessage)) {
2581             // pending USSD not found
2582             // The network may initiate its own USSD request
2583 
2584             // ignore everything that isnt a Notify or a Request
2585             // also, discard if there is no message to present
2586             GsmMmiCode mmi;
2587             mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
2588                                                    isUssdRequest,
2589                                                    GsmCdmaPhone.this,
2590                                                    mUiccApplication.get());
2591             onNetworkInitiatedUssd(mmi);
2592         }
2593     }
2594 
2595     /**
2596      * Make sure the network knows our preferred setting.
2597      */
2598     @UnsupportedAppUsage
syncClirSetting()2599     private void syncClirSetting() {
2600         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
2601         migrateClirSettingIfNeeded(sp);
2602 
2603         int clirSetting = sp.getInt(CLIR_KEY + getSubId(), -1);
2604         Rlog.i(LOG_TAG, "syncClirSetting: " + CLIR_KEY + getSubId() + "=" + clirSetting);
2605         if (clirSetting >= 0) {
2606             mCi.setCLIR(clirSetting, null);
2607         }
2608     }
2609 
2610     /**
2611      * Migrate CLIR setting with sudId mapping once if there's CLIR setting mapped with phoneId.
2612      */
migrateClirSettingIfNeeded(SharedPreferences sp)2613     private void migrateClirSettingIfNeeded(SharedPreferences sp) {
2614         // Get old CLIR setting mapped with phoneId
2615         int clirSetting = sp.getInt("clir_key" + getPhoneId(), -1);
2616         if (clirSetting >= 0) {
2617             // Migrate CLIR setting to new shared preference key with subId
2618             Rlog.i(LOG_TAG, "Migrate CLIR setting: value=" + clirSetting + ", clir_key"
2619                     + getPhoneId() + " -> " + CLIR_KEY + getSubId());
2620             SharedPreferences.Editor editor = sp.edit();
2621             editor.putInt(CLIR_KEY + getSubId(), clirSetting);
2622 
2623             // Remove old CLIR setting key
2624             editor.remove("clir_key" + getPhoneId()).commit();
2625         }
2626     }
2627 
handleRadioAvailable()2628     private void handleRadioAvailable() {
2629         mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
2630 
2631         mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
2632         mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
2633         mCi.areUiccApplicationsEnabled(obtainMessage(EVENT_GET_UICC_APPS_ENABLEMENT_DONE));
2634 
2635         startLceAfterRadioIsAvailable();
2636     }
2637 
handleRadioOn()2638     private void handleRadioOn() {
2639         /* Proactively query voice radio technologies */
2640         mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
2641 
2642         if (!isPhoneTypeGsm()) {
2643             mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
2644         }
2645 
2646         // If this is on APM off, SIM may already be loaded. Send setPreferredNetworkType
2647         // request to RIL to preserve user setting across APM toggling
2648         setPreferredNetworkTypeIfSimLoaded();
2649     }
2650 
handleRadioOffOrNotAvailable()2651     private void handleRadioOffOrNotAvailable() {
2652         if (isPhoneTypeGsm()) {
2653             // Some MMI requests (eg USSD) are not completed
2654             // within the course of a CommandsInterface request
2655             // If the radio shuts off or resets while one of these
2656             // is pending, we need to clean up.
2657 
2658             for (int i = mPendingMMIs.size() - 1; i >= 0; i--) {
2659                 if (((GsmMmiCode) mPendingMMIs.get(i)).isPendingUSSD()) {
2660                     ((GsmMmiCode) mPendingMMIs.get(i)).onUssdFinishedError();
2661                 }
2662             }
2663         }
2664         mRadioOffOrNotAvailableRegistrants.notifyRegistrants();
2665     }
2666 
handleRadioPowerStateChange()2667     private void handleRadioPowerStateChange() {
2668         Rlog.d(LOG_TAG, "handleRadioPowerStateChange, state= " + mCi.getRadioState());
2669         mNotifier.notifyRadioPowerStateChanged(this, mCi.getRadioState());
2670     }
2671 
2672     @Override
handleMessage(Message msg)2673     public void handleMessage(Message msg) {
2674         AsyncResult ar;
2675         Message onComplete;
2676 
2677         switch (msg.what) {
2678             case EVENT_RADIO_AVAILABLE: {
2679                 handleRadioAvailable();
2680             }
2681             break;
2682 
2683             case EVENT_GET_DEVICE_IDENTITY_DONE:{
2684                 ar = (AsyncResult)msg.obj;
2685 
2686                 if (ar.exception != null) {
2687                     break;
2688                 }
2689                 String[] respId = (String[])ar.result;
2690                 mImei = respId[0];
2691                 mImeiSv = respId[1];
2692                 mEsn  =  respId[2];
2693                 mMeid =  respId[3];
2694             }
2695             break;
2696 
2697             case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
2698                 handleEnterEmergencyCallbackMode(msg);
2699             }
2700             break;
2701 
2702             case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
2703                 handleExitEmergencyCallbackMode(msg);
2704             }
2705             break;
2706 
2707             case EVENT_MODEM_RESET: {
2708                 logd("Event EVENT_MODEM_RESET Received" + " isInEcm = " + isInEcm()
2709                         + " isPhoneTypeGsm = " + isPhoneTypeGsm() + " mImsPhone = " + mImsPhone);
2710                 if (isInEcm()) {
2711                     if (isPhoneTypeGsm()) {
2712                         if (mImsPhone != null) {
2713                             mImsPhone.handleExitEmergencyCallbackMode();
2714                         }
2715                     } else {
2716                         handleExitEmergencyCallbackMode(msg);
2717                     }
2718                 }
2719             }
2720             break;
2721 
2722             case EVENT_RUIM_RECORDS_LOADED:
2723                 logd("Event EVENT_RUIM_RECORDS_LOADED Received");
2724                 updateCurrentCarrierInProvider();
2725                 break;
2726 
2727             case EVENT_RADIO_ON:
2728                 logd("Event EVENT_RADIO_ON Received");
2729                 handleRadioOn();
2730                 break;
2731 
2732             case EVENT_RIL_CONNECTED:
2733                 ar = (AsyncResult) msg.obj;
2734                 if (ar.exception == null && ar.result != null) {
2735                     mRilVersion = (Integer) ar.result;
2736                 } else {
2737                     logd("Unexpected exception on EVENT_RIL_CONNECTED");
2738                     mRilVersion = -1;
2739                 }
2740                 break;
2741 
2742             case EVENT_VOICE_RADIO_TECH_CHANGED:
2743             case EVENT_REQUEST_VOICE_RADIO_TECH_DONE:
2744                 String what = (msg.what == EVENT_VOICE_RADIO_TECH_CHANGED) ?
2745                         "EVENT_VOICE_RADIO_TECH_CHANGED" : "EVENT_REQUEST_VOICE_RADIO_TECH_DONE";
2746                 ar = (AsyncResult) msg.obj;
2747                 if (ar.exception == null) {
2748                     if ((ar.result != null) && (((int[]) ar.result).length != 0)) {
2749                         int newVoiceTech = ((int[]) ar.result)[0];
2750                         logd(what + ": newVoiceTech=" + newVoiceTech);
2751                         phoneObjectUpdater(newVoiceTech);
2752                     } else {
2753                         loge(what + ": has no tech!");
2754                     }
2755                 } else {
2756                     loge(what + ": exception=" + ar.exception);
2757                 }
2758                 break;
2759 
2760             case EVENT_UPDATE_PHONE_OBJECT:
2761                 phoneObjectUpdater(msg.arg1);
2762                 break;
2763 
2764             case EVENT_CARRIER_CONFIG_CHANGED:
2765                 // Only check for the voice radio tech if it not going to be updated by the voice
2766                 // registration changes.
2767                 if (!mContext.getResources().getBoolean(com.android.internal.R.bool.
2768                         config_switch_phone_on_voice_reg_state_change)) {
2769                     mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
2770                 }
2771                 // Force update IMS service if it is available, if it isn't the config will be
2772                 // updated when ImsPhoneCallTracker opens a connection.
2773                 ImsManager imsManager = ImsManager.getInstance(mContext, mPhoneId);
2774                 if (imsManager.isServiceAvailable()) {
2775                     imsManager.updateImsServiceConfig(true);
2776                 } else {
2777                     logd("ImsManager is not available to update CarrierConfig.");
2778                 }
2779 
2780                 // Update broadcastEmergencyCallStateChanges
2781                 CarrierConfigManager configMgr = (CarrierConfigManager)
2782                         getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
2783                 PersistableBundle b = configMgr.getConfigForSubId(getSubId());
2784                 if (b != null) {
2785                     boolean broadcastEmergencyCallStateChanges = b.getBoolean(
2786                             CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL);
2787                     logd("broadcastEmergencyCallStateChanges = " +
2788                             broadcastEmergencyCallStateChanges);
2789                     setBroadcastEmergencyCallStateChanges(broadcastEmergencyCallStateChanges);
2790                 } else {
2791                     loge("didn't get broadcastEmergencyCallStateChanges from carrier config");
2792                 }
2793 
2794                 // Changing the cdma roaming settings based carrier config.
2795                 if (b != null) {
2796                     int config_cdma_roaming_mode = b.getInt(
2797                             CarrierConfigManager.KEY_CDMA_ROAMING_MODE_INT);
2798                     int current_cdma_roaming_mode =
2799                             Settings.Global.getInt(getContext().getContentResolver(),
2800                             Settings.Global.CDMA_ROAMING_MODE,
2801                             TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT);
2802                     switch (config_cdma_roaming_mode) {
2803                         // Carrier's cdma_roaming_mode will overwrite the user's previous settings
2804                         // Keep the user's previous setting in global variable which will be used
2805                         // when carrier's setting is turn off.
2806                         case TelephonyManager.CDMA_ROAMING_MODE_HOME:
2807                         case TelephonyManager.CDMA_ROAMING_MODE_AFFILIATED:
2808                         case TelephonyManager.CDMA_ROAMING_MODE_ANY:
2809                             logd("cdma_roaming_mode is going to changed to "
2810                                     + config_cdma_roaming_mode);
2811                             setCdmaRoamingPreference(config_cdma_roaming_mode,
2812                                     obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
2813                             break;
2814 
2815                         // When carrier's setting is turn off, change the cdma_roaming_mode to the
2816                         // previous user's setting
2817                         case TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT:
2818                             if (current_cdma_roaming_mode != config_cdma_roaming_mode) {
2819                                 logd("cdma_roaming_mode is going to changed to "
2820                                         + current_cdma_roaming_mode);
2821                                 setCdmaRoamingPreference(current_cdma_roaming_mode,
2822                                         obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
2823                             }
2824 
2825                         default:
2826                             loge("Invalid cdma_roaming_mode settings: "
2827                                     + config_cdma_roaming_mode);
2828                     }
2829                 } else {
2830                     loge("didn't get the cdma_roaming_mode changes from the carrier config.");
2831                 }
2832                 break;
2833 
2834             case EVENT_SET_ROAMING_PREFERENCE_DONE:
2835                 logd("cdma_roaming_mode change is done");
2836                 break;
2837 
2838             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
2839                 logd("EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED");
2840                 mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
2841                 break;
2842 
2843             case EVENT_REGISTERED_TO_NETWORK:
2844                 logd("Event EVENT_REGISTERED_TO_NETWORK Received");
2845                 if (isPhoneTypeGsm()) {
2846                     syncClirSetting();
2847                 }
2848                 break;
2849 
2850             case EVENT_SIM_RECORDS_LOADED:
2851                 updateCurrentCarrierInProvider();
2852 
2853                 // Check if this is a different SIM than the previous one. If so unset the
2854                 // voice mail number.
2855                 String imsi = getVmSimImsi();
2856                 String imsiFromSIM = getSubscriberId();
2857                 if ((!isPhoneTypeGsm() || imsi != null) && imsiFromSIM != null
2858                         && !imsiFromSIM.equals(imsi)) {
2859                     storeVoiceMailNumber(null);
2860                     setVmSimImsi(null);
2861                 }
2862 
2863                 updateVoiceMail();
2864 
2865                 mSimRecordsLoadedRegistrants.notifyRegistrants();
2866                 break;
2867 
2868             case EVENT_GET_BASEBAND_VERSION_DONE:
2869                 ar = (AsyncResult)msg.obj;
2870 
2871                 if (ar.exception != null) {
2872                     break;
2873                 }
2874 
2875                 if (DBG) logd("Baseband version: " + ar.result);
2876                 TelephonyManager.from(mContext).setBasebandVersionForPhone(getPhoneId(),
2877                         (String)ar.result);
2878             break;
2879 
2880             case EVENT_GET_IMEI_DONE:
2881                 ar = (AsyncResult)msg.obj;
2882 
2883                 if (ar.exception != null) {
2884                     break;
2885                 }
2886 
2887                 mImei = (String)ar.result;
2888             break;
2889 
2890             case EVENT_GET_IMEISV_DONE:
2891                 ar = (AsyncResult)msg.obj;
2892 
2893                 if (ar.exception != null) {
2894                     break;
2895                 }
2896 
2897                 mImeiSv = (String)ar.result;
2898             break;
2899 
2900             case EVENT_USSD:
2901                 ar = (AsyncResult)msg.obj;
2902 
2903                 String[] ussdResult = (String[]) ar.result;
2904 
2905                 if (ussdResult.length > 1) {
2906                     try {
2907                         onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
2908                     } catch (NumberFormatException e) {
2909                         Rlog.w(LOG_TAG, "error parsing USSD");
2910                     }
2911                 }
2912             break;
2913 
2914             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: {
2915                 logd("Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
2916                 handleRadioOffOrNotAvailable();
2917                 break;
2918             }
2919 
2920             case EVENT_RADIO_STATE_CHANGED: {
2921                 logd("EVENT EVENT_RADIO_STATE_CHANGED");
2922                 handleRadioPowerStateChange();
2923                 break;
2924             }
2925 
2926             case EVENT_SSN:
2927                 logd("Event EVENT_SSN Received");
2928                 if (isPhoneTypeGsm()) {
2929                     ar = (AsyncResult) msg.obj;
2930                     SuppServiceNotification not = (SuppServiceNotification) ar.result;
2931                     mSsnRegistrants.notifyRegistrants(ar);
2932                 }
2933                 break;
2934 
2935             case EVENT_REGISTRATION_FAILED:
2936                 logd("Event RegistrationFailed Received");
2937                 ar = (AsyncResult) msg.obj;
2938                 RegistrationFailedEvent rfe = (RegistrationFailedEvent) ar.result;
2939                 mNotifier.notifyRegistrationFailed(this, rfe.cellIdentity, rfe.chosenPlmn,
2940                         rfe.domain, rfe.causeCode, rfe.additionalCauseCode);
2941                 break;
2942 
2943             case EVENT_BARRING_INFO_CHANGED:
2944                 logd("Event BarringInfoChanged Received");
2945                 ar = (AsyncResult) msg.obj;
2946                 BarringInfo barringInfo = (BarringInfo) ar.result;
2947                 mNotifier.notifyBarringInfoChanged(this, barringInfo);
2948                 break;
2949 
2950             case EVENT_SET_CALL_FORWARD_DONE:
2951                 ar = (AsyncResult)msg.obj;
2952                 Cfu cfu = (Cfu) ar.userObj;
2953                 if (ar.exception == null) {
2954                     setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber);
2955                 }
2956                 if (cfu.mOnComplete != null) {
2957                     AsyncResult.forMessage(cfu.mOnComplete, ar.result, ar.exception);
2958                     cfu.mOnComplete.sendToTarget();
2959                 }
2960                 break;
2961 
2962             case EVENT_SET_VM_NUMBER_DONE:
2963                 ar = (AsyncResult)msg.obj;
2964                 if (((isPhoneTypeGsm() || mSimRecords != null)
2965                         && IccVmNotSupportedException.class.isInstance(ar.exception))
2966                         || (!isPhoneTypeGsm() && mSimRecords == null
2967                         && IccException.class.isInstance(ar.exception))) {
2968                     storeVoiceMailNumber(mVmNumber);
2969                     ar.exception = null;
2970                 }
2971                 onComplete = (Message) ar.userObj;
2972                 if (onComplete != null) {
2973                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2974                     onComplete.sendToTarget();
2975                 }
2976                 break;
2977 
2978 
2979             case EVENT_GET_CALL_FORWARD_DONE:
2980                 ar = (AsyncResult)msg.obj;
2981                 if (ar.exception == null) {
2982                     handleCfuQueryResult((CallForwardInfo[])ar.result);
2983                 }
2984                 onComplete = (Message) ar.userObj;
2985                 if (onComplete != null) {
2986                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2987                     onComplete.sendToTarget();
2988                 }
2989                 break;
2990 
2991             case EVENT_SET_NETWORK_AUTOMATIC:
2992                 // Automatic network selection from EF_CSP SIM record
2993                 ar = (AsyncResult) msg.obj;
2994                 if (mSST.mSS.getIsManualSelection()) {
2995                     setNetworkSelectionModeAutomatic((Message) ar.result);
2996                     logd("SET_NETWORK_SELECTION_AUTOMATIC: set to automatic");
2997                 } else {
2998                     // prevent duplicate request which will push current PLMN to low priority
2999                     logd("SET_NETWORK_SELECTION_AUTOMATIC: already automatic, ignore");
3000                 }
3001                 break;
3002 
3003             case EVENT_ICC_RECORD_EVENTS:
3004                 ar = (AsyncResult)msg.obj;
3005                 processIccRecordEvents((Integer)ar.result);
3006                 break;
3007 
3008             case EVENT_SET_CLIR_COMPLETE:
3009                 ar = (AsyncResult)msg.obj;
3010                 if (ar.exception == null) {
3011                     saveClirSetting(msg.arg1);
3012                 }
3013                 onComplete = (Message) ar.userObj;
3014                 if (onComplete != null) {
3015                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
3016                     onComplete.sendToTarget();
3017                 }
3018                 break;
3019 
3020             case EVENT_SS:
3021                 ar = (AsyncResult)msg.obj;
3022                 logd("Event EVENT_SS received");
3023                 if (isPhoneTypeGsm()) {
3024                     // SS data is already being handled through MMI codes.
3025                     // So, this result if processed as MMI response would help
3026                     // in re-using the existing functionality.
3027                     GsmMmiCode mmi = new GsmMmiCode(this, mUiccApplication.get());
3028                     mmi.processSsData(ar);
3029                 }
3030                 break;
3031 
3032             case EVENT_GET_RADIO_CAPABILITY:
3033                 ar = (AsyncResult) msg.obj;
3034                 RadioCapability rc = (RadioCapability) ar.result;
3035                 if (ar.exception != null) {
3036                     Rlog.d(LOG_TAG, "get phone radio capability fail, no need to change " +
3037                             "mRadioCapability");
3038                 } else {
3039                     radioCapabilityUpdated(rc);
3040                 }
3041                 Rlog.d(LOG_TAG, "EVENT_GET_RADIO_CAPABILITY: phone rc: " + rc);
3042                 break;
3043             case EVENT_VRS_OR_RAT_CHANGED:
3044                 ar = (AsyncResult) msg.obj;
3045                 Pair<Integer, Integer> vrsRatPair = (Pair<Integer, Integer>) ar.result;
3046                 onVoiceRegStateOrRatChanged(vrsRatPair.first, vrsRatPair.second);
3047                 break;
3048 
3049             case EVENT_SET_CARRIER_DATA_ENABLED:
3050                 ar = (AsyncResult) msg.obj;
3051                 boolean enabled = (boolean) ar.result;
3052                 mDataEnabledSettings.setCarrierDataEnabled(enabled);
3053                 break;
3054             case EVENT_DEVICE_PROVISIONED_CHANGE:
3055                 mDataEnabledSettings.updateProvisionedChanged();
3056                 break;
3057             case EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE:
3058                 mDataEnabledSettings.updateProvisioningDataEnabled();
3059                 break;
3060             case EVENT_GET_AVAILABLE_NETWORKS_DONE:
3061                 ar = (AsyncResult) msg.obj;
3062                 if (ar.exception == null && ar.result != null && mSST != null) {
3063                     List<OperatorInfo> operatorInfoList = (List<OperatorInfo>) ar.result;
3064                     List<OperatorInfo> filteredInfoList = new ArrayList<>();
3065                     for (OperatorInfo operatorInfo : operatorInfoList) {
3066                         if (OperatorInfo.State.CURRENT == operatorInfo.getState()) {
3067                             filteredInfoList.add(new OperatorInfo(
3068                                     mSST.filterOperatorNameByPattern(
3069                                             operatorInfo.getOperatorAlphaLong()),
3070                                     mSST.filterOperatorNameByPattern(
3071                                             operatorInfo.getOperatorAlphaShort()),
3072                                     operatorInfo.getOperatorNumeric(),
3073                                     operatorInfo.getState()
3074                             ));
3075                         } else {
3076                             filteredInfoList.add(operatorInfo);
3077                         }
3078                     }
3079                     ar.result = filteredInfoList;
3080                 }
3081 
3082                 onComplete = (Message) ar.userObj;
3083                 if (onComplete != null) {
3084                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
3085                     onComplete.sendToTarget();
3086                 }
3087                 break;
3088             case EVENT_GET_UICC_APPS_ENABLEMENT_DONE:
3089             case EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED:
3090                 ar = (AsyncResult) msg.obj;
3091                 if (ar == null) return;
3092                 if (ar.exception != null) {
3093                     logd("Received exception on event" + msg.what + " : " + ar.exception);
3094                     return;
3095                 }
3096 
3097                 mUiccApplicationsEnabled = (Boolean) ar.result;
3098             // Intentional falling through.
3099             case EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED:
3100                 reapplyUiccAppsEnablementIfNeeded(ENABLE_UICC_APPS_MAX_RETRIES);
3101                 break;
3102 
3103             case EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE: {
3104                 ar = (AsyncResult) msg.obj;
3105                 if (ar == null || ar.exception == null) return;
3106                 Pair<Boolean, Integer> userObject = (Pair) ar.userObj;
3107                 if (userObject == null) return;
3108                 boolean expectedValue = userObject.first;
3109                 int retries = userObject.second;
3110                 CommandException.Error error = ((CommandException) ar.exception).getCommandError();
3111                 loge("Error received when re-applying uicc application"
3112                         + " setting to " +  expectedValue + " on phone " + mPhoneId
3113                         + " Error code: " + error + " retry count left: " + retries);
3114                 if (retries > 0 && (error == GENERIC_FAILURE || error == SIM_BUSY)) {
3115                     // Retry for certain errors, but not for others like RADIO_NOT_AVAILABLE or
3116                     // SIM_ABSENT, as they will trigger it whey they become available.
3117                     postDelayed(()->reapplyUiccAppsEnablementIfNeeded(retries - 1),
3118                             REAPPLY_UICC_APPS_SETTING_RETRY_TIME_GAP_IN_MS);
3119                 }
3120                 break;
3121             }
3122             default:
3123                 super.handleMessage(msg);
3124         }
3125     }
3126 
getUiccCardApplication()3127     public UiccCardApplication getUiccCardApplication() {
3128         if (isPhoneTypeGsm()) {
3129             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP);
3130         } else {
3131             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
3132         }
3133     }
3134 
3135     // todo: check if ICC availability needs to be handled here. mSimRecords should not be needed
3136     // now because APIs can be called directly on UiccProfile, and that should handle the requests
3137     // correctly based on supported apps, voice RAT, etc.
3138     @Override
onUpdateIccAvailability()3139     protected void onUpdateIccAvailability() {
3140         if (mUiccController == null ) {
3141             return;
3142         }
3143 
3144         UiccCardApplication newUiccApplication = null;
3145 
3146         // Update mIsimUiccRecords
3147         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
3148             newUiccApplication =
3149                     mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS);
3150             IsimUiccRecords newIsimUiccRecords = null;
3151 
3152             if (newUiccApplication != null) {
3153                 newIsimUiccRecords = (IsimUiccRecords) newUiccApplication.getIccRecords();
3154                 if (DBG) logd("New ISIM application found");
3155             }
3156             mIsimUiccRecords = newIsimUiccRecords;
3157         }
3158 
3159         // Update mSimRecords
3160         if (mSimRecords != null) {
3161             mSimRecords.unregisterForRecordsLoaded(this);
3162         }
3163         if (isPhoneTypeCdmaLte() || isPhoneTypeCdma()) {
3164             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
3165                     UiccController.APP_FAM_3GPP);
3166             SIMRecords newSimRecords = null;
3167             if (newUiccApplication != null) {
3168                 newSimRecords = (SIMRecords) newUiccApplication.getIccRecords();
3169             }
3170             mSimRecords = newSimRecords;
3171             if (mSimRecords != null) {
3172                 mSimRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
3173             }
3174         } else {
3175             mSimRecords = null;
3176         }
3177 
3178         // Update mIccRecords, mUiccApplication, mIccPhoneBookIntManager
3179         newUiccApplication = getUiccCardApplication();
3180         if (!isPhoneTypeGsm() && newUiccApplication == null) {
3181             logd("can't find 3GPP2 application; trying APP_FAM_3GPP");
3182             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
3183                     UiccController.APP_FAM_3GPP);
3184         }
3185 
3186         UiccCardApplication app = mUiccApplication.get();
3187         if (app != newUiccApplication) {
3188             if (app != null) {
3189                 if (DBG) logd("Removing stale icc objects.");
3190                 if (mIccRecords.get() != null) {
3191                     unregisterForIccRecordEvents();
3192                     mIccPhoneBookIntManager.updateIccRecords(null);
3193                 }
3194                 mIccRecords.set(null);
3195                 mUiccApplication.set(null);
3196             }
3197             if (newUiccApplication != null) {
3198                 if (DBG) {
3199                     logd("New Uicc application found. type = " + newUiccApplication.getType());
3200                 }
3201                 final IccRecords iccRecords = newUiccApplication.getIccRecords();
3202                 mUiccApplication.set(newUiccApplication);
3203                 mIccRecords.set(iccRecords);
3204                 registerForIccRecordEvents();
3205                 mIccPhoneBookIntManager.updateIccRecords(iccRecords);
3206                 if (iccRecords != null) {
3207                     final String simOperatorNumeric = iccRecords.getOperatorNumeric();
3208                     if (DBG) {
3209                         logd("New simOperatorNumeric = " + simOperatorNumeric);
3210                     }
3211                     if (!TextUtils.isEmpty(simOperatorNumeric)) {
3212                         TelephonyManager.from(mContext).setSimOperatorNumericForPhone(mPhoneId,
3213                                 simOperatorNumeric);
3214                     }
3215                 }
3216                 updateCurrentCarrierInProvider();
3217             }
3218         }
3219 
3220         reapplyUiccAppsEnablementIfNeeded(ENABLE_UICC_APPS_MAX_RETRIES);
3221     }
3222 
processIccRecordEvents(int eventCode)3223     private void processIccRecordEvents(int eventCode) {
3224         switch (eventCode) {
3225             case IccRecords.EVENT_CFI:
3226                 logi("processIccRecordEvents: EVENT_CFI");
3227                 notifyCallForwardingIndicator();
3228                 break;
3229         }
3230     }
3231 
3232     /**
3233      * Sets the "current" field in the telephony provider according to the SIM's operator
3234      *
3235      * @return true for success; false otherwise.
3236      */
3237     @Override
updateCurrentCarrierInProvider()3238     public boolean updateCurrentCarrierInProvider() {
3239         long currentDds = SubscriptionManager.getDefaultDataSubscriptionId();
3240         String operatorNumeric = getOperatorNumeric();
3241 
3242         logd("updateCurrentCarrierInProvider: mSubId = " + getSubId()
3243                 + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric);
3244 
3245         if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) {
3246             try {
3247                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
3248                 ContentValues map = new ContentValues();
3249                 map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
3250                 mContext.getContentResolver().insert(uri, map);
3251                 return true;
3252             } catch (SQLException e) {
3253                 Rlog.e(LOG_TAG, "Can't store current operator", e);
3254             }
3255         }
3256         return false;
3257     }
3258 
3259     //CDMA
3260     /**
3261      * Sets the "current" field in the telephony provider according to the
3262      * build-time operator numeric property
3263      *
3264      * @return true for success; false otherwise.
3265      */
updateCurrentCarrierInProvider(String operatorNumeric)3266     private boolean updateCurrentCarrierInProvider(String operatorNumeric) {
3267         if (isPhoneTypeCdma()
3268                 || (isPhoneTypeCdmaLte() && mUiccController.getUiccCardApplication(mPhoneId,
3269                         UiccController.APP_FAM_3GPP) == null)) {
3270             logd("CDMAPhone: updateCurrentCarrierInProvider called");
3271             if (!TextUtils.isEmpty(operatorNumeric)) {
3272                 try {
3273                     Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
3274                     ContentValues map = new ContentValues();
3275                     map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
3276                     logd("updateCurrentCarrierInProvider from system: numeric=" + operatorNumeric);
3277                     getContext().getContentResolver().insert(uri, map);
3278 
3279                     // Updates MCC MNC device configuration information
3280                     logd("update mccmnc=" + operatorNumeric);
3281                     MccTable.updateMccMncConfiguration(mContext, operatorNumeric);
3282 
3283                     return true;
3284                 } catch (SQLException e) {
3285                     Rlog.e(LOG_TAG, "Can't store current operator", e);
3286                 }
3287             }
3288             return false;
3289         } else { // isPhoneTypeCdmaLte()
3290             if (DBG) logd("updateCurrentCarrierInProvider not updated X retVal=" + true);
3291             return true;
3292         }
3293     }
3294 
handleCfuQueryResult(CallForwardInfo[] infos)3295     private void handleCfuQueryResult(CallForwardInfo[] infos) {
3296         if (infos == null || infos.length == 0) {
3297             // Assume the default is not active
3298             // Set unconditional CFF in SIM to false
3299             setVoiceCallForwardingFlag(1, false, null);
3300         } else {
3301             for (int i = 0, s = infos.length; i < s; i++) {
3302                 if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
3303                     setVoiceCallForwardingFlag(1, (infos[i].status == 1),
3304                         infos[i].number);
3305                     // should only have the one
3306                     break;
3307                 }
3308             }
3309         }
3310     }
3311 
3312     /**
3313      * Retrieves the IccPhoneBookInterfaceManager of the GsmCdmaPhone
3314      */
3315     @Override
getIccPhoneBookInterfaceManager()3316     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
3317         return mIccPhoneBookIntManager;
3318     }
3319 
3320     /**
3321      * Activate or deactivate cell broadcast SMS.
3322      *
3323      * @param activate 0 = activate, 1 = deactivate
3324      * @param response Callback message is empty on completion
3325      */
3326     @Override
activateCellBroadcastSms(int activate, Message response)3327     public void activateCellBroadcastSms(int activate, Message response) {
3328         loge("[GsmCdmaPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
3329         response.sendToTarget();
3330     }
3331 
3332     /**
3333      * Query the current configuration of cdma cell broadcast SMS.
3334      *
3335      * @param response Callback message is empty on completion
3336      */
3337     @Override
getCellBroadcastSmsConfig(Message response)3338     public void getCellBroadcastSmsConfig(Message response) {
3339         loge("[GsmCdmaPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
3340         response.sendToTarget();
3341     }
3342 
3343     /**
3344      * Configure cdma cell broadcast SMS.
3345      *
3346      * @param response Callback message is empty on completion
3347      */
3348     @Override
setCellBroadcastSmsConfig(int[] configValuesArray, Message response)3349     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
3350         loge("[GsmCdmaPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
3351         response.sendToTarget();
3352     }
3353 
3354     /**
3355      * Returns true if OTA Service Provisioning needs to be performed.
3356      */
3357     @Override
needsOtaServiceProvisioning()3358     public boolean needsOtaServiceProvisioning() {
3359         if (isPhoneTypeGsm()) {
3360             return false;
3361         } else {
3362             return mSST.getOtasp() != TelephonyManager.OTASP_NOT_NEEDED;
3363         }
3364     }
3365 
3366     @Override
isCspPlmnEnabled()3367     public boolean isCspPlmnEnabled() {
3368         IccRecords r = mIccRecords.get();
3369         return (r != null) ? r.isCspPlmnEnabled() : false;
3370     }
3371 
3372     /**
3373      * Whether manual select is now allowed and we should set
3374      * to auto network select mode.
3375      */
shouldForceAutoNetworkSelect()3376     public boolean shouldForceAutoNetworkSelect() {
3377 
3378         int nwMode = Phone.PREFERRED_NT_MODE;
3379         int subId = getSubId();
3380 
3381         // If it's invalid subId, we shouldn't force to auto network select mode.
3382         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
3383             return false;
3384         }
3385 
3386         nwMode = android.provider.Settings.Global.getInt(mContext.getContentResolver(),
3387                     android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, nwMode);
3388 
3389         logd("shouldForceAutoNetworkSelect in mode = " + nwMode);
3390         /*
3391          *  For multimode targets in global mode manual network
3392          *  selection is disallowed. So we should force auto select mode.
3393          */
3394         if (isManualSelProhibitedInGlobalMode()
3395                 && ((nwMode == TelephonyManager.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
3396                         || (nwMode == TelephonyManager.NETWORK_MODE_GLOBAL)) ){
3397             logd("Should force auto network select mode = " + nwMode);
3398             return true;
3399         } else {
3400             logd("Should not force auto network select mode = " + nwMode);
3401         }
3402 
3403         /*
3404          *  Single mode phone with - GSM network modes/global mode
3405          *  LTE only for 3GPP
3406          *  LTE centric + 3GPP Legacy
3407          *  Note: the actual enabling/disabling manual selection for these
3408          *  cases will be controlled by csp
3409          */
3410         return false;
3411     }
3412 
3413     @UnsupportedAppUsage
isManualSelProhibitedInGlobalMode()3414     private boolean isManualSelProhibitedInGlobalMode() {
3415         boolean isProhibited = false;
3416         final String configString = getContext().getResources().getString(com.android.internal.
3417                 R.string.prohibit_manual_network_selection_in_gobal_mode);
3418 
3419         if (!TextUtils.isEmpty(configString)) {
3420             String[] configArray = configString.split(";");
3421 
3422             if (configArray != null &&
3423                     ((configArray.length == 1 && configArray[0].equalsIgnoreCase("true")) ||
3424                         (configArray.length == 2 && !TextUtils.isEmpty(configArray[1]) &&
3425                             configArray[0].equalsIgnoreCase("true") &&
3426                             isMatchGid(configArray[1])))) {
3427                             isProhibited = true;
3428             }
3429         }
3430         logd("isManualNetSelAllowedInGlobal in current carrier is " + isProhibited);
3431         return isProhibited;
3432     }
3433 
registerForIccRecordEvents()3434     private void registerForIccRecordEvents() {
3435         IccRecords r = mIccRecords.get();
3436         if (r == null) {
3437             return;
3438         }
3439         if (isPhoneTypeGsm()) {
3440             r.registerForNetworkSelectionModeAutomatic(
3441                     this, EVENT_SET_NETWORK_AUTOMATIC, null);
3442             r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
3443             r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
3444         } else {
3445             r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
3446             if (isPhoneTypeCdmaLte()) {
3447                 // notify simRecordsLoaded registrants for cdmaLte phone
3448                 r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
3449             }
3450         }
3451     }
3452 
unregisterForIccRecordEvents()3453     private void unregisterForIccRecordEvents() {
3454         IccRecords r = mIccRecords.get();
3455         if (r == null) {
3456             return;
3457         }
3458         r.unregisterForNetworkSelectionModeAutomatic(this);
3459         r.unregisterForRecordsEvents(this);
3460         r.unregisterForRecordsLoaded(this);
3461     }
3462 
3463     @UnsupportedAppUsage
3464     @Override
exitEmergencyCallbackMode()3465     public void exitEmergencyCallbackMode() {
3466         if (DBG) {
3467             Rlog.d(LOG_TAG, "exitEmergencyCallbackMode: mImsPhone=" + mImsPhone
3468                     + " isPhoneTypeGsm=" + isPhoneTypeGsm());
3469         }
3470         if (mImsPhone != null && mImsPhone.isInImsEcm()) {
3471             mImsPhone.exitEmergencyCallbackMode();
3472         } else {
3473             if (mWakeLock.isHeld()) {
3474                 mWakeLock.release();
3475             }
3476             Message msg = null;
3477             if (mIsTestingEmergencyCallbackMode) {
3478                 // prevent duplicate exit messages from happening due to this message being handled
3479                 // as well as an UNSOL when the modem exits ECbM. Instead, only register for this
3480                 // message callback when this is a test and we will not be receiving the UNSOL from
3481                 // the modem.
3482                 msg = obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE);
3483             }
3484             mCi.exitEmergencyCallbackMode(msg);
3485         }
3486     }
3487 
3488     //CDMA
handleEnterEmergencyCallbackMode(Message msg)3489     private void handleEnterEmergencyCallbackMode(Message msg) {
3490         if (DBG) {
3491             Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode, isInEcm()="
3492                     + isInEcm());
3493         }
3494         // if phone is not in Ecm mode, and it's changed to Ecm mode
3495         if (!isInEcm()) {
3496             setIsInEcm(true);
3497 
3498             // notify change
3499             sendEmergencyCallbackModeChange();
3500 
3501             // Post this runnable so we will automatically exit
3502             // if no one invokes exitEmergencyCallbackMode() directly.
3503             long delayInMillis = TelephonyProperties.ecm_exit_timer()
3504                     .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE);
3505             postDelayed(mExitEcmRunnable, delayInMillis);
3506             // We don't want to go to sleep while in Ecm
3507             mWakeLock.acquire();
3508         }
3509     }
3510 
3511     //CDMA
handleExitEmergencyCallbackMode(Message msg)3512     private void handleExitEmergencyCallbackMode(Message msg) {
3513         AsyncResult ar = (AsyncResult)msg.obj;
3514         if (DBG) {
3515             Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , isInEcm="
3516                     + ar.exception + isInEcm());
3517         }
3518         // Remove pending exit Ecm runnable, if any
3519         removeCallbacks(mExitEcmRunnable);
3520 
3521         if (mEcmExitRespRegistrant != null) {
3522             mEcmExitRespRegistrant.notifyRegistrant(ar);
3523         }
3524         // if exiting is successful or we are testing and the modem responded with an error upon
3525         // exit, which may occur in some IRadio implementations.
3526         if (ar.exception == null || mIsTestingEmergencyCallbackMode) {
3527             if (isInEcm()) {
3528                 setIsInEcm(false);
3529             }
3530 
3531             // release wakeLock
3532             if (mWakeLock.isHeld()) {
3533                 mWakeLock.release();
3534             }
3535 
3536             // send an Intent
3537             sendEmergencyCallbackModeChange();
3538             // Re-initiate data connection
3539             mDataEnabledSettings.setInternalDataEnabled(true);
3540             notifyEmergencyCallRegistrants(false);
3541         }
3542         mIsTestingEmergencyCallbackMode = false;
3543     }
3544 
3545     //CDMA
notifyEmergencyCallRegistrants(boolean started)3546     public void notifyEmergencyCallRegistrants(boolean started) {
3547         mEmergencyCallToggledRegistrants.notifyResult(started ? 1 : 0);
3548     }
3549 
3550     //CDMA
3551     /**
3552      * Handle to cancel or restart Ecm timer in emergency call back mode
3553      * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
3554      * otherwise, restart Ecm timer and notify apps the timer is restarted.
3555      */
handleTimerInEmergencyCallbackMode(int action)3556     public void handleTimerInEmergencyCallbackMode(int action) {
3557         switch(action) {
3558             case CANCEL_ECM_TIMER:
3559                 removeCallbacks(mExitEcmRunnable);
3560                 mEcmTimerResetRegistrants.notifyResult(Boolean.TRUE);
3561                 setEcmCanceledForEmergency(true /*isCanceled*/);
3562                 break;
3563             case RESTART_ECM_TIMER:
3564                 long delayInMillis = TelephonyProperties.ecm_exit_timer()
3565                         .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE);
3566                 postDelayed(mExitEcmRunnable, delayInMillis);
3567                 mEcmTimerResetRegistrants.notifyResult(Boolean.FALSE);
3568                 setEcmCanceledForEmergency(false /*isCanceled*/);
3569                 break;
3570             default:
3571                 Rlog.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
3572         }
3573     }
3574 
3575     //CDMA
3576     private static final String IS683A_FEATURE_CODE = "*228";
3577     private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
3578     private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
3579     private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
3580 
3581     private static final int IS683_CONST_800MHZ_A_BAND = 0;
3582     private static final int IS683_CONST_800MHZ_B_BAND = 1;
3583     private static final int IS683_CONST_1900MHZ_A_BLOCK = 2;
3584     private static final int IS683_CONST_1900MHZ_B_BLOCK = 3;
3585     private static final int IS683_CONST_1900MHZ_C_BLOCK = 4;
3586     private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
3587     private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
3588     private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
3589     private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
3590 
3591     // Define the pattern/format for carrier specified OTASP number schema.
3592     // It separates by comma and/or whitespace.
3593     private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
3594 
3595     //CDMA
isIs683OtaSpDialStr(String dialStr)3596     private static boolean isIs683OtaSpDialStr(String dialStr) {
3597         int sysSelCodeInt;
3598         boolean isOtaspDialString = false;
3599         int dialStrLen = dialStr.length();
3600 
3601         if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) {
3602             if (dialStr.equals(IS683A_FEATURE_CODE)) {
3603                 isOtaspDialString = true;
3604             }
3605         } else {
3606             sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
3607             switch (sysSelCodeInt) {
3608                 case IS683_CONST_800MHZ_A_BAND:
3609                 case IS683_CONST_800MHZ_B_BAND:
3610                 case IS683_CONST_1900MHZ_A_BLOCK:
3611                 case IS683_CONST_1900MHZ_B_BLOCK:
3612                 case IS683_CONST_1900MHZ_C_BLOCK:
3613                 case IS683_CONST_1900MHZ_D_BLOCK:
3614                 case IS683_CONST_1900MHZ_E_BLOCK:
3615                 case IS683_CONST_1900MHZ_F_BLOCK:
3616                     isOtaspDialString = true;
3617                     break;
3618                 default:
3619                     break;
3620             }
3621         }
3622         return isOtaspDialString;
3623     }
3624 
3625     //CDMA
3626     /**
3627      * This function extracts the system selection code from the dial string.
3628      */
extractSelCodeFromOtaSpNum(String dialStr)3629     private static int extractSelCodeFromOtaSpNum(String dialStr) {
3630         int dialStrLen = dialStr.length();
3631         int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
3632 
3633         if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
3634                 0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
3635                 (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
3636                         IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
3637             // Since we checked the condition above, the system selection code
3638             // extracted from dialStr will not cause any exception
3639             sysSelCodeInt = Integer.parseInt (
3640                     dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
3641                             IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
3642         }
3643         if (DBG) Rlog.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
3644         return sysSelCodeInt;
3645     }
3646 
3647     //CDMA
3648     /**
3649      * This function checks if the system selection code extracted from
3650      * the dial string "sysSelCodeInt' is the system selection code specified
3651      * in the carrier ota sp number schema "sch".
3652      */
checkOtaSpNumBasedOnSysSelCode(int sysSelCodeInt, String sch[])3653     private static boolean checkOtaSpNumBasedOnSysSelCode(int sysSelCodeInt, String sch[]) {
3654         boolean isOtaSpNum = false;
3655         try {
3656             // Get how many number of system selection code ranges
3657             int selRc = Integer.parseInt(sch[1]);
3658             for (int i = 0; i < selRc; i++) {
3659                 if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
3660                     int selMin = Integer.parseInt(sch[i+2]);
3661                     int selMax = Integer.parseInt(sch[i+3]);
3662                     // Check if the selection code extracted from the dial string falls
3663                     // within any of the range pairs specified in the schema.
3664                     if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
3665                         isOtaSpNum = true;
3666                         break;
3667                     }
3668                 }
3669             }
3670         } catch (NumberFormatException ex) {
3671             // If the carrier ota sp number schema is not correct, we still allow dial
3672             // and only log the error:
3673             Rlog.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
3674         }
3675         return isOtaSpNum;
3676     }
3677 
3678     //CDMA
3679     /**
3680      * The following function checks if a dial string is a carrier specified
3681      * OTASP number or not by checking against the OTASP number schema stored
3682      * in PROPERTY_OTASP_NUM_SCHEMA.
3683      *
3684      * Currently, there are 2 schemas for carriers to specify the OTASP number:
3685      * 1) Use system selection code:
3686      *    The schema is:
3687      *    SELC,the # of code pairs,min1,max1,min2,max2,...
3688      *    e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
3689      *    selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
3690      *
3691      * 2) Use feature code:
3692      *    The schema is:
3693      *    "FC,length of feature code,feature code".
3694      *     e.g "FC,2,*2" indicates that the length of the feature code is 2,
3695      *     and the code itself is "*2".
3696      */
isCarrierOtaSpNum(String dialStr)3697     private boolean isCarrierOtaSpNum(String dialStr) {
3698         boolean isOtaSpNum = false;
3699         int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
3700         if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
3701             return isOtaSpNum;
3702         }
3703         // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
3704         if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
3705             Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
3706             if (DBG) {
3707                 Rlog.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
3708             }
3709 
3710             if (m.find()) {
3711                 String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
3712                 // If carrier uses system selection code mechanism
3713                 if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
3714                     if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
3715                         isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
3716                     } else {
3717                         if (DBG) {
3718                             Rlog.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
3719                         }
3720                     }
3721                 } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
3722                     int fcLen =  Integer.parseInt(sch[1]);
3723                     String fc = sch[2];
3724                     if (dialStr.regionMatches(0,fc,0,fcLen)) {
3725                         isOtaSpNum = true;
3726                     } else {
3727                         if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
3728                     }
3729                 } else {
3730                     if (DBG) {
3731                         Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
3732                     }
3733                 }
3734             } else {
3735                 if (DBG) {
3736                     Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
3737                             mCarrierOtaSpNumSchema);
3738                 }
3739             }
3740         } else {
3741             if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
3742         }
3743         return isOtaSpNum;
3744     }
3745 
3746     /**
3747      * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
3748      * OTASP dial string.
3749      *
3750      * @param dialStr the number to look up.
3751      * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
3752      */
3753     @Override
isOtaSpNumber(String dialStr)3754     public  boolean isOtaSpNumber(String dialStr) {
3755         if (isPhoneTypeGsm()) {
3756             return super.isOtaSpNumber(dialStr);
3757         } else {
3758             boolean isOtaSpNum = false;
3759             String dialableStr = PhoneNumberUtils.extractNetworkPortionAlt(dialStr);
3760             if (dialableStr != null) {
3761                 isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
3762                 if (isOtaSpNum == false) {
3763                     isOtaSpNum = isCarrierOtaSpNum(dialableStr);
3764                 }
3765             }
3766             if (DBG) Rlog.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
3767             return isOtaSpNum;
3768         }
3769     }
3770 
3771     @Override
getOtasp()3772     public int getOtasp() {
3773         return mSST.getOtasp();
3774     }
3775 
3776     @Override
getCdmaEriIconIndex()3777     public int getCdmaEriIconIndex() {
3778         if (isPhoneTypeGsm()) {
3779             return super.getCdmaEriIconIndex();
3780         } else {
3781             return getServiceState().getCdmaEriIconIndex();
3782         }
3783     }
3784 
3785     /**
3786      * Returns the CDMA ERI icon mode,
3787      * 0 - ON
3788      * 1 - FLASHING
3789      */
3790     @Override
getCdmaEriIconMode()3791     public int getCdmaEriIconMode() {
3792         if (isPhoneTypeGsm()) {
3793             return super.getCdmaEriIconMode();
3794         } else {
3795             return getServiceState().getCdmaEriIconMode();
3796         }
3797     }
3798 
3799     /**
3800      * Returns the CDMA ERI text,
3801      */
3802     @UnsupportedAppUsage
3803     @Override
getCdmaEriText()3804     public String getCdmaEriText() {
3805         if (isPhoneTypeGsm()) {
3806             return super.getCdmaEriText();
3807         } else {
3808             int roamInd = getServiceState().getCdmaRoamingIndicator();
3809             int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
3810             return mSST.getCdmaEriText(roamInd, defRoamInd);
3811         }
3812     }
3813 
3814     // Return true if either CSIM or RUIM app is present
3815     @Override
isCdmaSubscriptionAppPresent()3816     public boolean isCdmaSubscriptionAppPresent() {
3817         UiccCardApplication cdmaApplication =
3818                 mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
3819         return cdmaApplication != null && (cdmaApplication.getType() == AppType.APPTYPE_CSIM ||
3820                 cdmaApplication.getType() == AppType.APPTYPE_RUIM);
3821     }
3822 
phoneObjectUpdater(int newVoiceRadioTech)3823     protected void phoneObjectUpdater(int newVoiceRadioTech) {
3824         logd("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech);
3825 
3826         // Check for a voice over LTE/NR replacement
3827         if (ServiceState.isPsOnlyTech(newVoiceRadioTech)
3828                 || (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) {
3829             CarrierConfigManager configMgr = (CarrierConfigManager)
3830                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
3831             PersistableBundle b = configMgr.getConfigForSubId(getSubId());
3832             if (b != null) {
3833                 int volteReplacementRat =
3834                         b.getInt(CarrierConfigManager.KEY_VOLTE_REPLACEMENT_RAT_INT);
3835                 logd("phoneObjectUpdater: volteReplacementRat=" + volteReplacementRat);
3836                 if (volteReplacementRat != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN &&
3837                            //In cdma case, replace rat only if csim or ruim app present
3838                            (ServiceState.isGsm(volteReplacementRat) ||
3839                            isCdmaSubscriptionAppPresent())) {
3840                     newVoiceRadioTech = volteReplacementRat;
3841                 }
3842             } else {
3843                 loge("phoneObjectUpdater: didn't get volteReplacementRat from carrier config");
3844             }
3845         }
3846 
3847         if(mRilVersion == 6 && getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
3848             /*
3849              * On v6 RIL, when LTE_ON_CDMA is TRUE, always create CDMALTEPhone
3850              * irrespective of the voice radio tech reported.
3851              */
3852             if (getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
3853                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Use CDMA Phone" +
3854                         " newVoiceRadioTech=" + newVoiceRadioTech +
3855                         " mActivePhone=" + getPhoneName());
3856                 return;
3857             } else {
3858                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Switch to CDMALTEPhone" +
3859                         " newVoiceRadioTech=" + newVoiceRadioTech +
3860                         " mActivePhone=" + getPhoneName());
3861                 newVoiceRadioTech = ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT;
3862             }
3863         } else {
3864 
3865             // If the device is shutting down, then there is no need to switch to the new phone
3866             // which might send unnecessary attach request to the modem.
3867             if (isShuttingDown()) {
3868                 logd("Device is shutting down. No need to switch phone now.");
3869                 return;
3870             }
3871 
3872             boolean matchCdma = ServiceState.isCdma(newVoiceRadioTech);
3873             boolean matchGsm = ServiceState.isGsm(newVoiceRadioTech);
3874             if ((matchCdma && getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) ||
3875                     (matchGsm && getPhoneType() == PhoneConstants.PHONE_TYPE_GSM)) {
3876                 // Nothing changed. Keep phone as it is.
3877                 logd("phoneObjectUpdater: No change ignore," +
3878                         " newVoiceRadioTech=" + newVoiceRadioTech +
3879                         " mActivePhone=" + getPhoneName());
3880                 return;
3881             }
3882             if (!matchCdma && !matchGsm) {
3883                 loge("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech +
3884                         " doesn't match either CDMA or GSM - error! No phone change");
3885                 return;
3886             }
3887         }
3888 
3889         if (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
3890             // We need some voice phone object to be active always, so never
3891             // delete the phone without anything to replace it with!
3892             logd("phoneObjectUpdater: Unknown rat ignore, "
3893                     + " newVoiceRadioTech=Unknown. mActivePhone=" + getPhoneName());
3894             return;
3895         }
3896 
3897         boolean oldPowerState = false; // old power state to off
3898         if (mResetModemOnRadioTechnologyChange) {
3899             if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) {
3900                 oldPowerState = true;
3901                 logd("phoneObjectUpdater: Setting Radio Power to Off");
3902                 mCi.setRadioPower(false, null);
3903             }
3904         }
3905 
3906         switchVoiceRadioTech(newVoiceRadioTech);
3907 
3908         if (mResetModemOnRadioTechnologyChange && oldPowerState) { // restore power state
3909             logd("phoneObjectUpdater: Resetting Radio");
3910             mCi.setRadioPower(oldPowerState, null);
3911         }
3912 
3913         // update voice radio tech in UiccProfile
3914         UiccProfile uiccProfile = getUiccProfile();
3915         if (uiccProfile != null) {
3916             uiccProfile.setVoiceRadioTech(newVoiceRadioTech);
3917         }
3918 
3919         // Send an Intent to the PhoneApp that we had a radio technology change
3920         Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
3921         intent.putExtra(PhoneConstants.PHONE_NAME_KEY, getPhoneName());
3922         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
3923         ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
3924     }
3925 
switchVoiceRadioTech(int newVoiceRadioTech)3926     private void switchVoiceRadioTech(int newVoiceRadioTech) {
3927 
3928         String outgoingPhoneName = getPhoneName();
3929 
3930         logd("Switching Voice Phone : " + outgoingPhoneName + " >>> "
3931                 + (ServiceState.isGsm(newVoiceRadioTech) ? "GSM" : "CDMA"));
3932 
3933         if (ServiceState.isCdma(newVoiceRadioTech)) {
3934             UiccCardApplication cdmaApplication =
3935                     mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
3936             if (cdmaApplication != null && cdmaApplication.getType() == AppType.APPTYPE_RUIM) {
3937                 switchPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
3938             } else {
3939                 switchPhoneType(PhoneConstants.PHONE_TYPE_CDMA_LTE);
3940             }
3941         } else if (ServiceState.isGsm(newVoiceRadioTech)) {
3942             switchPhoneType(PhoneConstants.PHONE_TYPE_GSM);
3943         } else {
3944             loge("deleteAndCreatePhone: newVoiceRadioTech=" + newVoiceRadioTech +
3945                     " is not CDMA or GSM (error) - aborting!");
3946             return;
3947         }
3948     }
3949 
3950     @Override
setSignalStrengthReportingCriteria( int signalStrengthMeasure, int[] thresholds, int ran, boolean isEnabled)3951     public void setSignalStrengthReportingCriteria(
3952             int signalStrengthMeasure, int[] thresholds, int ran, boolean isEnabled) {
3953         mCi.setSignalStrengthReportingCriteria(new SignalThresholdInfo(signalStrengthMeasure,
3954                 REPORTING_HYSTERESIS_MILLIS, REPORTING_HYSTERESIS_DB, thresholds, isEnabled),
3955                 ran, null);
3956     }
3957 
3958     @Override
setLinkCapacityReportingCriteria(int[] dlThresholds, int[] ulThresholds, int ran)3959     public void setLinkCapacityReportingCriteria(int[] dlThresholds, int[] ulThresholds, int ran) {
3960         mCi.setLinkCapacityReportingCriteria(REPORTING_HYSTERESIS_MILLIS, REPORTING_HYSTERESIS_KBPS,
3961                 REPORTING_HYSTERESIS_KBPS, dlThresholds, ulThresholds, ran, null);
3962     }
3963 
3964     @Override
getIccSmsInterfaceManager()3965     public IccSmsInterfaceManager getIccSmsInterfaceManager(){
3966         return mIccSmsInterfaceManager;
3967     }
3968 
3969     @Override
updatePhoneObject(int voiceRadioTech)3970     public void updatePhoneObject(int voiceRadioTech) {
3971         logd("updatePhoneObject: radioTechnology=" + voiceRadioTech);
3972         sendMessage(obtainMessage(EVENT_UPDATE_PHONE_OBJECT, voiceRadioTech, 0, null));
3973     }
3974 
3975     @Override
setImsRegistrationState(boolean registered)3976     public void setImsRegistrationState(boolean registered) {
3977         mSST.setImsRegistrationState(registered);
3978     }
3979 
3980     @Override
getIccRecordsLoaded()3981     public boolean getIccRecordsLoaded() {
3982         UiccProfile uiccProfile = getUiccProfile();
3983         return uiccProfile != null && uiccProfile.getIccRecordsLoaded();
3984     }
3985 
3986     @Override
getIccCard()3987     public IccCard getIccCard() {
3988         // This function doesn't return null for backwards compatability purposes.
3989         // To differentiate between cases where SIM is absent vs. unknown we return a placeholder
3990         // IccCard with the sim state set.
3991         IccCard card = getUiccProfile();
3992         if (card != null) {
3993             return card;
3994         } else {
3995             UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId);
3996             if (slot == null || slot.isStateUnknown()) {
3997                 return new IccCard(IccCardConstants.State.UNKNOWN);
3998             } else {
3999                 return new IccCard(IccCardConstants.State.ABSENT);
4000             }
4001         }
4002     }
4003 
getUiccProfile()4004     private UiccProfile getUiccProfile() {
4005         return UiccController.getInstance().getUiccProfileForPhone(mPhoneId);
4006     }
4007 
4008     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)4009     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4010         pw.println("GsmCdmaPhone extends:");
4011         super.dump(fd, pw, args);
4012         pw.println(" mPrecisePhoneType=" + mPrecisePhoneType);
4013         pw.println(" mCT=" + mCT);
4014         pw.println(" mSST=" + mSST);
4015         pw.println(" mPendingMMIs=" + mPendingMMIs);
4016         pw.println(" mIccPhoneBookIntManager=" + mIccPhoneBookIntManager);
4017         pw.println(" mImei=" + pii(mImei));
4018         pw.println(" mImeiSv=" + pii(mImeiSv));
4019         pw.println(" mVmNumber=" + pii(mVmNumber));
4020         pw.println(" mCdmaSSM=" + mCdmaSSM);
4021         pw.println(" mCdmaSubscriptionSource=" + mCdmaSubscriptionSource);
4022         pw.println(" mWakeLock=" + mWakeLock);
4023         pw.println(" isInEcm()=" + isInEcm());
4024         pw.println(" mEsn=" + pii(mEsn));
4025         pw.println(" mMeid=" + pii(mMeid));
4026         pw.println(" mCarrierOtaSpNumSchema=" + mCarrierOtaSpNumSchema);
4027         if (!isPhoneTypeGsm()) {
4028             pw.println(" getCdmaEriIconIndex()=" + getCdmaEriIconIndex());
4029             pw.println(" getCdmaEriIconMode()=" + getCdmaEriIconMode());
4030             pw.println(" getCdmaEriText()=" + getCdmaEriText());
4031             pw.println(" isMinInfoReady()=" + isMinInfoReady());
4032         }
4033         pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled());
4034         pw.flush();
4035     }
4036 
4037     @Override
setOperatorBrandOverride(String brand)4038     public boolean setOperatorBrandOverride(String brand) {
4039         if (mUiccController == null) {
4040             return false;
4041         }
4042 
4043         UiccCard card = mUiccController.getUiccCard(getPhoneId());
4044         if (card == null) {
4045             return false;
4046         }
4047 
4048         boolean status = card.setOperatorBrandOverride(brand);
4049 
4050         // Refresh.
4051         if (status) {
4052             TelephonyManager.from(mContext).setSimOperatorNameForPhone(
4053                     getPhoneId(), mSST.getServiceProviderName());
4054             // TODO: check if pollState is need when set operator brand override.
4055             mSST.pollState();
4056         }
4057         return status;
4058     }
4059 
4060     /**
4061      * This allows a short number to be remapped to a test emergency number for testing how the
4062      * frameworks handles Emergency Callback Mode without actually calling an emergency number.
4063      *
4064      * This is not a full test and is not a substitute for testing real emergency
4065      * numbers but can be useful.
4066      *
4067      * To use this feature, first set a test emergency number using
4068      * adb shell cmd phone emergency-number-test-mode -a 1-555-555-1212
4069      *
4070      * and then set the system property ril.test.emergencynumber to a pair of
4071      * numbers separated by a colon. If the first number matches the number parameter
4072      * this routine returns the second number. Example:
4073      *
4074      * ril.test.emergencynumber=411:1-555-555-1212
4075      *
4076      * To test Dial 411 take call then hang up on MO device to enter ECM.
4077      *
4078      * @param dialString to test if it should be remapped
4079      * @return the same number or the remapped number.
4080      */
checkForTestEmergencyNumber(String dialString)4081     private String checkForTestEmergencyNumber(String dialString) {
4082         String testEn = SystemProperties.get("ril.test.emergencynumber");
4083         if (!TextUtils.isEmpty(testEn)) {
4084             String[] values = testEn.split(":");
4085             logd("checkForTestEmergencyNumber: values.length=" + values.length);
4086             if (values.length == 2) {
4087                 if (values[0].equals(PhoneNumberUtils.stripSeparators(dialString))) {
4088                     logd("checkForTestEmergencyNumber: remap " + dialString + " to " + values[1]);
4089                     dialString = values[1];
4090                 }
4091             }
4092         }
4093         return dialString;
4094     }
4095 
4096     @Override
4097     @NonNull
getOperatorNumeric()4098     public String getOperatorNumeric() {
4099         String operatorNumeric = null;
4100         if (isPhoneTypeGsm()) {
4101             IccRecords r = mIccRecords.get();
4102             if (r != null) {
4103                 operatorNumeric = r.getOperatorNumeric();
4104             }
4105         } else { //isPhoneTypeCdmaLte()
4106             IccRecords curIccRecords = null;
4107             if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_NV) {
4108                 operatorNumeric = SystemProperties.get("ro.cdma.home.operator.numeric");
4109             } else if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_RUIM_SIM) {
4110                 UiccCardApplication uiccCardApplication = mUiccApplication.get();
4111                 if (uiccCardApplication != null
4112                         && uiccCardApplication.getType() == AppType.APPTYPE_RUIM) {
4113                     logd("Legacy RUIM app present");
4114                     curIccRecords = mIccRecords.get();
4115                 } else {
4116                     // Use sim-records for SimApp, USimApp, CSimApp and ISimApp.
4117                     curIccRecords = mSimRecords;
4118                 }
4119                 if (curIccRecords != null && curIccRecords == mSimRecords) {
4120                     operatorNumeric = curIccRecords.getOperatorNumeric();
4121                 } else {
4122                     curIccRecords = mIccRecords.get();
4123                     if (curIccRecords != null && (curIccRecords instanceof RuimRecords)) {
4124                         RuimRecords csim = (RuimRecords) curIccRecords;
4125                         operatorNumeric = csim.getRUIMOperatorNumeric();
4126                     }
4127                 }
4128             }
4129             if (operatorNumeric == null) {
4130                 loge("getOperatorNumeric: Cannot retrieve operatorNumeric:"
4131                         + " mCdmaSubscriptionSource = " + mCdmaSubscriptionSource +
4132                         " mIccRecords = " + ((curIccRecords != null) ?
4133                         curIccRecords.getRecordsLoaded() : null));
4134             }
4135 
4136             logd("getOperatorNumeric: mCdmaSubscriptionSource = " + mCdmaSubscriptionSource
4137                     + " operatorNumeric = " + operatorNumeric);
4138 
4139         }
4140         return TextUtils.emptyIfNull(operatorNumeric);
4141     }
4142 
4143     /**
4144      * @return The country ISO for the subscription associated with this phone.
4145      */
getCountryIso()4146     public String getCountryIso() {
4147         int subId = getSubId();
4148         SubscriptionInfo subInfo = SubscriptionManager.from(getContext())
4149                 .getActiveSubscriptionInfo(subId);
4150         if (subInfo == null || TextUtils.isEmpty(subInfo.getCountryIso())) {
4151             return null;
4152         }
4153         return subInfo.getCountryIso().toUpperCase();
4154     }
4155 
notifyEcbmTimerReset(Boolean flag)4156     public void notifyEcbmTimerReset(Boolean flag) {
4157         mEcmTimerResetRegistrants.notifyResult(flag);
4158     }
4159 
4160     private static final int[] VOICE_PS_CALL_RADIO_TECHNOLOGY = {
4161             ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
4162             ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA,
4163             ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
4164             ServiceState.RIL_RADIO_TECHNOLOGY_NR
4165     };
4166 
4167     /**
4168      * Calculates current RIL voice radio technology for CS calls.
4169      *
4170      * This function should only be used in {@link com.android.internal.telephony.GsmCdmaConnection}
4171      * to indicate current CS call radio technology.
4172      *
4173      * @return the RIL voice radio technology used for CS calls,
4174      *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
4175      */
getCsCallRadioTech()4176     public @RilRadioTechnology int getCsCallRadioTech() {
4177         int calcVrat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
4178         if (mSST != null) {
4179             calcVrat = getCsCallRadioTech(mSST.mSS.getState(),
4180                     mSST.mSS.getRilVoiceRadioTechnology());
4181         }
4182 
4183         return calcVrat;
4184     }
4185 
4186     /**
4187      * Calculates current RIL voice radio technology for CS calls based on current voice
4188      * registration state and technology.
4189      *
4190      * Mark current RIL voice radio technology as unknow when any of below condtion is met:
4191      *  1) Current RIL voice registration state is not in-service.
4192      *  2) Current RIL voice radio technology is PS call technology, which means CSFB will
4193      *     happen later after call connection is established.
4194      *     It is inappropriate to notify upper layer the PS call technology while current call
4195      *     is CS call, so before CSFB happens, mark voice radio technology as unknow.
4196      *     After CSFB happens, {@link #onVoiceRegStateOrRatChanged} will update voice call radio
4197      *     technology with correct value.
4198      *
4199      * @param vrs the voice registration state
4200      * @param vrat the RIL voice radio technology
4201      *
4202      * @return the RIL voice radio technology used for CS calls,
4203      *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
4204      */
getCsCallRadioTech(int vrs, int vrat)4205     private @RilRadioTechnology int getCsCallRadioTech(int vrs, int vrat) {
4206         logd("getCsCallRadioTech, current vrs=" + vrs + ", vrat=" + vrat);
4207         int calcVrat = vrat;
4208         if (vrs != ServiceState.STATE_IN_SERVICE
4209                 || ArrayUtils.contains(VOICE_PS_CALL_RADIO_TECHNOLOGY, vrat)) {
4210             calcVrat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
4211         }
4212 
4213         logd("getCsCallRadioTech, result calcVrat=" + calcVrat);
4214         return calcVrat;
4215     }
4216 
4217     /**
4218      * Handler of RIL Voice Radio Technology changed event.
4219      */
onVoiceRegStateOrRatChanged(int vrs, int vrat)4220     private void onVoiceRegStateOrRatChanged(int vrs, int vrat) {
4221         logd("onVoiceRegStateOrRatChanged");
4222         mCT.dispatchCsCallRadioTech(getCsCallRadioTech(vrs, vrat));
4223     }
4224 
4225     /**
4226      * Registration point for Ecm timer reset
4227      *
4228      * @param h handler to notify
4229      * @param what User-defined message code
4230      * @param obj placed in Message.obj
4231      */
4232     @Override
registerForEcmTimerReset(Handler h, int what, Object obj)4233     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
4234         mEcmTimerResetRegistrants.addUnique(h, what, obj);
4235     }
4236 
4237     @Override
unregisterForEcmTimerReset(Handler h)4238     public void unregisterForEcmTimerReset(Handler h) {
4239         mEcmTimerResetRegistrants.remove(h);
4240     }
4241 
4242     @Override
registerForVolteSilentRedial(Handler h, int what, Object obj)4243     public void registerForVolteSilentRedial(Handler h, int what, Object obj) {
4244         mVolteSilentRedialRegistrants.addUnique(h, what, obj);
4245     }
4246 
4247     @Override
unregisterForVolteSilentRedial(Handler h)4248     public void unregisterForVolteSilentRedial(Handler h) {
4249         mVolteSilentRedialRegistrants.remove(h);
4250     }
4251 
notifyVolteSilentRedial(String dialString, int causeCode)4252     public void notifyVolteSilentRedial(String dialString, int causeCode) {
4253         logd("notifyVolteSilentRedial: dialString=" + dialString + " causeCode=" + causeCode);
4254         AsyncResult ar = new AsyncResult(null,
4255                 new SilentRedialParam(dialString, causeCode, mDialArgs), null);
4256         mVolteSilentRedialRegistrants.notifyRegistrants(ar);
4257     }
4258 
4259     /**
4260      * Sets the SIM voice message waiting indicator records.
4261      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
4262      * @param countWaiting The number of messages waiting, if known. Use
4263      *                     -1 to indicate that an unknown number of
4264      *                      messages are waiting
4265      */
4266     @Override
setVoiceMessageWaiting(int line, int countWaiting)4267     public void setVoiceMessageWaiting(int line, int countWaiting) {
4268         if (isPhoneTypeGsm()) {
4269             IccRecords r = mIccRecords.get();
4270             if (r != null) {
4271                 r.setVoiceMessageWaiting(line, countWaiting);
4272             } else {
4273                 logd("SIM Records not found, MWI not updated");
4274             }
4275         } else {
4276             setVoiceMessageCount(countWaiting);
4277         }
4278     }
4279 
makeEmptyCallForward()4280     private CallForwardInfo[] makeEmptyCallForward() {
4281         CallForwardInfo infos[] = new CallForwardInfo[1];
4282 
4283         infos[0] = new CallForwardInfo();
4284         infos[0].status = CommandsInterface.SS_STATUS_UNKNOWN;
4285         infos[0].reason = 0;
4286         infos[0].serviceClass = CommandsInterface.SERVICE_CLASS_VOICE;
4287         infos[0].toa = PhoneNumberUtils.TOA_Unknown;
4288         infos[0].number = "";
4289         infos[0].timeSeconds = 0;
4290 
4291         return infos;
4292     }
4293 
subscriptionIdToPhoneAccountHandle(final int subId)4294     private PhoneAccountHandle subscriptionIdToPhoneAccountHandle(final int subId) {
4295         final TelecomManager telecomManager = TelecomManager.from(mContext);
4296         final TelephonyManager telephonyManager = TelephonyManager.from(mContext);
4297         final Iterator<PhoneAccountHandle> phoneAccounts =
4298             telecomManager.getCallCapablePhoneAccounts(true).listIterator();
4299 
4300         while (phoneAccounts.hasNext()) {
4301             final PhoneAccountHandle phoneAccountHandle = phoneAccounts.next();
4302             final PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
4303             if (subId == telephonyManager.getSubIdForPhoneAccount(phoneAccount)) {
4304                 return phoneAccountHandle;
4305             }
4306         }
4307 
4308         return null;
4309     }
4310 
4311     @UnsupportedAppUsage
logd(String s)4312     private void logd(String s) {
4313         Rlog.d(LOG_TAG, "[" + mPhoneId + "] " + s);
4314     }
4315 
logi(String s)4316     private void logi(String s) {
4317         Rlog.i(LOG_TAG, "[" + mPhoneId + "] " + s);
4318     }
4319 
4320     @UnsupportedAppUsage
loge(String s)4321     private void loge(String s) {
4322         Rlog.e(LOG_TAG, "[" + mPhoneId + "] " + s);
4323     }
4324 
pii(String s)4325     private static String pii(String s) {
4326         return Rlog.pii(LOG_TAG, s);
4327     }
4328 
4329     @Override
isUtEnabled()4330     public boolean isUtEnabled() {
4331         Phone imsPhone = mImsPhone;
4332         if (imsPhone != null) {
4333             return imsPhone.isUtEnabled();
4334         } else {
4335             logd("isUtEnabled: called for GsmCdma");
4336             return false;
4337         }
4338     }
4339 
getDtmfToneDelayKey()4340     public String getDtmfToneDelayKey() {
4341         return isPhoneTypeGsm() ?
4342                 CarrierConfigManager.KEY_GSM_DTMF_TONE_DELAY_INT :
4343                 CarrierConfigManager.KEY_CDMA_DTMF_TONE_DELAY_INT;
4344     }
4345 
4346     @VisibleForTesting
getWakeLock()4347     public PowerManager.WakeLock getWakeLock() {
4348         return mWakeLock;
4349     }
4350 
getLteOnCdmaMode()4351     public int getLteOnCdmaMode() {
4352         int currentConfig = TelephonyProperties.lte_on_cdma_device()
4353                 .orElse(PhoneConstants.LTE_ON_CDMA_FALSE);
4354         int lteOnCdmaModeDynamicValue = currentConfig;
4355 
4356         UiccCardApplication cdmaApplication =
4357                     mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
4358         if (cdmaApplication != null && cdmaApplication.getType() == AppType.APPTYPE_RUIM) {
4359             //Legacy RUIM cards don't support LTE.
4360             lteOnCdmaModeDynamicValue = RILConstants.LTE_ON_CDMA_FALSE;
4361 
4362             //Override only if static configuration is TRUE.
4363             if (currentConfig == RILConstants.LTE_ON_CDMA_TRUE) {
4364                 return lteOnCdmaModeDynamicValue;
4365             }
4366         }
4367         return currentConfig;
4368     }
4369 
updateTtyMode(int ttyMode)4370     private void updateTtyMode(int ttyMode) {
4371         logi(String.format("updateTtyMode ttyMode=%d", ttyMode));
4372         setTTYMode(telecomModeToPhoneMode(ttyMode), null);
4373     }
updateUiTtyMode(int ttyMode)4374     private void updateUiTtyMode(int ttyMode) {
4375         logi(String.format("updateUiTtyMode ttyMode=%d", ttyMode));
4376         setUiTTYMode(telecomModeToPhoneMode(ttyMode), null);
4377     }
4378 
4379     /**
4380      * Given a telecom TTY mode, convert to a Telephony mode equivalent.
4381      * @param telecomMode Telecom TTY mode.
4382      * @return Telephony phone TTY mode.
4383      */
telecomModeToPhoneMode(int telecomMode)4384     private static int telecomModeToPhoneMode(int telecomMode) {
4385         switch (telecomMode) {
4386             // AT command only has 0 and 1, so mapping VCO
4387             // and HCO to FULL
4388             case TelecomManager.TTY_MODE_FULL:
4389             case TelecomManager.TTY_MODE_VCO:
4390             case TelecomManager.TTY_MODE_HCO:
4391                 return Phone.TTY_MODE_FULL;
4392             default:
4393                 return Phone.TTY_MODE_OFF;
4394         }
4395     }
4396 
4397     /**
4398      * Load the current TTY mode in GsmCdmaPhone based on Telecom and UI settings.
4399      */
loadTtyMode()4400     private void loadTtyMode() {
4401         int ttyMode = TelecomManager.TTY_MODE_OFF;
4402         TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
4403         if (telecomManager != null) {
4404             ttyMode = telecomManager.getCurrentTtyMode();
4405         }
4406         updateTtyMode(ttyMode);
4407         //Get preferred TTY mode from settings as UI Tty mode is always user preferred Tty mode.
4408         ttyMode = Settings.Secure.getInt(mContext.getContentResolver(),
4409                 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF);
4410         updateUiTtyMode(ttyMode);
4411     }
4412 
reapplyUiccAppsEnablementIfNeeded(int retries)4413     private void reapplyUiccAppsEnablementIfNeeded(int retries) {
4414         UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId);
4415 
4416         // If no card is present or we don't have mUiccApplicationsEnabled yet, do nothing.
4417         if (slot == null || slot.getCardState() != IccCardStatus.CardState.CARDSTATE_PRESENT
4418                 || mUiccApplicationsEnabled == null) {
4419             return;
4420         }
4421 
4422         String iccId = slot.getIccId();
4423         if (iccId == null) return;
4424 
4425         SubscriptionInfo info = SubscriptionController.getInstance().getSubInfoForIccId(
4426                 IccUtils.stripTrailingFs(iccId));
4427 
4428         // If info is null, it could be a new subscription. By default we enable it.
4429         boolean expectedValue = info == null ? true : info.areUiccApplicationsEnabled();
4430 
4431         // If for any reason current state is different from configured state, re-apply the
4432         // configured state.
4433         if (expectedValue != mUiccApplicationsEnabled) {
4434             mCi.enableUiccApplications(expectedValue, Message.obtain(
4435                     this, EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE,
4436                     new Pair<Boolean, Integer>(expectedValue, retries)));
4437         }
4438     }
4439 
4440     // Enable or disable uicc applications.
4441     @Override
enableUiccApplications(boolean enable, Message onCompleteMessage)4442     public void enableUiccApplications(boolean enable, Message onCompleteMessage) {
4443         // First check if card is present. Otherwise mUiccApplicationsDisabled doesn't make
4444         // any sense.
4445         UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId);
4446         if (slot == null || slot.getCardState() != IccCardStatus.CardState.CARDSTATE_PRESENT) {
4447             if (onCompleteMessage != null) {
4448                 AsyncResult.forMessage(onCompleteMessage, null,
4449                         new IllegalStateException("No SIM card is present"));
4450                 onCompleteMessage.sendToTarget();
4451             }
4452             return;
4453         }
4454 
4455         mCi.enableUiccApplications(enable, onCompleteMessage);
4456     }
4457 
4458     /**
4459      * Whether disabling a physical subscription is supported or not.
4460      */
4461     @Override
canDisablePhysicalSubscription()4462     public boolean canDisablePhysicalSubscription() {
4463         return mCi.canToggleUiccApplicationsEnablement();
4464     }
4465 }
4466