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