Merge "Support for detection of international call while on WFC only."
[android/platform/frameworks/opt/telephony.git] / src / java / com / android / internal / telephony / GsmCdmaPhone.java
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 android.app.ActivityManagerNative;
20 import android.content.BroadcastReceiver;
21 import android.content.ContentValues;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.SharedPreferences;
26 import android.database.SQLException;
27 import android.net.Uri;
28 import android.os.AsyncResult;
29 import android.os.Bundle;
30 import android.os.Handler;
31 import android.os.Message;
32 import android.os.PersistableBundle;
33 import android.os.PowerManager;
34 import android.os.Registrant;
35 import android.os.RegistrantList;
36 import android.os.SystemProperties;
37 import android.os.UserHandle;
38 import android.os.WorkSource;
39 import android.preference.PreferenceManager;
40 import android.provider.Settings;
41 import android.provider.Telephony;
42 import android.telecom.VideoProfile;
43 import android.telephony.CarrierConfigManager;
44 import android.telephony.CellLocation;
45 import android.telephony.PhoneNumberUtils;
46 import android.telephony.ServiceState;
47 import android.telephony.SubscriptionInfo;
48 import android.telephony.SubscriptionManager;
49 import android.telephony.TelephonyManager;
50
51 import android.telephony.cdma.CdmaCellLocation;
52 import android.text.TextUtils;
53 import android.telephony.Rlog;
54 import android.util.Log;
55
56 import com.android.ims.ImsManager;
57 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
58 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
59 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
60 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
61 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
62 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
63 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
64 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
65 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
66 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
67 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
68
69 import com.android.internal.annotations.VisibleForTesting;
70 import com.android.internal.telephony.cdma.CdmaMmiCode;
71 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
72 import com.android.internal.telephony.cdma.EriManager;
73 import com.android.internal.telephony.gsm.GsmMmiCode;
74 import com.android.internal.telephony.gsm.SuppServiceNotification;
75 import com.android.internal.telephony.test.SimulatedRadioControl;
76 import com.android.internal.telephony.uicc.IccCardProxy;
77 import com.android.internal.telephony.uicc.IccException;
78 import com.android.internal.telephony.uicc.IccRecords;
79 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
80 import com.android.internal.telephony.uicc.RuimRecords;
81 import com.android.internal.telephony.uicc.SIMRecords;
82 import com.android.internal.telephony.uicc.UiccCard;
83 import com.android.internal.telephony.uicc.UiccCardApplication;
84 import com.android.internal.telephony.uicc.UiccController;
85 import com.android.internal.telephony.uicc.IsimRecords;
86 import com.android.internal.telephony.uicc.IsimUiccRecords;
87
88 import java.io.FileDescriptor;
89 import java.io.PrintWriter;
90 import java.util.ArrayList;
91 import java.util.List;
92 import java.util.regex.Matcher;
93 import java.util.regex.Pattern;
94
95
96 /**
97  * {@hide}
98  */
99 public class GsmCdmaPhone extends Phone {
100     // NOTE that LOG_TAG here is "GsmCdma", which means that log messages
101     // from this file will go into the radio log rather than the main
102     // log.  (Use "adb logcat -b radio" to see them.)
103     public static final String LOG_TAG = "GsmCdmaPhone";
104     private static final boolean DBG = true;
105     private static final boolean VDBG = false; /* STOPSHIP if true */
106
107     //GSM
108     // Key used to read/write voice mail number
109     private static final String VM_NUMBER = "vm_number_key";
110     // Key used to read/write the SIM IMSI used for storing the voice mail
111     private static final String VM_SIM_IMSI = "vm_sim_imsi_key";
112     /** List of Registrants to receive Supplementary Service Notifications. */
113     private RegistrantList mSsnRegistrants = new RegistrantList();
114
115     //CDMA
116     // Default Emergency Callback Mode exit timer
117     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
118     private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
119     public static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
120     public static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
121     private CdmaSubscriptionSourceManager mCdmaSSM;
122     public int mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
123     public EriManager mEriManager;
124     private PowerManager.WakeLock mWakeLock;
125     // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
126     private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
127     // mEcmExitRespRegistrant is informed after the phone has been exited
128     private Registrant mEcmExitRespRegistrant;
129     private String mEsn;
130     private String mMeid;
131     // string to define how the carrier specifies its own ota sp number
132     private String mCarrierOtaSpNumSchema;
133     // A runnable which is used to automatically exit from Ecm after a period of time.
134     private Runnable mExitEcmRunnable = new Runnable() {
135         @Override
136         public void run() {
137             exitEmergencyCallbackMode();
138         }
139     };
140     public static final String PROPERTY_CDMA_HOME_OPERATOR_NUMERIC =
141             "ro.cdma.home.operator.numeric";
142
143     //CDMALTE
144     /** PHONE_TYPE_CDMA_LTE in addition to RuimRecords needs access to SIMRecords and
145      * IsimUiccRecords
146      */
147     private SIMRecords mSimRecords;
148
149     //Common
150     // Instance Variables
151     private IsimUiccRecords mIsimUiccRecords;
152     public GsmCdmaCallTracker mCT;
153     public ServiceStateTracker mSST;
154     private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
155     private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
156
157     private int mPrecisePhoneType;
158
159     // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
160     private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
161
162     private String mImei;
163     private String mImeiSv;
164     private String mVmNumber;
165
166     // Create Cfu (Call forward unconditional) so that dialing number &
167     // mOnComplete (Message object passed by client) can be packed &
168     // given as a single Cfu object as user data to RIL.
169     private static class Cfu {
170         final String mSetCfNumber;
171         final Message mOnComplete;
172
173         Cfu(String cfNumber, Message onComplete) {
174             mSetCfNumber = cfNumber;
175             mOnComplete = onComplete;
176         }
177     }
178
179     private IccSmsInterfaceManager mIccSmsInterfaceManager;
180     private IccCardProxy mIccCardProxy;
181
182     private boolean mResetModemOnRadioTechnologyChange = false;
183
184     private int mRilVersion;
185     private boolean mBroadcastEmergencyCallStateChanges = false;
186
187     // Constructors
188
189     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId,
190                         int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) {
191         this(context, ci, notifier, false, phoneId, precisePhoneType, telephonyComponentFactory);
192     }
193
194     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
195                         boolean unitTestMode, int phoneId, int precisePhoneType,
196                         TelephonyComponentFactory telephonyComponentFactory) {
197         super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA",
198                 notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory);
199
200         // phone type needs to be set before other initialization as other objects rely on it
201         mPrecisePhoneType = precisePhoneType;
202         initOnce(ci);
203         initRatSpecific(precisePhoneType);
204         mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
205         // DcTracker uses SST so needs to be created after it is instantiated
206         mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
207         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
208         logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
209     }
210
211     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
212         @Override
213         public void onReceive(Context context, Intent intent) {
214             Rlog.d(LOG_TAG, "mBroadcastReceiver: action " + intent.getAction());
215             if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
216                 sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED));
217             }
218         }
219     };
220
221     private void initOnce(CommandsInterface ci) {
222         if (ci instanceof SimulatedRadioControl) {
223             mSimulatedRadioControl = (SimulatedRadioControl) ci;
224         }
225
226         mCT = mTelephonyComponentFactory.makeGsmCdmaCallTracker(this);
227         mIccPhoneBookIntManager = mTelephonyComponentFactory.makeIccPhoneBookInterfaceManager(this);
228         PowerManager pm
229                 = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
230         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
231         mIccSmsInterfaceManager = mTelephonyComponentFactory.makeIccSmsInterfaceManager(this);
232         mIccCardProxy = mTelephonyComponentFactory.makeIccCardProxy(mContext, mCi, mPhoneId);
233
234         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
235         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
236         mCi.registerForOn(this, EVENT_RADIO_ON, null);
237         mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
238
239         //GSM
240         mCi.setOnUSSD(this, EVENT_USSD, null);
241         mCi.setOnSs(this, EVENT_SS, null);
242
243         //CDMA
244         mCdmaSSM = mTelephonyComponentFactory.getCdmaSubscriptionSourceManagerInstance(mContext,
245                 mCi, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
246         mEriManager = mTelephonyComponentFactory.makeEriManager(this, mContext,
247                 EriManager.ERI_FROM_XML);
248         mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
249         mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE,
250                 null);
251         // get the string that specifies the carrier OTA Sp number
252         mCarrierOtaSpNumSchema = TelephonyManager.from(mContext).getOtaSpNumberSchemaForPhone(
253                 getPhoneId(), "");
254
255         mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(
256                 TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);
257
258         mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
259         mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
260         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
261                 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
262     }
263
264     private void initRatSpecific(int precisePhoneType) {
265         mPendingMMIs.clear();
266         mIccPhoneBookIntManager.updateIccRecords(null);
267         mEsn = null;
268         mMeid = null;
269
270         mPrecisePhoneType = precisePhoneType;
271
272         TelephonyManager tm = TelephonyManager.from(mContext);
273         if (isPhoneTypeGsm()) {
274             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
275             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_GSM);
276             mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
277         } else {
278             mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
279             // This is needed to handle phone process crashes
280             mIsPhoneInEcmState = getInEcmMode();
281             if (mIsPhoneInEcmState) {
282                 // Send a message which will invoke handleExitEmergencyCallbackMode
283                 mCi.exitEmergencyCallbackMode(
284                         obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
285             }
286
287             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
288             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_CDMA);
289             mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
290             // Sets operator properties by retrieving from build-time system property
291             String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
292             String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
293             logd("init: operatorAlpha='" + operatorAlpha
294                     + "' operatorNumeric='" + operatorNumeric + "'");
295             if (mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP) ==
296                     null || isPhoneTypeCdmaLte()) {
297                 if (!TextUtils.isEmpty(operatorAlpha)) {
298                     logd("init: set 'gsm.sim.operator.alpha' to operator='" + operatorAlpha + "'");
299                     tm.setSimOperatorNameForPhone(mPhoneId, operatorAlpha);
300                 }
301                 if (!TextUtils.isEmpty(operatorNumeric)) {
302                     logd("init: set 'gsm.sim.operator.numeric' to operator='" + operatorNumeric +
303                             "'");
304                     logd("update icc_operator_numeric=" + operatorNumeric);
305                     tm.setSimOperatorNumericForPhone(mPhoneId, operatorNumeric);
306
307                     SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId());
308                     // Sets iso country property by retrieving from build-time system property
309                     setIsoCountryProperty(operatorNumeric);
310                     // Updates MCC MNC device configuration information
311                     logd("update mccmnc=" + operatorNumeric);
312                     MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
313                 }
314             }
315
316             // Sets current entry in the telephony carrier table
317             updateCurrentCarrierInProvider(operatorNumeric);
318         }
319     }
320
321     //CDMA
322     /**
323      * Sets PROPERTY_ICC_OPERATOR_ISO_COUNTRY property
324      *
325      */
326     private void setIsoCountryProperty(String operatorNumeric) {
327         TelephonyManager tm = TelephonyManager.from(mContext);
328         if (TextUtils.isEmpty(operatorNumeric)) {
329             logd("setIsoCountryProperty: clear 'gsm.sim.operator.iso-country'");
330             tm.setSimCountryIsoForPhone(mPhoneId, "");
331         } else {
332             String iso = "";
333             try {
334                 iso = MccTable.countryCodeForMcc(Integer.parseInt(
335                         operatorNumeric.substring(0,3)));
336             } catch (NumberFormatException ex) {
337                 Rlog.e(LOG_TAG, "setIsoCountryProperty: countryCodeForMcc error", ex);
338             } catch (StringIndexOutOfBoundsException ex) {
339                 Rlog.e(LOG_TAG, "setIsoCountryProperty: countryCodeForMcc error", ex);
340             }
341
342             logd("setIsoCountryProperty: set 'gsm.sim.operator.iso-country' to iso=" + iso);
343             tm.setSimCountryIsoForPhone(mPhoneId, iso);
344         }
345     }
346
347     public boolean isPhoneTypeGsm() {
348         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM;
349     }
350
351     public boolean isPhoneTypeCdma() {
352         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA;
353     }
354
355     public boolean isPhoneTypeCdmaLte() {
356         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA_LTE;
357     }
358
359     private void switchPhoneType(int precisePhoneType) {
360         removeCallbacks(mExitEcmRunnable);
361
362         initRatSpecific(precisePhoneType);
363
364         mSST.updatePhoneType();
365         setPhoneName(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA");
366         onUpdateIccAvailability();
367         mCT.updatePhoneType();
368
369         CommandsInterface.RadioState radioState = mCi.getRadioState();
370         if (radioState.isAvailable()) {
371             handleRadioAvailable();
372             if (radioState.isOn()) {
373                 handleRadioOn();
374             }
375         }
376         if (!radioState.isAvailable() || !radioState.isOn()) {
377             handleRadioOffOrNotAvailable();
378         }
379     }
380
381     @Override
382     protected void finalize() {
383         if(DBG) logd("GsmCdmaPhone finalized");
384         if (mWakeLock != null && mWakeLock.isHeld()) {
385             Rlog.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
386             mWakeLock.release();
387         }
388     }
389
390     @Override
391     public ServiceState getServiceState() {
392         if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) {
393             if (mImsPhone != null) {
394                 return ServiceState.mergeServiceStates(
395                         (mSST == null) ? new ServiceState() : mSST.mSS,
396                         mImsPhone.getServiceState());
397             }
398         }
399
400         if (mSST != null) {
401             return mSST.mSS;
402         } else {
403             // avoid potential NPE in EmergencyCallHelper during Phone switch
404             return new ServiceState();
405         }
406     }
407
408     @Override
409     public CellLocation getCellLocation(WorkSource workSource) {
410         if (isPhoneTypeGsm()) {
411             return mSST.getCellLocation(workSource);
412         } else {
413             CdmaCellLocation loc = (CdmaCellLocation)mSST.mCellLoc;
414
415             int mode = Settings.Secure.getInt(getContext().getContentResolver(),
416                     Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
417             if (mode == Settings.Secure.LOCATION_MODE_OFF) {
418                 // clear lat/long values for location privacy
419                 CdmaCellLocation privateLoc = new CdmaCellLocation();
420                 privateLoc.setCellLocationData(loc.getBaseStationId(),
421                         CdmaCellLocation.INVALID_LAT_LONG,
422                         CdmaCellLocation.INVALID_LAT_LONG,
423                         loc.getSystemId(), loc.getNetworkId());
424                 loc = privateLoc;
425             }
426             return loc;
427         }
428     }
429
430     @Override
431     public PhoneConstants.State getState() {
432         if (mImsPhone != null) {
433             PhoneConstants.State imsState = mImsPhone.getState();
434             if (imsState != PhoneConstants.State.IDLE) {
435                 return imsState;
436             }
437         }
438
439         return mCT.mState;
440     }
441
442     @Override
443     public int getPhoneType() {
444         if (mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM) {
445             return PhoneConstants.PHONE_TYPE_GSM;
446         } else {
447             return PhoneConstants.PHONE_TYPE_CDMA;
448         }
449     }
450
451     @Override
452     public ServiceStateTracker getServiceStateTracker() {
453         return mSST;
454     }
455
456     @Override
457     public CallTracker getCallTracker() {
458         return mCT;
459     }
460
461     @Override
462     public void updateVoiceMail() {
463         if (isPhoneTypeGsm()) {
464             int countVoiceMessages = 0;
465             IccRecords r = mIccRecords.get();
466             if (r != null) {
467                 // get voice mail count from SIM
468                 countVoiceMessages = r.getVoiceMessageCount();
469             }
470             int countVoiceMessagesStored = getStoredVoiceMessageCount();
471             if (countVoiceMessages == -1 && countVoiceMessagesStored != 0) {
472                 countVoiceMessages = countVoiceMessagesStored;
473             }
474             logd("updateVoiceMail countVoiceMessages = " + countVoiceMessages
475                     + " subId " + getSubId());
476             setVoiceMessageCount(countVoiceMessages);
477         } else {
478             setVoiceMessageCount(getStoredVoiceMessageCount());
479         }
480     }
481
482     @Override
483     public List<? extends MmiCode>
484     getPendingMmiCodes() {
485         return mPendingMMIs;
486     }
487
488     @Override
489     public PhoneConstants.DataState getDataConnectionState(String apnType) {
490         PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED;
491
492         if (mSST == null) {
493             // Radio Technology Change is ongoning, dispose() and removeReferences() have
494             // already been called
495
496             ret = PhoneConstants.DataState.DISCONNECTED;
497         } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE
498                 && (isPhoneTypeCdma() ||
499                 (isPhoneTypeGsm() && !apnType.equals(PhoneConstants.APN_TYPE_EMERGENCY)))) {
500             // If we're out of service, open TCP sockets may still work
501             // but no data will flow
502
503             // Emergency APN is available even in Out Of Service
504             // Pass the actual State of EPDN
505
506             ret = PhoneConstants.DataState.DISCONNECTED;
507         } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */
508             switch (mDcTracker.getState(apnType)) {
509                 case RETRYING:
510                 case FAILED:
511                 case IDLE:
512                     ret = PhoneConstants.DataState.DISCONNECTED;
513                 break;
514
515                 case CONNECTED:
516                 case DISCONNECTING:
517                     if ( mCT.mState != PhoneConstants.State.IDLE
518                             && !mSST.isConcurrentVoiceAndDataAllowed()) {
519                         ret = PhoneConstants.DataState.SUSPENDED;
520                     } else {
521                         ret = PhoneConstants.DataState.CONNECTED;
522                     }
523                 break;
524
525                 case CONNECTING:
526                 case SCANNING:
527                     ret = PhoneConstants.DataState.CONNECTING;
528                 break;
529             }
530         }
531
532         logd("getDataConnectionState apnType=" + apnType + " ret=" + ret);
533         return ret;
534     }
535
536     @Override
537     public DataActivityState getDataActivityState() {
538         DataActivityState ret = DataActivityState.NONE;
539
540         if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
541             switch (mDcTracker.getActivity()) {
542                 case DATAIN:
543                     ret = DataActivityState.DATAIN;
544                 break;
545
546                 case DATAOUT:
547                     ret = DataActivityState.DATAOUT;
548                 break;
549
550                 case DATAINANDOUT:
551                     ret = DataActivityState.DATAINANDOUT;
552                 break;
553
554                 case DORMANT:
555                     ret = DataActivityState.DORMANT;
556                 break;
557
558                 default:
559                     ret = DataActivityState.NONE;
560                 break;
561             }
562         }
563
564         return ret;
565     }
566
567     /**
568      * Notify any interested party of a Phone state change
569      * {@link com.android.internal.telephony.PhoneConstants.State}
570      */
571     public void notifyPhoneStateChanged() {
572         mNotifier.notifyPhoneState(this);
573     }
574
575     /**
576      * Notify registrants of a change in the call state. This notifies changes in
577      * {@link com.android.internal.telephony.Call.State}. Use this when changes
578      * in the precise call state are needed, else use notifyPhoneStateChanged.
579      */
580     public void notifyPreciseCallStateChanged() {
581         /* we'd love it if this was package-scoped*/
582         super.notifyPreciseCallStateChangedP();
583     }
584
585     public void notifyNewRingingConnection(Connection c) {
586         super.notifyNewRingingConnectionP(c);
587     }
588
589     public void notifyDisconnect(Connection cn) {
590         mDisconnectRegistrants.notifyResult(cn);
591
592         mNotifier.notifyDisconnectCause(cn.getDisconnectCause(), cn.getPreciseDisconnectCause());
593     }
594
595     public void notifyUnknownConnection(Connection cn) {
596         super.notifyUnknownConnectionP(cn);
597     }
598
599     @Override
600     public boolean isInEmergencyCall() {
601         if (isPhoneTypeGsm()) {
602             return false;
603         } else {
604             return mCT.isInEmergencyCall();
605         }
606     }
607
608     @Override
609     protected void setIsInEmergencyCall() {
610         if (!isPhoneTypeGsm()) {
611             mCT.setIsInEmergencyCall();
612         }
613     }
614
615     @Override
616     public boolean isInEcm() {
617         if (isPhoneTypeGsm()) {
618             return false;
619         } else {
620             return mIsPhoneInEcmState;
621         }
622     }
623
624     //CDMA
625     private void sendEmergencyCallbackModeChange(){
626         //Send an Intent
627         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
628         intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
629         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
630         ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
631         if (DBG) logd("sendEmergencyCallbackModeChange");
632     }
633
634     @Override
635     public void sendEmergencyCallStateChange(boolean callActive) {
636         if (mBroadcastEmergencyCallStateChanges) {
637             Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
638             intent.putExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, callActive);
639             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
640             ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
641             if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: callActive " + callActive);
642         }
643     }
644
645     @Override
646     public void setBroadcastEmergencyCallStateChanges(boolean broadcast) {
647         mBroadcastEmergencyCallStateChanges = broadcast;
648     }
649
650     public void notifySuppServiceFailed(SuppService code) {
651         mSuppServiceFailedRegistrants.notifyResult(code);
652     }
653
654     public void notifyServiceStateChanged(ServiceState ss) {
655         super.notifyServiceStateChangedP(ss);
656     }
657
658     public void notifyLocationChanged() {
659         mNotifier.notifyCellLocation(this);
660     }
661
662     @Override
663     public void notifyCallForwardingIndicator() {
664         mNotifier.notifyCallForwardingChanged(this);
665     }
666
667     // override for allowing access from other classes of this package
668     /**
669      * {@inheritDoc}
670      */
671     @Override
672     public void setSystemProperty(String property, String value) {
673         if (getUnitTestMode()) {
674             return;
675         }
676         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
677             TelephonyManager.setTelephonyProperty(mPhoneId, property, value);
678         } else {
679             super.setSystemProperty(property, value);
680         }
681     }
682
683     @Override
684     public void registerForSuppServiceNotification(
685             Handler h, int what, Object obj) {
686         mSsnRegistrants.addUnique(h, what, obj);
687         if (mSsnRegistrants.size() == 1) mCi.setSuppServiceNotifications(true, null);
688     }
689
690     @Override
691     public void unregisterForSuppServiceNotification(Handler h) {
692         mSsnRegistrants.remove(h);
693         if (mSsnRegistrants.size() == 0) mCi.setSuppServiceNotifications(false, null);
694     }
695
696     @Override
697     public void registerForSimRecordsLoaded(Handler h, int what, Object obj) {
698         mSimRecordsLoadedRegistrants.addUnique(h, what, obj);
699     }
700
701     @Override
702     public void unregisterForSimRecordsLoaded(Handler h) {
703         mSimRecordsLoadedRegistrants.remove(h);
704     }
705
706     @Override
707     public void acceptCall(int videoState) throws CallStateException {
708         Phone imsPhone = mImsPhone;
709         if ( imsPhone != null && imsPhone.getRingingCall().isRinging() ) {
710             imsPhone.acceptCall(videoState);
711         } else {
712             mCT.acceptCall();
713         }
714     }
715
716     @Override
717     public void rejectCall() throws CallStateException {
718         mCT.rejectCall();
719     }
720
721     @Override
722     public void switchHoldingAndActive() throws CallStateException {
723         mCT.switchWaitingOrHoldingAndActive();
724     }
725
726     @Override
727     public String getIccSerialNumber() {
728         IccRecords r = mIccRecords.get();
729         if (!isPhoneTypeGsm() && r == null) {
730             // to get ICCID form SIMRecords because it is on MF.
731             r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP);
732         }
733         return (r != null) ? r.getIccId() : null;
734     }
735
736     @Override
737     public String getFullIccSerialNumber() {
738         IccRecords r = mIccRecords.get();
739         if (!isPhoneTypeGsm() && r == null) {
740             // to get ICCID form SIMRecords because it is on MF.
741             r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP);
742         }
743         return (r != null) ? r.getFullIccId() : null;
744     }
745
746     @Override
747     public boolean canConference() {
748         if (mImsPhone != null && mImsPhone.canConference()) {
749             return true;
750         }
751         if (isPhoneTypeGsm()) {
752             return mCT.canConference();
753         } else {
754             loge("canConference: not possible in CDMA");
755             return false;
756         }
757     }
758
759     @Override
760     public void conference() {
761         if (mImsPhone != null && mImsPhone.canConference()) {
762             logd("conference() - delegated to IMS phone");
763             try {
764                 mImsPhone.conference();
765             } catch (CallStateException e) {
766                 loge(e.toString());
767             }
768             return;
769         }
770         if (isPhoneTypeGsm()) {
771             mCT.conference();
772         } else {
773             // three way calls in CDMA will be handled by feature codes
774             loge("conference: not possible in CDMA");
775         }
776     }
777
778     @Override
779     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
780         if (isPhoneTypeGsm()) {
781             loge("enableEnhancedVoicePrivacy: not expected on GSM");
782         } else {
783             mCi.setPreferredVoicePrivacy(enable, onComplete);
784         }
785     }
786
787     @Override
788     public void getEnhancedVoicePrivacy(Message onComplete) {
789         if (isPhoneTypeGsm()) {
790             loge("getEnhancedVoicePrivacy: not expected on GSM");
791         } else {
792             mCi.getPreferredVoicePrivacy(onComplete);
793         }
794     }
795
796     @Override
797     public void clearDisconnected() {
798         mCT.clearDisconnected();
799     }
800
801     @Override
802     public boolean canTransfer() {
803         if (isPhoneTypeGsm()) {
804             return mCT.canTransfer();
805         } else {
806             loge("canTransfer: not possible in CDMA");
807             return false;
808         }
809     }
810
811     @Override
812     public void explicitCallTransfer() {
813         if (isPhoneTypeGsm()) {
814             mCT.explicitCallTransfer();
815         } else {
816             loge("explicitCallTransfer: not possible in CDMA");
817         }
818     }
819
820     @Override
821     public GsmCdmaCall getForegroundCall() {
822         return mCT.mForegroundCall;
823     }
824
825     @Override
826     public GsmCdmaCall getBackgroundCall() {
827         return mCT.mBackgroundCall;
828     }
829
830     @Override
831     public Call getRingingCall() {
832         Phone imsPhone = mImsPhone;
833         // It returns the ringing call of ImsPhone if the ringing call of GSMPhone isn't ringing.
834         // In CallManager.registerPhone(), it always registers ringing call of ImsPhone, because
835         // the ringing call of GSMPhone isn't ringing. Consequently, it can't answer GSM call
836         // successfully by invoking TelephonyManager.answerRingingCall() since the implementation
837         // in PhoneInterfaceManager.answerRingingCallInternal() could not get the correct ringing
838         // call from CallManager. So we check the ringing call state of imsPhone first as
839         // accpetCall() does.
840         if ( imsPhone != null && imsPhone.getRingingCall().isRinging()) {
841             return imsPhone.getRingingCall();
842         }
843         return mCT.mRingingCall;
844     }
845
846     private boolean handleCallDeflectionIncallSupplementaryService(
847             String dialString) {
848         if (dialString.length() > 1) {
849             return false;
850         }
851
852         if (getRingingCall().getState() != GsmCdmaCall.State.IDLE) {
853             if (DBG) logd("MmiCode 0: rejectCall");
854             try {
855                 mCT.rejectCall();
856             } catch (CallStateException e) {
857                 if (DBG) Rlog.d(LOG_TAG,
858                         "reject failed", e);
859                 notifySuppServiceFailed(Phone.SuppService.REJECT);
860             }
861         } else if (getBackgroundCall().getState() != GsmCdmaCall.State.IDLE) {
862             if (DBG) logd("MmiCode 0: hangupWaitingOrBackground");
863             mCT.hangupWaitingOrBackground();
864         }
865
866         return true;
867     }
868
869     //GSM
870     private boolean handleCallWaitingIncallSupplementaryService(String dialString) {
871         int len = dialString.length();
872
873         if (len > 2) {
874             return false;
875         }
876
877         GsmCdmaCall call = getForegroundCall();
878
879         try {
880             if (len > 1) {
881                 char ch = dialString.charAt(1);
882                 int callIndex = ch - '0';
883
884                 if (callIndex >= 1 && callIndex <= GsmCdmaCallTracker.MAX_CONNECTIONS_GSM) {
885                     if (DBG) logd("MmiCode 1: hangupConnectionByIndex " + callIndex);
886                     mCT.hangupConnectionByIndex(call, callIndex);
887                 }
888             } else {
889                 if (call.getState() != GsmCdmaCall.State.IDLE) {
890                     if (DBG) logd("MmiCode 1: hangup foreground");
891                     //mCT.hangupForegroundResumeBackground();
892                     mCT.hangup(call);
893                 } else {
894                     if (DBG) logd("MmiCode 1: switchWaitingOrHoldingAndActive");
895                     mCT.switchWaitingOrHoldingAndActive();
896                 }
897             }
898         } catch (CallStateException e) {
899             if (DBG) Rlog.d(LOG_TAG,
900                     "hangup failed", e);
901             notifySuppServiceFailed(Phone.SuppService.HANGUP);
902         }
903
904         return true;
905     }
906
907     private boolean handleCallHoldIncallSupplementaryService(String dialString) {
908         int len = dialString.length();
909
910         if (len > 2) {
911             return false;
912         }
913
914         GsmCdmaCall call = getForegroundCall();
915
916         if (len > 1) {
917             try {
918                 char ch = dialString.charAt(1);
919                 int callIndex = ch - '0';
920                 GsmCdmaConnection conn = mCT.getConnectionByIndex(call, callIndex);
921
922                 // GsmCdma index starts at 1, up to 5 connections in a call,
923                 if (conn != null && callIndex >= 1 && callIndex <= GsmCdmaCallTracker.MAX_CONNECTIONS_GSM) {
924                     if (DBG) logd("MmiCode 2: separate call " + callIndex);
925                     mCT.separate(conn);
926                 } else {
927                     if (DBG) logd("separate: invalid call index " + callIndex);
928                     notifySuppServiceFailed(Phone.SuppService.SEPARATE);
929                 }
930             } catch (CallStateException e) {
931                 if (DBG) Rlog.d(LOG_TAG, "separate failed", e);
932                 notifySuppServiceFailed(Phone.SuppService.SEPARATE);
933             }
934         } else {
935             try {
936                 if (getRingingCall().getState() != GsmCdmaCall.State.IDLE) {
937                     if (DBG) logd("MmiCode 2: accept ringing call");
938                     mCT.acceptCall();
939                 } else {
940                     if (DBG) logd("MmiCode 2: switchWaitingOrHoldingAndActive");
941                     mCT.switchWaitingOrHoldingAndActive();
942                 }
943             } catch (CallStateException e) {
944                 if (DBG) Rlog.d(LOG_TAG, "switch failed", e);
945                 notifySuppServiceFailed(Phone.SuppService.SWITCH);
946             }
947         }
948
949         return true;
950     }
951
952     private boolean handleMultipartyIncallSupplementaryService(String dialString) {
953         if (dialString.length() > 1) {
954             return false;
955         }
956
957         if (DBG) logd("MmiCode 3: merge calls");
958         conference();
959         return true;
960     }
961
962     private boolean handleEctIncallSupplementaryService(String dialString) {
963
964         int len = dialString.length();
965
966         if (len != 1) {
967             return false;
968         }
969
970         if (DBG) logd("MmiCode 4: explicit call transfer");
971         explicitCallTransfer();
972         return true;
973     }
974
975     private boolean handleCcbsIncallSupplementaryService(String dialString) {
976         if (dialString.length() > 1) {
977             return false;
978         }
979
980         Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!");
981         // Treat it as an "unknown" service.
982         notifySuppServiceFailed(Phone.SuppService.UNKNOWN);
983         return true;
984     }
985
986     @Override
987     public boolean handleInCallMmiCommands(String dialString) throws CallStateException {
988         if (!isPhoneTypeGsm()) {
989             loge("method handleInCallMmiCommands is NOT supported in CDMA!");
990             return false;
991         }
992
993         Phone imsPhone = mImsPhone;
994         if (imsPhone != null
995                 && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) {
996             return imsPhone.handleInCallMmiCommands(dialString);
997         }
998
999         if (!isInCall()) {
1000             return false;
1001         }
1002
1003         if (TextUtils.isEmpty(dialString)) {
1004             return false;
1005         }
1006
1007         boolean result = false;
1008         char ch = dialString.charAt(0);
1009         switch (ch) {
1010             case '0':
1011                 result = handleCallDeflectionIncallSupplementaryService(dialString);
1012                 break;
1013             case '1':
1014                 result = handleCallWaitingIncallSupplementaryService(dialString);
1015                 break;
1016             case '2':
1017                 result = handleCallHoldIncallSupplementaryService(dialString);
1018                 break;
1019             case '3':
1020                 result = handleMultipartyIncallSupplementaryService(dialString);
1021                 break;
1022             case '4':
1023                 result = handleEctIncallSupplementaryService(dialString);
1024                 break;
1025             case '5':
1026                 result = handleCcbsIncallSupplementaryService(dialString);
1027                 break;
1028             default:
1029                 break;
1030         }
1031
1032         return result;
1033     }
1034
1035     public boolean isInCall() {
1036         GsmCdmaCall.State foregroundCallState = getForegroundCall().getState();
1037         GsmCdmaCall.State backgroundCallState = getBackgroundCall().getState();
1038         GsmCdmaCall.State ringingCallState = getRingingCall().getState();
1039
1040        return (foregroundCallState.isAlive() ||
1041                 backgroundCallState.isAlive() ||
1042                 ringingCallState.isAlive());
1043     }
1044
1045     @Override
1046     public Connection dial(String dialString, int videoState) throws CallStateException {
1047         return dial(dialString, null, videoState, null);
1048     }
1049
1050     @Override
1051     public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
1052             throws CallStateException {
1053         if (!isPhoneTypeGsm() && uusInfo != null) {
1054             throw new CallStateException("Sending UUS information NOT supported in CDMA!");
1055         }
1056
1057         boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(dialString);
1058         Phone imsPhone = mImsPhone;
1059
1060         CarrierConfigManager configManager =
1061                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1062         boolean alwaysTryImsForEmergencyCarrierConfig = configManager.getConfigForSubId(getSubId())
1063                 .getBoolean(CarrierConfigManager.KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL);
1064
1065         boolean imsUseEnabled = isImsUseEnabled()
1066                  && imsPhone != null
1067                  && (imsPhone.isVolteEnabled() || imsPhone.isWifiCallingEnabled() ||
1068                  (imsPhone.isVideoEnabled() && VideoProfile.isVideo(videoState)))
1069                  && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
1070
1071         boolean useImsForEmergency = imsPhone != null
1072                 && isEmergency
1073                 && alwaysTryImsForEmergencyCarrierConfig
1074                 && ImsManager.isNonTtyOrTtyOnVolteEnabled(mContext)
1075                 && (imsPhone.getServiceState().getState() != ServiceState.STATE_POWER_OFF);
1076
1077         String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(PhoneNumberUtils.
1078                 stripSeparators(dialString));
1079         boolean isUt = (dialPart.startsWith("*") || dialPart.startsWith("#"))
1080                 && dialPart.endsWith("#");
1081
1082         boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled();
1083
1084         if (DBG) {
1085             logd("imsUseEnabled=" + imsUseEnabled
1086                     + ", useImsForEmergency=" + useImsForEmergency
1087                     + ", useImsForUt=" + useImsForUt
1088                     + ", isUt=" + isUt
1089                     + ", imsPhone=" + imsPhone
1090                     + ", imsPhone.isVolteEnabled()="
1091                     + ((imsPhone != null) ? imsPhone.isVolteEnabled() : "N/A")
1092                     + ", imsPhone.isVowifiEnabled()="
1093                     + ((imsPhone != null) ? imsPhone.isWifiCallingEnabled() : "N/A")
1094                     + ", imsPhone.isVideoEnabled()="
1095                     + ((imsPhone != null) ? imsPhone.isVideoEnabled() : "N/A")
1096                     + ", imsPhone.getServiceState().getState()="
1097                     + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A"));
1098         }
1099
1100         Phone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mContext);
1101
1102         if ((imsUseEnabled && (!isUt || useImsForUt)) || useImsForEmergency) {
1103             try {
1104                 if (DBG) logd("Trying IMS PS call");
1105                 return imsPhone.dial(dialString, uusInfo, videoState, intentExtras);
1106             } catch (CallStateException e) {
1107                 if (DBG) logd("IMS PS call exception " + e +
1108                         "imsUseEnabled =" + imsUseEnabled + ", imsPhone =" + imsPhone);
1109                 if (!Phone.CS_FALLBACK.equals(e.getMessage())) {
1110                     CallStateException ce = new CallStateException(e.getMessage());
1111                     ce.setStackTrace(e.getStackTrace());
1112                     throw ce;
1113                 }
1114             }
1115         }
1116
1117         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE
1118                 && mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) {
1119             throw new CallStateException("cannot dial in current state");
1120         }
1121         // Check non-emergency voice CS call - shouldn't dial when POWER_OFF
1122         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_POWER_OFF /* CS POWER_OFF */
1123                 && !VideoProfile.isVideo(videoState) /* voice call */
1124                 && !isEmergency /* non-emergency call */) {
1125             throw new CallStateException(
1126                 CallStateException.ERROR_POWER_OFF,
1127                 "cannot dial voice call in airplane mode");
1128         }
1129         if (DBG) logd("Trying (non-IMS) CS call");
1130
1131         if (isPhoneTypeGsm()) {
1132             return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);
1133         } else {
1134             return dialInternal(dialString, null, videoState, intentExtras);
1135         }
1136     }
1137
1138     /**
1139      * @return {@code true} if the user should be informed of an attempt to dial an international
1140      * number while on WFC only, {@code false} otherwise.
1141      */
1142     public boolean isNotificationOfWfcCallRequired(String dialString) {
1143         CarrierConfigManager configManager =
1144                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1145         PersistableBundle config = configManager.getConfigForSubId(getSubId());
1146
1147         // Determine if carrier config indicates that international calls over WFC should trigger a
1148         // notification to the user. This is controlled by carrier configuration and is off by
1149         // default.
1150         boolean shouldNotifyInternationalCallOnWfc = config != null
1151                 && config.getBoolean(
1152                         CarrierConfigManager.KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL);
1153
1154         if (!shouldNotifyInternationalCallOnWfc) {
1155             return false;
1156         }
1157
1158         Phone imsPhone = mImsPhone;
1159         boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
1160         boolean shouldConfirmCall =
1161                         // Using IMS
1162                         isImsUseEnabled()
1163                         && imsPhone != null
1164                         // VoLTE not available
1165                         && !imsPhone.isVolteEnabled()
1166                         // WFC is available
1167                         && imsPhone.isWifiCallingEnabled()
1168                         && !isEmergency
1169                         // Dialing international number
1170                         && PhoneNumberUtils.isInternationalNumber(dialString, getCountryIso());
1171         return shouldConfirmCall;
1172     }
1173
1174     @Override
1175     protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
1176                                       Bundle intentExtras)
1177             throws CallStateException {
1178
1179         // Need to make sure dialString gets parsed properly
1180         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
1181
1182         if (isPhoneTypeGsm()) {
1183             // handle in-call MMI first if applicable
1184             if (handleInCallMmiCommands(newDialString)) {
1185                 return null;
1186             }
1187
1188             // Only look at the Network portion for mmi
1189             String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
1190             GsmMmiCode mmi =
1191                     GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
1192             if (DBG) logd("dialing w/ mmi '" + mmi + "'...");
1193
1194             if (mmi == null) {
1195                 return mCT.dial(newDialString, uusInfo, intentExtras);
1196             } else if (mmi.isTemporaryModeCLIR()) {
1197                 return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
1198             } else {
1199                 mPendingMMIs.add(mmi);
1200                 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1201                 try {
1202                     mmi.processCode();
1203                 } catch (CallStateException e) {
1204                     //do nothing
1205                 }
1206
1207                 // FIXME should this return null or something else?
1208                 return null;
1209             }
1210         } else {
1211             return mCT.dial(newDialString);
1212         }
1213     }
1214
1215     @Override
1216     public boolean handlePinMmi(String dialString) {
1217         MmiCode mmi;
1218         if (isPhoneTypeGsm()) {
1219             mmi = GsmMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
1220         } else {
1221             mmi = CdmaMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
1222         }
1223
1224         if (mmi != null && mmi.isPinPukCommand()) {
1225             mPendingMMIs.add(mmi);
1226             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1227             try {
1228                 mmi.processCode();
1229             } catch (CallStateException e) {
1230                 //do nothing
1231             }
1232             return true;
1233         }
1234
1235         loge("Mmi is null or unrecognized!");
1236         return false;
1237     }
1238
1239     @Override
1240     public void sendUssdResponse(String ussdMessge) {
1241         if (isPhoneTypeGsm()) {
1242             GsmMmiCode mmi = GsmMmiCode.newFromUssdUserInput(ussdMessge, this, mUiccApplication.get());
1243             mPendingMMIs.add(mmi);
1244             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1245             mmi.sendUssd(ussdMessge);
1246         } else {
1247             loge("sendUssdResponse: not possible in CDMA");
1248         }
1249     }
1250
1251     @Override
1252     public void sendDtmf(char c) {
1253         if (!PhoneNumberUtils.is12Key(c)) {
1254             loge("sendDtmf called with invalid character '" + c + "'");
1255         } else {
1256             if (mCT.mState ==  PhoneConstants.State.OFFHOOK) {
1257                 mCi.sendDtmf(c, null);
1258             }
1259         }
1260     }
1261
1262     @Override
1263     public void startDtmf(char c) {
1264         if (!PhoneNumberUtils.is12Key(c)) {
1265             loge("startDtmf called with invalid character '" + c + "'");
1266         } else {
1267             mCi.startDtmf(c, null);
1268         }
1269     }
1270
1271     @Override
1272     public void stopDtmf() {
1273         mCi.stopDtmf(null);
1274     }
1275
1276     @Override
1277     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
1278         if (isPhoneTypeGsm()) {
1279             loge("[GsmCdmaPhone] sendBurstDtmf() is a CDMA method");
1280         } else {
1281             boolean check = true;
1282             for (int itr = 0;itr < dtmfString.length(); itr++) {
1283                 if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
1284                     Rlog.e(LOG_TAG,
1285                             "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'");
1286                     check = false;
1287                     break;
1288                 }
1289             }
1290             if (mCT.mState == PhoneConstants.State.OFFHOOK && check) {
1291                 mCi.sendBurstDtmf(dtmfString, on, off, onComplete);
1292             }
1293         }
1294     }
1295
1296     @Override
1297     public void setRadioPower(boolean power) {
1298         mSST.setRadioPower(power);
1299     }
1300
1301     private void storeVoiceMailNumber(String number) {
1302         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1303         SharedPreferences.Editor editor = sp.edit();
1304         if (isPhoneTypeGsm()) {
1305             editor.putString(VM_NUMBER + getPhoneId(), number);
1306             editor.apply();
1307             setVmSimImsi(getSubscriberId());
1308         } else {
1309             editor.putString(VM_NUMBER_CDMA + getPhoneId(), number);
1310             editor.apply();
1311         }
1312     }
1313
1314     @Override
1315     public String getVoiceMailNumber() {
1316         String number = null;
1317         if (isPhoneTypeGsm()) {
1318             // Read from the SIM. If its null, try reading from the shared preference area.
1319             IccRecords r = mIccRecords.get();
1320             number = (r != null) ? r.getVoiceMailNumber() : "";
1321             if (TextUtils.isEmpty(number)) {
1322                 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1323                 number = sp.getString(VM_NUMBER + getPhoneId(), null);
1324             }
1325         } else {
1326             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1327             number = sp.getString(VM_NUMBER_CDMA + getPhoneId(), null);
1328         }
1329
1330         if (TextUtils.isEmpty(number)) {
1331             CarrierConfigManager configManager = (CarrierConfigManager)
1332                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
1333             PersistableBundle b = configManager.getConfig();
1334             if (b != null) {
1335                 String defaultVmNumber =
1336                         b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING);
1337                 if (!TextUtils.isEmpty(defaultVmNumber)) {
1338                     number = defaultVmNumber;
1339                 }
1340             }
1341         }
1342
1343         if (!isPhoneTypeGsm() && TextUtils.isEmpty(number)) {
1344             // Read platform settings for dynamic voicemail number
1345             if (getContext().getResources().getBoolean(com.android.internal
1346                     .R.bool.config_telephony_use_own_number_for_voicemail)) {
1347                 number = getLine1Number();
1348             } else {
1349                 number = "*86";
1350             }
1351         }
1352
1353         return number;
1354     }
1355
1356     private String getVmSimImsi() {
1357         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1358         return sp.getString(VM_SIM_IMSI + getPhoneId(), null);
1359     }
1360
1361     private void setVmSimImsi(String imsi) {
1362         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1363         SharedPreferences.Editor editor = sp.edit();
1364         editor.putString(VM_SIM_IMSI + getPhoneId(), imsi);
1365         editor.apply();
1366     }
1367
1368     @Override
1369     public String getVoiceMailAlphaTag() {
1370         String ret = "";
1371
1372         if (isPhoneTypeGsm()) {
1373             IccRecords r = mIccRecords.get();
1374
1375             ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
1376         }
1377
1378         if (ret == null || ret.length() == 0) {
1379             return mContext.getText(
1380                 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
1381         }
1382
1383         return ret;
1384     }
1385
1386     @Override
1387     public String getDeviceId() {
1388         if (isPhoneTypeGsm()) {
1389             return mImei;
1390         } else {
1391             CarrierConfigManager configManager = (CarrierConfigManager)
1392                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1393             boolean force_imei = configManager.getConfigForSubId(getSubId())
1394                     .getBoolean(CarrierConfigManager.KEY_FORCE_IMEI_BOOL);
1395             if (force_imei) return mImei;
1396
1397             String id = getMeid();
1398             if ((id == null) || id.matches("^0*$")) {
1399                 loge("getDeviceId(): MEID is not initialized use ESN");
1400                 id = getEsn();
1401             }
1402             return id;
1403         }
1404     }
1405
1406     @Override
1407     public String getDeviceSvn() {
1408         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1409             return mImeiSv;
1410         } else {
1411             loge("getDeviceSvn(): return 0");
1412             return "0";
1413         }
1414     }
1415
1416     @Override
1417     public IsimRecords getIsimRecords() {
1418         return mIsimUiccRecords;
1419     }
1420
1421     @Override
1422     public String getImei() {
1423         return mImei;
1424     }
1425
1426     @Override
1427     public String getEsn() {
1428         if (isPhoneTypeGsm()) {
1429             loge("[GsmCdmaPhone] getEsn() is a CDMA method");
1430             return "0";
1431         } else {
1432             return mEsn;
1433         }
1434     }
1435
1436     @Override
1437     public String getMeid() {
1438         if (isPhoneTypeGsm()) {
1439             loge("[GsmCdmaPhone] getMeid() is a CDMA method");
1440             return "0";
1441         } else {
1442             return mMeid;
1443         }
1444     }
1445
1446     @Override
1447     public String getNai() {
1448         IccRecords r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP2);
1449         if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
1450             Rlog.v(LOG_TAG, "IccRecords is " + r);
1451         }
1452         return (r != null) ? r.getNAI() : null;
1453     }
1454
1455     @Override
1456     public String getSubscriberId() {
1457         if (isPhoneTypeGsm()) {
1458             IccRecords r = mIccRecords.get();
1459             return (r != null) ? r.getIMSI() : null;
1460         } else if (isPhoneTypeCdma()) {
1461             return mSST.getImsi();
1462         } else { //isPhoneTypeCdmaLte()
1463             return (mSimRecords != null) ? mSimRecords.getIMSI() : "";
1464         }
1465     }
1466
1467     @Override
1468     public String getGroupIdLevel1() {
1469         if (isPhoneTypeGsm()) {
1470             IccRecords r = mIccRecords.get();
1471             return (r != null) ? r.getGid1() : null;
1472         } else if (isPhoneTypeCdma()) {
1473             loge("GID1 is not available in CDMA");
1474             return null;
1475         } else { //isPhoneTypeCdmaLte()
1476             return (mSimRecords != null) ? mSimRecords.getGid1() : "";
1477         }
1478     }
1479
1480     @Override
1481     public String getGroupIdLevel2() {
1482         if (isPhoneTypeGsm()) {
1483             IccRecords r = mIccRecords.get();
1484             return (r != null) ? r.getGid2() : null;
1485         } else if (isPhoneTypeCdma()) {
1486             loge("GID2 is not available in CDMA");
1487             return null;
1488         } else { //isPhoneTypeCdmaLte()
1489             return (mSimRecords != null) ? mSimRecords.getGid2() : "";
1490         }
1491     }
1492
1493     @Override
1494     public String getLine1Number() {
1495         if (isPhoneTypeGsm()) {
1496             IccRecords r = mIccRecords.get();
1497             return (r != null) ? r.getMsisdnNumber() : null;
1498         } else {
1499             return mSST.getMdnNumber();
1500         }
1501     }
1502
1503     @Override
1504     public String getCdmaPrlVersion() {
1505         return mSST.getPrlVersion();
1506     }
1507
1508     @Override
1509     public String getCdmaMin() {
1510         return mSST.getCdmaMin();
1511     }
1512
1513     @Override
1514     public boolean isMinInfoReady() {
1515         return mSST.isMinInfoReady();
1516     }
1517
1518     @Override
1519     public String getMsisdn() {
1520         if (isPhoneTypeGsm()) {
1521             IccRecords r = mIccRecords.get();
1522             return (r != null) ? r.getMsisdnNumber() : null;
1523         } else if (isPhoneTypeCdmaLte()) {
1524             return (mSimRecords != null) ? mSimRecords.getMsisdnNumber() : null;
1525         } else {
1526             loge("getMsisdn: not expected on CDMA");
1527             return null;
1528         }
1529     }
1530
1531     @Override
1532     public String getLine1AlphaTag() {
1533         if (isPhoneTypeGsm()) {
1534             IccRecords r = mIccRecords.get();
1535             return (r != null) ? r.getMsisdnAlphaTag() : null;
1536         } else {
1537             loge("getLine1AlphaTag: not possible in CDMA");
1538             return null;
1539         }
1540     }
1541
1542     @Override
1543     public boolean setLine1Number(String alphaTag, String number, Message onComplete) {
1544         if (isPhoneTypeGsm()) {
1545             IccRecords r = mIccRecords.get();
1546             if (r != null) {
1547                 r.setMsisdnNumber(alphaTag, number, onComplete);
1548                 return true;
1549             } else {
1550                 return false;
1551             }
1552         } else {
1553             loge("setLine1Number: not possible in CDMA");
1554             return false;
1555         }
1556     }
1557
1558     @Override
1559     public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete) {
1560         Message resp;
1561         mVmNumber = voiceMailNumber;
1562         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
1563         IccRecords r = mIccRecords.get();
1564         if (r != null) {
1565             r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
1566         }
1567     }
1568
1569     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
1570         switch (commandInterfaceCFReason) {
1571             case CF_REASON_UNCONDITIONAL:
1572             case CF_REASON_BUSY:
1573             case CF_REASON_NO_REPLY:
1574             case CF_REASON_NOT_REACHABLE:
1575             case CF_REASON_ALL:
1576             case CF_REASON_ALL_CONDITIONAL:
1577                 return true;
1578             default:
1579                 return false;
1580         }
1581     }
1582
1583     @Override
1584     public String getSystemProperty(String property, String defValue) {
1585         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1586             if (getUnitTestMode()) {
1587                 return null;
1588             }
1589             return TelephonyManager.getTelephonyProperty(mPhoneId, property, defValue);
1590         } else {
1591             return super.getSystemProperty(property, defValue);
1592         }
1593     }
1594
1595     private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
1596         switch (commandInterfaceCFAction) {
1597             case CF_ACTION_DISABLE:
1598             case CF_ACTION_ENABLE:
1599             case CF_ACTION_REGISTRATION:
1600             case CF_ACTION_ERASURE:
1601                 return true;
1602             default:
1603                 return false;
1604         }
1605     }
1606
1607     private boolean isCfEnable(int action) {
1608         return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
1609     }
1610
1611     @Override
1612     public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
1613         if (isPhoneTypeGsm()) {
1614             Phone imsPhone = mImsPhone;
1615             if ((imsPhone != null)
1616                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1617                     || imsPhone.isUtEnabled())) {
1618                 imsPhone.getCallForwardingOption(commandInterfaceCFReason, onComplete);
1619                 return;
1620             }
1621
1622             if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
1623                 if (DBG) logd("requesting call forwarding query.");
1624                 Message resp;
1625                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1626                     resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
1627                 } else {
1628                     resp = onComplete;
1629                 }
1630                 mCi.queryCallForwardStatus(commandInterfaceCFReason, 0, null, resp);
1631             }
1632         } else {
1633             loge("getCallForwardingOption: not possible in CDMA");
1634         }
1635     }
1636
1637     @Override
1638     public void setCallForwardingOption(int commandInterfaceCFAction,
1639             int commandInterfaceCFReason,
1640             String dialingNumber,
1641             int timerSeconds,
1642             Message onComplete) {
1643         if (isPhoneTypeGsm()) {
1644             Phone imsPhone = mImsPhone;
1645             if ((imsPhone != null)
1646                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1647                     || imsPhone.isUtEnabled())) {
1648                 imsPhone.setCallForwardingOption(commandInterfaceCFAction,
1649                         commandInterfaceCFReason, dialingNumber, timerSeconds, onComplete);
1650                 return;
1651             }
1652
1653             if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
1654                     (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
1655
1656                 Message resp;
1657                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1658                     Cfu cfu = new Cfu(dialingNumber, onComplete);
1659                     resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
1660                             isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cfu);
1661                 } else {
1662                     resp = onComplete;
1663                 }
1664                 mCi.setCallForward(commandInterfaceCFAction,
1665                         commandInterfaceCFReason,
1666                         CommandsInterface.SERVICE_CLASS_VOICE,
1667                         dialingNumber,
1668                         timerSeconds,
1669                         resp);
1670             }
1671         } else {
1672             loge("setCallForwardingOption: not possible in CDMA");
1673         }
1674     }
1675
1676     @Override
1677     public void getOutgoingCallerIdDisplay(Message onComplete) {
1678         if (isPhoneTypeGsm()) {
1679             Phone imsPhone = mImsPhone;
1680             if ((imsPhone != null)
1681                     && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1682                 imsPhone.getOutgoingCallerIdDisplay(onComplete);
1683                 return;
1684             }
1685             mCi.getCLIR(onComplete);
1686         } else {
1687             loge("getOutgoingCallerIdDisplay: not possible in CDMA");
1688         }
1689     }
1690
1691     @Override
1692     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
1693         if (isPhoneTypeGsm()) {
1694             Phone imsPhone = mImsPhone;
1695             if ((imsPhone != null)
1696                     && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1697                 imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete);
1698                 return;
1699             }
1700             // Packing CLIR value in the message. This will be required for
1701             // SharedPreference caching, if the message comes back as part of
1702             // a success response.
1703             mCi.setCLIR(commandInterfaceCLIRMode,
1704                     obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
1705         } else {
1706             loge("setOutgoingCallerIdDisplay: not possible in CDMA");
1707         }
1708     }
1709
1710     @Override
1711     public void getCallWaiting(Message onComplete) {
1712         if (isPhoneTypeGsm()) {
1713             Phone imsPhone = mImsPhone;
1714             if ((imsPhone != null)
1715                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1716                     || imsPhone.isUtEnabled())) {
1717                 imsPhone.getCallWaiting(onComplete);
1718                 return;
1719             }
1720
1721             //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
1722             //class parameter in call waiting interrogation  to network
1723             mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
1724         } else {
1725             mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
1726         }
1727     }
1728
1729     @Override
1730     public void setCallWaiting(boolean enable, Message onComplete) {
1731         if (isPhoneTypeGsm()) {
1732             Phone imsPhone = mImsPhone;
1733             if ((imsPhone != null)
1734                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1735                     || imsPhone.isUtEnabled())) {
1736                 imsPhone.setCallWaiting(enable, onComplete);
1737                 return;
1738             }
1739
1740             mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
1741         } else {
1742             loge("method setCallWaiting is NOT supported in CDMA!");
1743         }
1744     }
1745
1746     @Override
1747     public void getAvailableNetworks(Message response) {
1748         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1749             mCi.getAvailableNetworks(response);
1750         } else {
1751             loge("getAvailableNetworks: not possible in CDMA");
1752         }
1753     }
1754
1755     @Override
1756     public void getNeighboringCids(Message response, WorkSource workSource) {
1757         if (isPhoneTypeGsm()) {
1758             mCi.getNeighboringCids(response, workSource);
1759         } else {
1760             /*
1761              * This is currently not implemented.  At least as of June
1762              * 2009, there is no neighbor cell information available for
1763              * CDMA because some party is resisting making this
1764              * information readily available.  Consequently, calling this
1765              * function can have no useful effect.  This situation may
1766              * (and hopefully will) change in the future.
1767              */
1768             if (response != null) {
1769                 CommandException ce = new CommandException(
1770                         CommandException.Error.REQUEST_NOT_SUPPORTED);
1771                 AsyncResult.forMessage(response).exception = ce;
1772                 response.sendToTarget();
1773             }
1774         }
1775     }
1776
1777     @Override
1778     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
1779        if (mImsPhone != null) {
1780            mImsPhone.setUiTTYMode(uiTtyMode, onComplete);
1781        }
1782     }
1783
1784     @Override
1785     public void setMute(boolean muted) {
1786         mCT.setMute(muted);
1787     }
1788
1789     @Override
1790     public boolean getMute() {
1791         return mCT.getMute();
1792     }
1793
1794     @Override
1795     public void getDataCallList(Message response) {
1796         mCi.getDataCallList(response);
1797     }
1798
1799     @Override
1800     public void updateServiceLocation() {
1801         mSST.enableSingleLocationUpdate();
1802     }
1803
1804     @Override
1805     public void enableLocationUpdates() {
1806         mSST.enableLocationUpdates();
1807     }
1808
1809     @Override
1810     public void disableLocationUpdates() {
1811         mSST.disableLocationUpdates();
1812     }
1813
1814     @Override
1815     public boolean getDataRoamingEnabled() {
1816         return mDcTracker.getDataOnRoamingEnabled();
1817     }
1818
1819     @Override
1820     public void setDataRoamingEnabled(boolean enable) {
1821         mDcTracker.setDataOnRoamingEnabled(enable);
1822     }
1823
1824     @Override
1825     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
1826         mCi.registerForCdmaOtaProvision(h, what, obj);
1827     }
1828
1829     @Override
1830     public void unregisterForCdmaOtaStatusChange(Handler h) {
1831         mCi.unregisterForCdmaOtaProvision(h);
1832     }
1833
1834     @Override
1835     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
1836         mSST.registerForSubscriptionInfoReady(h, what, obj);
1837     }
1838
1839     @Override
1840     public void unregisterForSubscriptionInfoReady(Handler h) {
1841         mSST.unregisterForSubscriptionInfoReady(h);
1842     }
1843
1844     @Override
1845     public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
1846         mEcmExitRespRegistrant = new Registrant(h, what, obj);
1847     }
1848
1849     @Override
1850     public void unsetOnEcbModeExitResponse(Handler h) {
1851         mEcmExitRespRegistrant.clear();
1852     }
1853
1854     @Override
1855     public void registerForCallWaiting(Handler h, int what, Object obj) {
1856         mCT.registerForCallWaiting(h, what, obj);
1857     }
1858
1859     @Override
1860     public void unregisterForCallWaiting(Handler h) {
1861         mCT.unregisterForCallWaiting(h);
1862     }
1863
1864     @Override
1865     public boolean getDataEnabled() {
1866         return mDcTracker.getDataEnabled();
1867     }
1868
1869     @Override
1870     public void setDataEnabled(boolean enable) {
1871         mDcTracker.setDataEnabled(enable);
1872     }
1873
1874     /**
1875      * Removes the given MMI from the pending list and notifies
1876      * registrants that it is complete.
1877      * @param mmi MMI that is done
1878      */
1879     public void onMMIDone(MmiCode mmi) {
1880
1881         /* Only notify complete if it's on the pending list.
1882          * Otherwise, it's already been handled (eg, previously canceled).
1883          * The exception is cancellation of an incoming USSD-REQUEST, which is
1884          * not on the list.
1885          */
1886         if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
1887                 ((GsmMmiCode)mmi).isSsInfo()))) {
1888             mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1889         }
1890     }
1891
1892     public boolean supports3gppCallForwardingWhileRoaming() {
1893         CarrierConfigManager configManager = (CarrierConfigManager)
1894                 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
1895         PersistableBundle b = configManager.getConfig();
1896         if (b != null) {
1897             return b.getBoolean(
1898                     CarrierConfigManager.KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
1899         } else {
1900             // Default value set in CarrierConfigManager
1901             return true;
1902         }
1903     }
1904
1905     private void onNetworkInitiatedUssd(MmiCode mmi) {
1906         mMmiCompleteRegistrants.notifyRegistrants(
1907             new AsyncResult(null, mmi, null));
1908     }
1909
1910     /** ussdMode is one of CommandsInterface.USSD_MODE_* */
1911     private void onIncomingUSSD (int ussdMode, String ussdMessage) {
1912         if (!isPhoneTypeGsm()) {
1913             loge("onIncomingUSSD: not expected on GSM");
1914         }
1915         boolean isUssdError;
1916         boolean isUssdRequest;
1917         boolean isUssdRelease;
1918
1919         isUssdRequest
1920             = (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
1921
1922         isUssdError
1923             = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
1924                 && ussdMode != CommandsInterface.USSD_MODE_REQUEST);
1925
1926         isUssdRelease = (ussdMode == CommandsInterface.USSD_MODE_NW_RELEASE);
1927
1928
1929         // See comments in GsmMmiCode.java
1930         // USSD requests aren't finished until one
1931         // of these two events happen
1932         GsmMmiCode found = null;
1933         for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
1934             if(((GsmMmiCode)mPendingMMIs.get(i)).isPendingUSSD()) {
1935                 found = (GsmMmiCode)mPendingMMIs.get(i);
1936                 break;
1937             }
1938         }
1939
1940         if (found != null) {
1941             // Complete pending USSD
1942
1943             if (isUssdRelease) {
1944                 found.onUssdRelease();
1945             } else if (isUssdError) {
1946                 found.onUssdFinishedError();
1947             } else {
1948                 found.onUssdFinished(ussdMessage, isUssdRequest);
1949             }
1950         } else { // pending USSD not found
1951             // The network may initiate its own USSD request
1952
1953             // ignore everything that isnt a Notify or a Request
1954             // also, discard if there is no message to present
1955             if (!isUssdError && ussdMessage != null) {
1956                 GsmMmiCode mmi;
1957                 mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
1958                                                    isUssdRequest,
1959                                                    GsmCdmaPhone.this,
1960                                                    mUiccApplication.get());
1961                 onNetworkInitiatedUssd(mmi);
1962             }
1963         }
1964     }
1965
1966     /**
1967      * Make sure the network knows our preferred setting.
1968      */
1969     private void syncClirSetting() {
1970         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1971         int clirSetting = sp.getInt(CLIR_KEY + getPhoneId(), -1);
1972         if (clirSetting >= 0) {
1973             mCi.setCLIR(clirSetting, null);
1974         }
1975     }
1976
1977     private void handleRadioAvailable() {
1978         mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
1979
1980         mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
1981         mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
1982         startLceAfterRadioIsAvailable();
1983     }
1984
1985     private void handleRadioOn() {
1986         /* Proactively query voice radio technologies */
1987         mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
1988
1989         if (!isPhoneTypeGsm()) {
1990             mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
1991         }
1992
1993         // If this is on APM off, SIM may already be loaded. Send setPreferredNetworkType
1994         // request to RIL to preserve user setting across APM toggling
1995         setPreferredNetworkTypeIfSimLoaded();
1996     }
1997
1998     private void handleRadioOffOrNotAvailable() {
1999         if (isPhoneTypeGsm()) {
2000             // Some MMI requests (eg USSD) are not completed
2001             // within the course of a CommandsInterface request
2002             // If the radio shuts off or resets while one of these
2003             // is pending, we need to clean up.
2004
2005             for (int i = mPendingMMIs.size() - 1; i >= 0; i--) {
2006                 if (((GsmMmiCode) mPendingMMIs.get(i)).isPendingUSSD()) {
2007                     ((GsmMmiCode) mPendingMMIs.get(i)).onUssdFinishedError();
2008                 }
2009             }
2010         }
2011         Phone imsPhone = mImsPhone;
2012         if (imsPhone != null) {
2013             imsPhone.getServiceState().setStateOff();
2014         }
2015         mRadioOffOrNotAvailableRegistrants.notifyRegistrants();
2016     }
2017
2018     @Override
2019     public void handleMessage(Message msg) {
2020         AsyncResult ar;
2021         Message onComplete;
2022
2023         switch (msg.what) {
2024             case EVENT_RADIO_AVAILABLE: {
2025                 handleRadioAvailable();
2026             }
2027             break;
2028
2029             case EVENT_GET_DEVICE_IDENTITY_DONE:{
2030                 ar = (AsyncResult)msg.obj;
2031
2032                 if (ar.exception != null) {
2033                     break;
2034                 }
2035                 String[] respId = (String[])ar.result;
2036                 mImei = respId[0];
2037                 mImeiSv = respId[1];
2038                 mEsn  =  respId[2];
2039                 mMeid =  respId[3];
2040             }
2041             break;
2042
2043             case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
2044                 handleEnterEmergencyCallbackMode(msg);
2045             }
2046             break;
2047
2048             case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
2049                 handleExitEmergencyCallbackMode(msg);
2050             }
2051             break;
2052
2053             case EVENT_RUIM_RECORDS_LOADED:
2054                 logd("Event EVENT_RUIM_RECORDS_LOADED Received");
2055                 updateCurrentCarrierInProvider();
2056                 break;
2057
2058             case EVENT_RADIO_ON:
2059                 logd("Event EVENT_RADIO_ON Received");
2060                 handleRadioOn();
2061                 break;
2062
2063             case EVENT_RIL_CONNECTED:
2064                 ar = (AsyncResult) msg.obj;
2065                 if (ar.exception == null && ar.result != null) {
2066                     mRilVersion = (Integer) ar.result;
2067                 } else {
2068                     logd("Unexpected exception on EVENT_RIL_CONNECTED");
2069                     mRilVersion = -1;
2070                 }
2071                 break;
2072
2073             case EVENT_VOICE_RADIO_TECH_CHANGED:
2074             case EVENT_REQUEST_VOICE_RADIO_TECH_DONE:
2075                 String what = (msg.what == EVENT_VOICE_RADIO_TECH_CHANGED) ?
2076                         "EVENT_VOICE_RADIO_TECH_CHANGED" : "EVENT_REQUEST_VOICE_RADIO_TECH_DONE";
2077                 ar = (AsyncResult) msg.obj;
2078                 if (ar.exception == null) {
2079                     if ((ar.result != null) && (((int[]) ar.result).length != 0)) {
2080                         int newVoiceTech = ((int[]) ar.result)[0];
2081                         logd(what + ": newVoiceTech=" + newVoiceTech);
2082                         phoneObjectUpdater(newVoiceTech);
2083                     } else {
2084                         loge(what + ": has no tech!");
2085                     }
2086                 } else {
2087                     loge(what + ": exception=" + ar.exception);
2088                 }
2089                 break;
2090
2091             case EVENT_UPDATE_PHONE_OBJECT:
2092                 phoneObjectUpdater(msg.arg1);
2093                 break;
2094
2095             case EVENT_CARRIER_CONFIG_CHANGED:
2096                 // Only check for the voice radio tech if it not going to be updated by the voice
2097                 // registration changes.
2098                 if (!mContext.getResources().getBoolean(com.android.internal.R.bool.
2099                         config_switch_phone_on_voice_reg_state_change)) {
2100                     mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
2101                 }
2102                 // Force update IMS service
2103                 ImsManager.updateImsServiceConfig(mContext, mPhoneId, true);
2104
2105                 // Update broadcastEmergencyCallStateChanges
2106                 CarrierConfigManager configMgr = (CarrierConfigManager)
2107                         getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
2108                 PersistableBundle b = configMgr.getConfigForSubId(getSubId());
2109                 if (b != null) {
2110                     boolean broadcastEmergencyCallStateChanges = b.getBoolean(
2111                             CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL);
2112                     logd("broadcastEmergencyCallStateChanges = " +
2113                             broadcastEmergencyCallStateChanges);
2114                     setBroadcastEmergencyCallStateChanges(broadcastEmergencyCallStateChanges);
2115                 } else {
2116                     loge("didn't get broadcastEmergencyCallStateChanges from carrier config");
2117                 }
2118
2119                 // Changing the cdma roaming settings based carrier config.
2120                 if (b != null) {
2121                     int config_cdma_roaming_mode = b.getInt(
2122                             CarrierConfigManager.KEY_CDMA_ROAMING_MODE_INT);
2123                     int current_cdma_roaming_mode =
2124                             Settings.Global.getInt(getContext().getContentResolver(),
2125                             Settings.Global.CDMA_ROAMING_MODE,
2126                             CarrierConfigManager.CDMA_ROAMING_MODE_RADIO_DEFAULT);
2127                     switch (config_cdma_roaming_mode) {
2128                         // Carrier's cdma_roaming_mode will overwrite the user's previous settings
2129                         // Keep the user's previous setting in global variable which will be used
2130                         // when carrier's setting is turn off.
2131                         case CarrierConfigManager.CDMA_ROAMING_MODE_HOME:
2132                         case CarrierConfigManager.CDMA_ROAMING_MODE_AFFILIATED:
2133                         case CarrierConfigManager.CDMA_ROAMING_MODE_ANY:
2134                             logd("cdma_roaming_mode is going to changed to "
2135                                     + config_cdma_roaming_mode);
2136                             setCdmaRoamingPreference(config_cdma_roaming_mode,
2137                                     obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
2138                             break;
2139
2140                         // When carrier's setting is turn off, change the cdma_roaming_mode to the
2141                         // previous user's setting
2142                         case CarrierConfigManager.CDMA_ROAMING_MODE_RADIO_DEFAULT:
2143                             if (current_cdma_roaming_mode != config_cdma_roaming_mode) {
2144                                 logd("cdma_roaming_mode is going to changed to "
2145                                         + current_cdma_roaming_mode);
2146                                 setCdmaRoamingPreference(current_cdma_roaming_mode,
2147                                         obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
2148                             }
2149
2150                         default:
2151                             loge("Invalid cdma_roaming_mode settings: "
2152                                     + config_cdma_roaming_mode);
2153                     }
2154                 } else {
2155                     loge("didn't get the cdma_roaming_mode changes from the carrier config.");
2156                 }
2157
2158                 // Load the ERI based on carrier config. Carrier might have their specific ERI.
2159                 prepareEri();
2160                 if (!isPhoneTypeGsm()) {
2161                     mSST.pollState();
2162                 }
2163
2164                 break;
2165
2166             case EVENT_SET_ROAMING_PREFERENCE_DONE:
2167                 logd("cdma_roaming_mode change is done");
2168                 break;
2169
2170             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
2171                 logd("EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED");
2172                 mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
2173                 break;
2174
2175             case EVENT_REGISTERED_TO_NETWORK:
2176                 logd("Event EVENT_REGISTERED_TO_NETWORK Received");
2177                 if (isPhoneTypeGsm()) {
2178                     syncClirSetting();
2179                 }
2180                 break;
2181
2182             case EVENT_SIM_RECORDS_LOADED:
2183                 if (isPhoneTypeGsm()) {
2184                     updateCurrentCarrierInProvider();
2185
2186                     // Check if this is a different SIM than the previous one. If so unset the
2187                     // voice mail number.
2188                     String imsi = getVmSimImsi();
2189                     String imsiFromSIM = getSubscriberId();
2190                     if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
2191                         storeVoiceMailNumber(null);
2192                         setVmSimImsi(null);
2193                     }
2194                 }
2195
2196                 mSimRecordsLoadedRegistrants.notifyRegistrants();
2197                 break;
2198
2199             case EVENT_GET_BASEBAND_VERSION_DONE:
2200                 ar = (AsyncResult)msg.obj;
2201
2202                 if (ar.exception != null) {
2203                     break;
2204                 }
2205
2206                 if (DBG) logd("Baseband version: " + ar.result);
2207                 TelephonyManager.from(mContext).setBasebandVersionForPhone(getPhoneId(),
2208                         (String)ar.result);
2209             break;
2210
2211             case EVENT_GET_IMEI_DONE:
2212                 ar = (AsyncResult)msg.obj;
2213
2214                 if (ar.exception != null) {
2215                     break;
2216                 }
2217
2218                 mImei = (String)ar.result;
2219             break;
2220
2221             case EVENT_GET_IMEISV_DONE:
2222                 ar = (AsyncResult)msg.obj;
2223
2224                 if (ar.exception != null) {
2225                     break;
2226                 }
2227
2228                 mImeiSv = (String)ar.result;
2229             break;
2230
2231             case EVENT_USSD:
2232                 ar = (AsyncResult)msg.obj;
2233
2234                 String[] ussdResult = (String[]) ar.result;
2235
2236                 if (ussdResult.length > 1) {
2237                     try {
2238                         onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
2239                     } catch (NumberFormatException e) {
2240                         Rlog.w(LOG_TAG, "error parsing USSD");
2241                     }
2242                 }
2243             break;
2244
2245             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: {
2246                 logd("Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
2247                 handleRadioOffOrNotAvailable();
2248                 break;
2249             }
2250
2251             case EVENT_SSN:
2252                 logd("Event EVENT_SSN Received");
2253                 if (isPhoneTypeGsm()) {
2254                     ar = (AsyncResult) msg.obj;
2255                     SuppServiceNotification not = (SuppServiceNotification) ar.result;
2256                     mSsnRegistrants.notifyRegistrants(ar);
2257                 }
2258                 break;
2259
2260             case EVENT_SET_CALL_FORWARD_DONE:
2261                 ar = (AsyncResult)msg.obj;
2262                 IccRecords r = mIccRecords.get();
2263                 Cfu cfu = (Cfu) ar.userObj;
2264                 if (ar.exception == null && r != null) {
2265                     setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber);
2266                 }
2267                 if (cfu.mOnComplete != null) {
2268                     AsyncResult.forMessage(cfu.mOnComplete, ar.result, ar.exception);
2269                     cfu.mOnComplete.sendToTarget();
2270                 }
2271                 break;
2272
2273             case EVENT_SET_VM_NUMBER_DONE:
2274                 ar = (AsyncResult)msg.obj;
2275                 if ((isPhoneTypeGsm() && IccVmNotSupportedException.class.isInstance(ar.exception)) ||
2276                         (!isPhoneTypeGsm() && IccException.class.isInstance(ar.exception))){
2277                     storeVoiceMailNumber(mVmNumber);
2278                     ar.exception = null;
2279                 }
2280                 onComplete = (Message) ar.userObj;
2281                 if (onComplete != null) {
2282                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2283                     onComplete.sendToTarget();
2284                 }
2285                 break;
2286
2287
2288             case EVENT_GET_CALL_FORWARD_DONE:
2289                 ar = (AsyncResult)msg.obj;
2290                 if (ar.exception == null) {
2291                     handleCfuQueryResult((CallForwardInfo[])ar.result);
2292                 }
2293                 onComplete = (Message) ar.userObj;
2294                 if (onComplete != null) {
2295                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2296                     onComplete.sendToTarget();
2297                 }
2298                 break;
2299
2300             case EVENT_SET_NETWORK_AUTOMATIC:
2301                 // Automatic network selection from EF_CSP SIM record
2302                 ar = (AsyncResult) msg.obj;
2303                 if (mSST.mSS.getIsManualSelection()) {
2304                     setNetworkSelectionModeAutomatic((Message) ar.result);
2305                     logd("SET_NETWORK_SELECTION_AUTOMATIC: set to automatic");
2306                 } else {
2307                     // prevent duplicate request which will push current PLMN to low priority
2308                     logd("SET_NETWORK_SELECTION_AUTOMATIC: already automatic, ignore");
2309                 }
2310                 break;
2311
2312             case EVENT_ICC_RECORD_EVENTS:
2313                 ar = (AsyncResult)msg.obj;
2314                 processIccRecordEvents((Integer)ar.result);
2315                 break;
2316
2317             case EVENT_SET_CLIR_COMPLETE:
2318                 ar = (AsyncResult)msg.obj;
2319                 if (ar.exception == null) {
2320                     saveClirSetting(msg.arg1);
2321                 }
2322                 onComplete = (Message) ar.userObj;
2323                 if (onComplete != null) {
2324                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2325                     onComplete.sendToTarget();
2326                 }
2327                 break;
2328
2329             case EVENT_SS:
2330                 ar = (AsyncResult)msg.obj;
2331                 logd("Event EVENT_SS received");
2332                 if (isPhoneTypeGsm()) {
2333                     // SS data is already being handled through MMI codes.
2334                     // So, this result if processed as MMI response would help
2335                     // in re-using the existing functionality.
2336                     GsmMmiCode mmi = new GsmMmiCode(this, mUiccApplication.get());
2337                     mmi.processSsData(ar);
2338                 }
2339                 break;
2340
2341             case EVENT_GET_RADIO_CAPABILITY:
2342                 ar = (AsyncResult) msg.obj;
2343                 RadioCapability rc = (RadioCapability) ar.result;
2344                 if (ar.exception != null) {
2345                     Rlog.d(LOG_TAG, "get phone radio capability fail, no need to change " +
2346                             "mRadioCapability");
2347                 } else {
2348                     radioCapabilityUpdated(rc);
2349                 }
2350                 Rlog.d(LOG_TAG, "EVENT_GET_RADIO_CAPABILITY: phone rc: " + rc);
2351                 break;
2352
2353             default:
2354                 super.handleMessage(msg);
2355         }
2356     }
2357
2358     public UiccCardApplication getUiccCardApplication() {
2359         if (isPhoneTypeGsm()) {
2360             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP);
2361         } else {
2362             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
2363         }
2364     }
2365
2366     @Override
2367     protected void onUpdateIccAvailability() {
2368         if (mUiccController == null ) {
2369             return;
2370         }
2371
2372         UiccCardApplication newUiccApplication = null;
2373
2374         // Update mIsimUiccRecords
2375         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
2376             newUiccApplication =
2377                     mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS);
2378             IsimUiccRecords newIsimUiccRecords = null;
2379
2380             if (newUiccApplication != null) {
2381                 newIsimUiccRecords = (IsimUiccRecords) newUiccApplication.getIccRecords();
2382                 if (DBG) logd("New ISIM application found");
2383             }
2384             mIsimUiccRecords = newIsimUiccRecords;
2385         }
2386
2387         // Update mSimRecords
2388         if (mSimRecords != null) {
2389             mSimRecords.unregisterForRecordsLoaded(this);
2390         }
2391         if (isPhoneTypeCdmaLte()) {
2392             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
2393                     UiccController.APP_FAM_3GPP);
2394             SIMRecords newSimRecords = null;
2395             if (newUiccApplication != null) {
2396                 newSimRecords = (SIMRecords) newUiccApplication.getIccRecords();
2397             }
2398             mSimRecords = newSimRecords;
2399             if (mSimRecords != null) {
2400                 mSimRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
2401             }
2402         } else {
2403             mSimRecords = null;
2404         }
2405
2406         // Update mIccRecords, mUiccApplication, mIccPhoneBookIntManager
2407         newUiccApplication = getUiccCardApplication();
2408         if (!isPhoneTypeGsm() && newUiccApplication == null) {
2409             logd("can't find 3GPP2 application; trying APP_FAM_3GPP");
2410             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
2411                     UiccController.APP_FAM_3GPP);
2412         }
2413
2414         UiccCardApplication app = mUiccApplication.get();
2415         if (app != newUiccApplication) {
2416             if (app != null) {
2417                 if (DBG) logd("Removing stale icc objects.");
2418                 if (mIccRecords.get() != null) {
2419                     unregisterForIccRecordEvents();
2420                     mIccPhoneBookIntManager.updateIccRecords(null);
2421                 }
2422                 mIccRecords.set(null);
2423                 mUiccApplication.set(null);
2424             }
2425             if (newUiccApplication != null) {
2426                 if (DBG) {
2427                     logd("New Uicc application found. type = " + newUiccApplication.getType());
2428                 }
2429                 mUiccApplication.set(newUiccApplication);
2430                 mIccRecords.set(newUiccApplication.getIccRecords());
2431                 registerForIccRecordEvents();
2432                 mIccPhoneBookIntManager.updateIccRecords(mIccRecords.get());
2433             }
2434         }
2435     }
2436
2437     private void processIccRecordEvents(int eventCode) {
2438         switch (eventCode) {
2439             case IccRecords.EVENT_CFI:
2440                 notifyCallForwardingIndicator();
2441                 break;
2442         }
2443     }
2444
2445     /**
2446      * Sets the "current" field in the telephony provider according to the SIM's operator
2447      *
2448      * @return true for success; false otherwise.
2449      */
2450     @Override
2451     public boolean updateCurrentCarrierInProvider() {
2452         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
2453             long currentDds = SubscriptionManager.getDefaultDataSubscriptionId();
2454             String operatorNumeric = getOperatorNumeric();
2455
2456             logd("updateCurrentCarrierInProvider: mSubId = " + getSubId()
2457                     + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric);
2458
2459             if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) {
2460                 try {
2461                     Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
2462                     ContentValues map = new ContentValues();
2463                     map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
2464                     mContext.getContentResolver().insert(uri, map);
2465                     return true;
2466                 } catch (SQLException e) {
2467                     Rlog.e(LOG_TAG, "Can't store current operator", e);
2468                 }
2469             }
2470             return false;
2471         } else {
2472             return true;
2473         }
2474     }
2475
2476     //CDMA
2477     /**
2478      * Sets the "current" field in the telephony provider according to the
2479      * build-time operator numeric property
2480      *
2481      * @return true for success; false otherwise.
2482      */
2483     private boolean updateCurrentCarrierInProvider(String operatorNumeric) {
2484         if (isPhoneTypeCdma()
2485                 || (isPhoneTypeCdmaLte() && mUiccController.getUiccCardApplication(mPhoneId,
2486                         UiccController.APP_FAM_3GPP) == null)) {
2487             logd("CDMAPhone: updateCurrentCarrierInProvider called");
2488             if (!TextUtils.isEmpty(operatorNumeric)) {
2489                 try {
2490                     Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
2491                     ContentValues map = new ContentValues();
2492                     map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
2493                     logd("updateCurrentCarrierInProvider from system: numeric=" + operatorNumeric);
2494                     getContext().getContentResolver().insert(uri, map);
2495
2496                     // Updates MCC MNC device configuration information
2497                     logd("update mccmnc=" + operatorNumeric);
2498                     MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
2499
2500                     return true;
2501                 } catch (SQLException e) {
2502                     Rlog.e(LOG_TAG, "Can't store current operator", e);
2503                 }
2504             }
2505             return false;
2506         } else { // isPhoneTypeCdmaLte()
2507             if (DBG) logd("updateCurrentCarrierInProvider not updated X retVal=" + true);
2508             return true;
2509         }
2510     }
2511
2512     private void handleCfuQueryResult(CallForwardInfo[] infos) {
2513         IccRecords r = mIccRecords.get();
2514         if (r != null) {
2515             if (infos == null || infos.length == 0) {
2516                 // Assume the default is not active
2517                 // Set unconditional CFF in SIM to false
2518                 setVoiceCallForwardingFlag(1, false, null);
2519             } else {
2520                 for (int i = 0, s = infos.length; i < s; i++) {
2521                     if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
2522                         setVoiceCallForwardingFlag(1, (infos[i].status == 1),
2523                             infos[i].number);
2524                         // should only have the one
2525                         break;
2526                     }
2527                 }
2528             }
2529         }
2530     }
2531
2532     /**
2533      * Retrieves the IccPhoneBookInterfaceManager of the GsmCdmaPhone
2534      */
2535     @Override
2536     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
2537         return mIccPhoneBookIntManager;
2538     }
2539
2540     //CDMA
2541     public void registerForEriFileLoaded(Handler h, int what, Object obj) {
2542         Registrant r = new Registrant (h, what, obj);
2543         mEriFileLoadedRegistrants.add(r);
2544     }
2545
2546     //CDMA
2547     public void unregisterForEriFileLoaded(Handler h) {
2548         mEriFileLoadedRegistrants.remove(h);
2549     }
2550
2551     //CDMA
2552     public void prepareEri() {
2553         if (mEriManager == null) {
2554             Rlog.e(LOG_TAG, "PrepareEri: Trying to access stale objects");
2555             return;
2556         }
2557         mEriManager.loadEriFile();
2558         if(mEriManager.isEriFileLoaded()) {
2559             // when the ERI file is loaded
2560             logd("ERI read, notify registrants");
2561             mEriFileLoadedRegistrants.notifyRegistrants();
2562         }
2563     }
2564
2565     //CDMA
2566     public boolean isEriFileLoaded() {
2567         return mEriManager.isEriFileLoaded();
2568     }
2569
2570
2571     /**
2572      * Activate or deactivate cell broadcast SMS.
2573      *
2574      * @param activate 0 = activate, 1 = deactivate
2575      * @param response Callback message is empty on completion
2576      */
2577     @Override
2578     public void activateCellBroadcastSms(int activate, Message response) {
2579         loge("[GsmCdmaPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
2580         response.sendToTarget();
2581     }
2582
2583     /**
2584      * Query the current configuration of cdma cell broadcast SMS.
2585      *
2586      * @param response Callback message is empty on completion
2587      */
2588     @Override
2589     public void getCellBroadcastSmsConfig(Message response) {
2590         loge("[GsmCdmaPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
2591         response.sendToTarget();
2592     }
2593
2594     /**
2595      * Configure cdma cell broadcast SMS.
2596      *
2597      * @param response Callback message is empty on completion
2598      */
2599     @Override
2600     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
2601         loge("[GsmCdmaPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
2602         response.sendToTarget();
2603     }
2604
2605     /**
2606      * Returns true if OTA Service Provisioning needs to be performed.
2607      */
2608     @Override
2609     public boolean needsOtaServiceProvisioning() {
2610         if (isPhoneTypeGsm()) {
2611             return false;
2612         } else {
2613             return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
2614         }
2615     }
2616
2617     @Override
2618     public boolean isCspPlmnEnabled() {
2619         IccRecords r = mIccRecords.get();
2620         return (r != null) ? r.isCspPlmnEnabled() : false;
2621     }
2622
2623     public boolean isManualNetSelAllowed() {
2624
2625         int nwMode = Phone.PREFERRED_NT_MODE;
2626         int subId = getSubId();
2627
2628         nwMode = android.provider.Settings.Global.getInt(mContext.getContentResolver(),
2629                     android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, nwMode);
2630
2631         logd("isManualNetSelAllowed in mode = " + nwMode);
2632         /*
2633          *  For multimode targets in global mode manual network
2634          *  selection is disallowed
2635          */
2636         if (isManualSelProhibitedInGlobalMode()
2637                 && ((nwMode == Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
2638                         || (nwMode == Phone.NT_MODE_GLOBAL)) ){
2639             logd("Manual selection not supported in mode = " + nwMode);
2640             return false;
2641         } else {
2642             logd("Manual selection is supported in mode = " + nwMode);
2643         }
2644
2645         /*
2646          *  Single mode phone with - GSM network modes/global mode
2647          *  LTE only for 3GPP
2648          *  LTE centric + 3GPP Legacy
2649          *  Note: the actual enabling/disabling manual selection for these
2650          *  cases will be controlled by csp
2651          */
2652         return true;
2653     }
2654
2655     private boolean isManualSelProhibitedInGlobalMode() {
2656         boolean isProhibited = false;
2657         final String configString = getContext().getResources().getString(com.android.internal.
2658                 R.string.prohibit_manual_network_selection_in_gobal_mode);
2659
2660         if (!TextUtils.isEmpty(configString)) {
2661             String[] configArray = configString.split(";");
2662
2663             if (configArray != null &&
2664                     ((configArray.length == 1 && configArray[0].equalsIgnoreCase("true")) ||
2665                         (configArray.length == 2 && !TextUtils.isEmpty(configArray[1]) &&
2666                             configArray[0].equalsIgnoreCase("true") &&
2667                             isMatchGid(configArray[1])))) {
2668                             isProhibited = true;
2669             }
2670         }
2671         logd("isManualNetSelAllowedInGlobal in current carrier is " + isProhibited);
2672         return isProhibited;
2673     }
2674
2675     private void registerForIccRecordEvents() {
2676         IccRecords r = mIccRecords.get();
2677         if (r == null) {
2678             return;
2679         }
2680         if (isPhoneTypeGsm()) {
2681             r.registerForNetworkSelectionModeAutomatic(
2682                     this, EVENT_SET_NETWORK_AUTOMATIC, null);
2683             r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
2684             r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
2685         } else {
2686             r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
2687             if (isPhoneTypeCdmaLte()) {
2688                 // notify simRecordsLoaded registrants for cdmaLte phone
2689                 r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
2690             }
2691         }
2692     }
2693
2694     private void unregisterForIccRecordEvents() {
2695         IccRecords r = mIccRecords.get();
2696         if (r == null) {
2697             return;
2698         }
2699         r.unregisterForNetworkSelectionModeAutomatic(this);
2700         r.unregisterForRecordsEvents(this);
2701         r.unregisterForRecordsLoaded(this);
2702     }
2703
2704     @Override
2705     public void exitEmergencyCallbackMode() {
2706         if (isPhoneTypeGsm()) {
2707             if (mImsPhone != null) {
2708                 mImsPhone.exitEmergencyCallbackMode();
2709             }
2710         } else {
2711             if (mWakeLock.isHeld()) {
2712                 mWakeLock.release();
2713             }
2714             // Send a message which will invoke handleExitEmergencyCallbackMode
2715             mCi.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
2716         }
2717     }
2718
2719     //CDMA
2720     private void handleEnterEmergencyCallbackMode(Message msg) {
2721         if (DBG) {
2722             Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
2723                     + mIsPhoneInEcmState);
2724         }
2725         // if phone is not in Ecm mode, and it's changed to Ecm mode
2726         if (mIsPhoneInEcmState == false) {
2727             setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
2728             mIsPhoneInEcmState = true;
2729             // notify change
2730             sendEmergencyCallbackModeChange();
2731
2732             // Post this runnable so we will automatically exit
2733             // if no one invokes exitEmergencyCallbackMode() directly.
2734             long delayInMillis = SystemProperties.getLong(
2735                     TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
2736             postDelayed(mExitEcmRunnable, delayInMillis);
2737             // We don't want to go to sleep while in Ecm
2738             mWakeLock.acquire();
2739         }
2740     }
2741
2742     //CDMA
2743     private void handleExitEmergencyCallbackMode(Message msg) {
2744         AsyncResult ar = (AsyncResult)msg.obj;
2745         if (DBG) {
2746             Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState "
2747                     + ar.exception + mIsPhoneInEcmState);
2748         }
2749         // Remove pending exit Ecm runnable, if any
2750         removeCallbacks(mExitEcmRunnable);
2751
2752         if (mEcmExitRespRegistrant != null) {
2753             mEcmExitRespRegistrant.notifyRegistrant(ar);
2754         }
2755         // if exiting ecm success
2756         if (ar.exception == null) {
2757             if (mIsPhoneInEcmState) {
2758                 setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
2759                 mIsPhoneInEcmState = false;
2760             }
2761
2762             // release wakeLock
2763             if (mWakeLock.isHeld()) {
2764                 mWakeLock.release();
2765             }
2766
2767             // send an Intent
2768             sendEmergencyCallbackModeChange();
2769             // Re-initiate data connection
2770             mDcTracker.setInternalDataEnabled(true);
2771             notifyEmergencyCallRegistrants(false);
2772         }
2773     }
2774
2775     //CDMA
2776     public void notifyEmergencyCallRegistrants(boolean started) {
2777         mEmergencyCallToggledRegistrants.notifyResult(started ? 1 : 0);
2778     }
2779
2780     //CDMA
2781     /**
2782      * Handle to cancel or restart Ecm timer in emergency call back mode
2783      * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
2784      * otherwise, restart Ecm timer and notify apps the timer is restarted.
2785      */
2786     public void handleTimerInEmergencyCallbackMode(int action) {
2787         switch(action) {
2788             case CANCEL_ECM_TIMER:
2789                 removeCallbacks(mExitEcmRunnable);
2790                 mEcmTimerResetRegistrants.notifyResult(Boolean.TRUE);
2791                 break;
2792             case RESTART_ECM_TIMER:
2793                 long delayInMillis = SystemProperties.getLong(
2794                         TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
2795                 postDelayed(mExitEcmRunnable, delayInMillis);
2796                 mEcmTimerResetRegistrants.notifyResult(Boolean.FALSE);
2797                 break;
2798             default:
2799                 Rlog.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
2800         }
2801     }
2802
2803     //CDMA
2804     private static final String IS683A_FEATURE_CODE = "*228";
2805     private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
2806     private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
2807     private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
2808
2809     private static final int IS683_CONST_800MHZ_A_BAND = 0;
2810     private static final int IS683_CONST_800MHZ_B_BAND = 1;
2811     private static final int IS683_CONST_1900MHZ_A_BLOCK = 2;
2812     private static final int IS683_CONST_1900MHZ_B_BLOCK = 3;
2813     private static final int IS683_CONST_1900MHZ_C_BLOCK = 4;
2814     private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
2815     private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
2816     private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
2817     private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
2818
2819     // Define the pattern/format for carrier specified OTASP number schema.
2820     // It separates by comma and/or whitespace.
2821     private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
2822
2823     //CDMA
2824     private static boolean isIs683OtaSpDialStr(String dialStr) {
2825         int sysSelCodeInt;
2826         boolean isOtaspDialString = false;
2827         int dialStrLen = dialStr.length();
2828
2829         if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) {
2830             if (dialStr.equals(IS683A_FEATURE_CODE)) {
2831                 isOtaspDialString = true;
2832             }
2833         } else {
2834             sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
2835             switch (sysSelCodeInt) {
2836                 case IS683_CONST_800MHZ_A_BAND:
2837                 case IS683_CONST_800MHZ_B_BAND:
2838                 case IS683_CONST_1900MHZ_A_BLOCK:
2839                 case IS683_CONST_1900MHZ_B_BLOCK:
2840                 case IS683_CONST_1900MHZ_C_BLOCK:
2841                 case IS683_CONST_1900MHZ_D_BLOCK:
2842                 case IS683_CONST_1900MHZ_E_BLOCK:
2843                 case IS683_CONST_1900MHZ_F_BLOCK:
2844                     isOtaspDialString = true;
2845                     break;
2846                 default:
2847                     break;
2848             }
2849         }
2850         return isOtaspDialString;
2851     }
2852
2853     //CDMA
2854     /**
2855      * This function extracts the system selection code from the dial string.
2856      */
2857     private static int extractSelCodeFromOtaSpNum(String dialStr) {
2858         int dialStrLen = dialStr.length();
2859         int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
2860
2861         if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
2862                 0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
2863                 (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
2864                         IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
2865             // Since we checked the condition above, the system selection code
2866             // extracted from dialStr will not cause any exception
2867             sysSelCodeInt = Integer.parseInt (
2868                     dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
2869                             IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
2870         }
2871         if (DBG) Rlog.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
2872         return sysSelCodeInt;
2873     }
2874
2875     //CDMA
2876     /**
2877      * This function checks if the system selection code extracted from
2878      * the dial string "sysSelCodeInt' is the system selection code specified
2879      * in the carrier ota sp number schema "sch".
2880      */
2881     private static boolean checkOtaSpNumBasedOnSysSelCode(int sysSelCodeInt, String sch[]) {
2882         boolean isOtaSpNum = false;
2883         try {
2884             // Get how many number of system selection code ranges
2885             int selRc = Integer.parseInt(sch[1]);
2886             for (int i = 0; i < selRc; i++) {
2887                 if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
2888                     int selMin = Integer.parseInt(sch[i+2]);
2889                     int selMax = Integer.parseInt(sch[i+3]);
2890                     // Check if the selection code extracted from the dial string falls
2891                     // within any of the range pairs specified in the schema.
2892                     if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
2893                         isOtaSpNum = true;
2894                         break;
2895                     }
2896                 }
2897             }
2898         } catch (NumberFormatException ex) {
2899             // If the carrier ota sp number schema is not correct, we still allow dial
2900             // and only log the error:
2901             Rlog.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
2902         }
2903         return isOtaSpNum;
2904     }
2905
2906     //CDMA
2907     /**
2908      * The following function checks if a dial string is a carrier specified
2909      * OTASP number or not by checking against the OTASP number schema stored
2910      * in PROPERTY_OTASP_NUM_SCHEMA.
2911      *
2912      * Currently, there are 2 schemas for carriers to specify the OTASP number:
2913      * 1) Use system selection code:
2914      *    The schema is:
2915      *    SELC,the # of code pairs,min1,max1,min2,max2,...
2916      *    e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
2917      *    selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
2918      *
2919      * 2) Use feature code:
2920      *    The schema is:
2921      *    "FC,length of feature code,feature code".
2922      *     e.g "FC,2,*2" indicates that the length of the feature code is 2,
2923      *     and the code itself is "*2".
2924      */
2925     private boolean isCarrierOtaSpNum(String dialStr) {
2926         boolean isOtaSpNum = false;
2927         int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
2928         if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
2929             return isOtaSpNum;
2930         }
2931         // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
2932         if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
2933             Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
2934             if (DBG) {
2935                 Rlog.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
2936             }
2937
2938             if (m.find()) {
2939                 String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
2940                 // If carrier uses system selection code mechanism
2941                 if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
2942                     if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
2943                         isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
2944                     } else {
2945                         if (DBG) {
2946                             Rlog.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
2947                         }
2948                     }
2949                 } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
2950                     int fcLen =  Integer.parseInt(sch[1]);
2951                     String fc = sch[2];
2952                     if (dialStr.regionMatches(0,fc,0,fcLen)) {
2953                         isOtaSpNum = true;
2954                     } else {
2955                         if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
2956                     }
2957                 } else {
2958                     if (DBG) {
2959                         Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
2960                     }
2961                 }
2962             } else {
2963                 if (DBG) {
2964                     Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
2965                             mCarrierOtaSpNumSchema);
2966                 }
2967             }
2968         } else {
2969             if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
2970         }
2971         return isOtaSpNum;
2972     }
2973
2974     /**
2975      * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
2976      * OTASP dial string.
2977      *
2978      * @param dialStr the number to look up.
2979      * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
2980      */
2981     @Override
2982     public  boolean isOtaSpNumber(String dialStr) {
2983         if (isPhoneTypeGsm()) {
2984             return super.isOtaSpNumber(dialStr);
2985         } else {
2986             boolean isOtaSpNum = false;
2987             String dialableStr = PhoneNumberUtils.extractNetworkPortionAlt(dialStr);
2988             if (dialableStr != null) {
2989                 isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
2990                 if (isOtaSpNum == false) {
2991                     isOtaSpNum = isCarrierOtaSpNum(dialableStr);
2992                 }
2993             }
2994             if (DBG) Rlog.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
2995             return isOtaSpNum;
2996         }
2997     }
2998
2999     @Override
3000     public int getCdmaEriIconIndex() {
3001         if (isPhoneTypeGsm()) {
3002             return super.getCdmaEriIconIndex();
3003         } else {
3004             return getServiceState().getCdmaEriIconIndex();
3005         }
3006     }
3007
3008     /**
3009      * Returns the CDMA ERI icon mode,
3010      * 0 - ON
3011      * 1 - FLASHING
3012      */
3013     @Override
3014     public int getCdmaEriIconMode() {
3015         if (isPhoneTypeGsm()) {
3016             return super.getCdmaEriIconMode();
3017         } else {
3018             return getServiceState().getCdmaEriIconMode();
3019         }
3020     }
3021
3022     /**
3023      * Returns the CDMA ERI text,
3024      */
3025     @Override
3026     public String getCdmaEriText() {
3027         if (isPhoneTypeGsm()) {
3028             return super.getCdmaEriText();
3029         } else {
3030             int roamInd = getServiceState().getCdmaRoamingIndicator();
3031             int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
3032             return mEriManager.getCdmaEriText(roamInd, defRoamInd);
3033         }
3034     }
3035
3036     private void phoneObjectUpdater(int newVoiceRadioTech) {
3037         logd("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech);
3038
3039         // Check for a voice over lte replacement
3040         if (ServiceState.isLte(newVoiceRadioTech)
3041                 || (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) {
3042             CarrierConfigManager configMgr = (CarrierConfigManager)
3043                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
3044             PersistableBundle b = configMgr.getConfigForSubId(getSubId());
3045             if (b != null) {
3046                 int volteReplacementRat =
3047                         b.getInt(CarrierConfigManager.KEY_VOLTE_REPLACEMENT_RAT_INT);
3048                 logd("phoneObjectUpdater: volteReplacementRat=" + volteReplacementRat);
3049                 if (volteReplacementRat != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
3050                     newVoiceRadioTech = volteReplacementRat;
3051                 }
3052             } else {
3053                 loge("phoneObjectUpdater: didn't get volteReplacementRat from carrier config");
3054             }
3055         }
3056
3057         if(mRilVersion == 6 && getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
3058             /*
3059              * On v6 RIL, when LTE_ON_CDMA is TRUE, always create CDMALTEPhone
3060              * irrespective of the voice radio tech reported.
3061              */
3062             if (getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
3063                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Use CDMA Phone" +
3064                         " newVoiceRadioTech=" + newVoiceRadioTech +
3065                         " mActivePhone=" + getPhoneName());
3066                 return;
3067             } else {
3068                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Switch to CDMALTEPhone" +
3069                         " newVoiceRadioTech=" + newVoiceRadioTech +
3070                         " mActivePhone=" + getPhoneName());
3071                 newVoiceRadioTech = ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT;
3072             }
3073         } else {
3074
3075             // If the device is shutting down, then there is no need to switch to the new phone
3076             // which might send unnecessary attach request to the modem.
3077             if (isShuttingDown()) {
3078                 logd("Device is shutting down. No need to switch phone now.");
3079                 return;
3080             }
3081
3082             boolean matchCdma = ServiceState.isCdma(newVoiceRadioTech);
3083             boolean matchGsm = ServiceState.isGsm(newVoiceRadioTech);
3084             if ((matchCdma && getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) ||
3085                     (matchGsm && getPhoneType() == PhoneConstants.PHONE_TYPE_GSM)) {
3086                 // Nothing changed. Keep phone as it is.
3087                 logd("phoneObjectUpdater: No change ignore," +
3088                         " newVoiceRadioTech=" + newVoiceRadioTech +
3089                         " mActivePhone=" + getPhoneName());
3090                 return;
3091             }
3092             if (!matchCdma && !matchGsm) {
3093                 loge("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech +
3094                         " doesn't match either CDMA or GSM - error! No phone change");
3095                 return;
3096             }
3097         }
3098
3099         if (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
3100             // We need some voice phone object to be active always, so never
3101             // delete the phone without anything to replace it with!
3102             logd("phoneObjectUpdater: Unknown rat ignore, "
3103                     + " newVoiceRadioTech=Unknown. mActivePhone=" + getPhoneName());
3104             return;
3105         }
3106
3107         boolean oldPowerState = false; // old power state to off
3108         if (mResetModemOnRadioTechnologyChange) {
3109             if (mCi.getRadioState().isOn()) {
3110                 oldPowerState = true;
3111                 logd("phoneObjectUpdater: Setting Radio Power to Off");
3112                 mCi.setRadioPower(false, null);
3113             }
3114         }
3115
3116         switchVoiceRadioTech(newVoiceRadioTech);
3117
3118         if (mResetModemOnRadioTechnologyChange && oldPowerState) { // restore power state
3119             logd("phoneObjectUpdater: Resetting Radio");
3120             mCi.setRadioPower(oldPowerState, null);
3121         }
3122
3123         // update voice radio tech in icc card proxy
3124         mIccCardProxy.setVoiceRadioTech(newVoiceRadioTech);
3125
3126         // Send an Intent to the PhoneApp that we had a radio technology change
3127         Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
3128         intent.putExtra(PhoneConstants.PHONE_NAME_KEY, getPhoneName());
3129         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
3130         ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
3131     }
3132
3133     private void switchVoiceRadioTech(int newVoiceRadioTech) {
3134
3135         String outgoingPhoneName = getPhoneName();
3136
3137         logd("Switching Voice Phone : " + outgoingPhoneName + " >>> "
3138                 + (ServiceState.isGsm(newVoiceRadioTech) ? "GSM" : "CDMA"));
3139
3140         if (ServiceState.isCdma(newVoiceRadioTech)) {
3141             switchPhoneType(PhoneConstants.PHONE_TYPE_CDMA_LTE);
3142         } else if (ServiceState.isGsm(newVoiceRadioTech)) {
3143             switchPhoneType(PhoneConstants.PHONE_TYPE_GSM);
3144         } else {
3145             loge("deleteAndCreatePhone: newVoiceRadioTech=" + newVoiceRadioTech +
3146                     " is not CDMA or GSM (error) - aborting!");
3147             return;
3148         }
3149     }
3150
3151     @Override
3152     public IccSmsInterfaceManager getIccSmsInterfaceManager(){
3153         return mIccSmsInterfaceManager;
3154     }
3155
3156     @Override
3157     public void updatePhoneObject(int voiceRadioTech) {
3158         logd("updatePhoneObject: radioTechnology=" + voiceRadioTech);
3159         sendMessage(obtainMessage(EVENT_UPDATE_PHONE_OBJECT, voiceRadioTech, 0, null));
3160     }
3161
3162     @Override
3163     public void setImsRegistrationState(boolean registered) {
3164         mSST.setImsRegistrationState(registered);
3165     }
3166
3167     @Override
3168     public boolean getIccRecordsLoaded() {
3169         return mIccCardProxy.getIccRecordsLoaded();
3170     }
3171
3172     @Override
3173     public IccCard getIccCard() {
3174         return mIccCardProxy;
3175     }
3176
3177     @Override
3178     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3179         pw.println("GsmCdmaPhone extends:");
3180         super.dump(fd, pw, args);
3181         pw.println(" mPrecisePhoneType=" + mPrecisePhoneType);
3182         pw.println(" mCT=" + mCT);
3183         pw.println(" mSST=" + mSST);
3184         pw.println(" mPendingMMIs=" + mPendingMMIs);
3185         pw.println(" mIccPhoneBookIntManager=" + mIccPhoneBookIntManager);
3186         if (VDBG) pw.println(" mImei=" + mImei);
3187         if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
3188         if (VDBG) pw.println(" mVmNumber=" + mVmNumber);
3189         pw.println(" mCdmaSSM=" + mCdmaSSM);
3190         pw.println(" mCdmaSubscriptionSource=" + mCdmaSubscriptionSource);
3191         pw.println(" mEriManager=" + mEriManager);
3192         pw.println(" mWakeLock=" + mWakeLock);
3193         pw.println(" mIsPhoneInEcmState=" + mIsPhoneInEcmState);
3194         if (VDBG) pw.println(" mEsn=" + mEsn);
3195         if (VDBG) pw.println(" mMeid=" + mMeid);
3196         pw.println(" mCarrierOtaSpNumSchema=" + mCarrierOtaSpNumSchema);
3197         if (!isPhoneTypeGsm()) {
3198             pw.println(" getCdmaEriIconIndex()=" + getCdmaEriIconIndex());
3199             pw.println(" getCdmaEriIconMode()=" + getCdmaEriIconMode());
3200             pw.println(" getCdmaEriText()=" + getCdmaEriText());
3201             pw.println(" isMinInfoReady()=" + isMinInfoReady());
3202         }
3203         pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled());
3204         pw.flush();
3205         pw.println("++++++++++++++++++++++++++++++++");
3206
3207         try {
3208             mIccCardProxy.dump(fd, pw, args);
3209         } catch (Exception e) {
3210             e.printStackTrace();
3211         }
3212         pw.flush();
3213         pw.println("++++++++++++++++++++++++++++++++");
3214     }
3215
3216     @Override
3217     public boolean setOperatorBrandOverride(String brand) {
3218         if (mUiccController == null) {
3219             return false;
3220         }
3221
3222         UiccCard card = mUiccController.getUiccCard(getPhoneId());
3223         if (card == null) {
3224             return false;
3225         }
3226
3227         boolean status = card.setOperatorBrandOverride(brand);
3228
3229         // Refresh.
3230         if (status) {
3231             IccRecords iccRecords = mIccRecords.get();
3232             if (iccRecords != null) {
3233                 TelephonyManager.from(mContext).setSimOperatorNameForPhone(
3234                         getPhoneId(), iccRecords.getServiceProviderName());
3235             }
3236             if (mSST != null) {
3237                 mSST.pollState();
3238             }
3239         }
3240         return status;
3241     }
3242
3243     /**
3244      * @return operator numeric.
3245      */
3246     private String getOperatorNumeric() {
3247         String operatorNumeric = null;
3248         if (isPhoneTypeGsm()) {
3249             IccRecords r = mIccRecords.get();
3250             if (r != null) {
3251                 operatorNumeric = r.getOperatorNumeric();
3252             }
3253         } else { //isPhoneTypeCdmaLte()
3254             IccRecords curIccRecords = null;
3255             if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_NV) {
3256                 operatorNumeric = SystemProperties.get("ro.cdma.home.operator.numeric");
3257             } else if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_RUIM_SIM) {
3258                 curIccRecords = mSimRecords;
3259                 if (curIccRecords != null) {
3260                     operatorNumeric = curIccRecords.getOperatorNumeric();
3261                 } else {
3262                     curIccRecords = mIccRecords.get();
3263                     if (curIccRecords != null && (curIccRecords instanceof RuimRecords)) {
3264                         RuimRecords csim = (RuimRecords) curIccRecords;
3265                         operatorNumeric = csim.getRUIMOperatorNumeric();
3266                     }
3267                 }
3268             }
3269             if (operatorNumeric == null) {
3270                 loge("getOperatorNumeric: Cannot retrieve operatorNumeric:"
3271                         + " mCdmaSubscriptionSource = " + mCdmaSubscriptionSource +
3272                         " mIccRecords = " + ((curIccRecords != null) ?
3273                         curIccRecords.getRecordsLoaded() : null));
3274             }
3275
3276             logd("getOperatorNumeric: mCdmaSubscriptionSource = " + mCdmaSubscriptionSource
3277                     + " operatorNumeric = " + operatorNumeric);
3278
3279         }
3280         return operatorNumeric;
3281     }
3282
3283     /**
3284      * @return The country ISO for the subscription associated with this phone.
3285      */
3286     public String getCountryIso() {
3287         int subId = getSubId();
3288         SubscriptionInfo subInfo = SubscriptionManager.from(getContext())
3289                 .getActiveSubscriptionInfo(subId);
3290         if (subInfo == null) {
3291             return null;
3292         }
3293         return subInfo.getCountryIso().toUpperCase();
3294     }
3295
3296     public void notifyEcbmTimerReset(Boolean flag) {
3297         mEcmTimerResetRegistrants.notifyResult(flag);
3298     }
3299
3300     /**
3301      * Registration point for Ecm timer reset
3302      *
3303      * @param h handler to notify
3304      * @param what User-defined message code
3305      * @param obj placed in Message.obj
3306      */
3307     @Override
3308     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
3309         mEcmTimerResetRegistrants.addUnique(h, what, obj);
3310     }
3311
3312     @Override
3313     public void unregisterForEcmTimerReset(Handler h) {
3314         mEcmTimerResetRegistrants.remove(h);
3315     }
3316
3317     /**
3318      * Sets the SIM voice message waiting indicator records.
3319      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
3320      * @param countWaiting The number of messages waiting, if known. Use
3321      *                     -1 to indicate that an unknown number of
3322      *                      messages are waiting
3323      */
3324     @Override
3325     public void setVoiceMessageWaiting(int line, int countWaiting) {
3326         if (isPhoneTypeGsm()) {
3327             IccRecords r = mIccRecords.get();
3328             if (r != null) {
3329                 r.setVoiceMessageWaiting(line, countWaiting);
3330             } else {
3331                 logd("SIM Records not found, MWI not updated");
3332             }
3333         } else {
3334             setVoiceMessageCount(countWaiting);
3335         }
3336     }
3337
3338     private void logd(String s) {
3339         Rlog.d(LOG_TAG, "[GsmCdmaPhone] " + s);
3340     }
3341
3342     private void loge(String s) {
3343         Rlog.e(LOG_TAG, "[GsmCdmaPhone] " + s);
3344     }
3345
3346     @Override
3347     public boolean isUtEnabled() {
3348         Phone imsPhone = mImsPhone;
3349         if (imsPhone != null) {
3350             return imsPhone.isUtEnabled();
3351         } else {
3352             logd("isUtEnabled: called for GsmCdma");
3353             return false;
3354         }
3355     }
3356
3357     public String getDtmfToneDelayKey() {
3358         return isPhoneTypeGsm() ?
3359                 CarrierConfigManager.KEY_GSM_DTMF_TONE_DELAY_INT :
3360                 CarrierConfigManager.KEY_CDMA_DTMF_TONE_DELAY_INT;
3361     }
3362
3363     @VisibleForTesting
3364     public PowerManager.WakeLock getWakeLock() {
3365         return mWakeLock;
3366     }
3367
3368 }