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