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