CDMAPhone.java revision 3caa1bd1061df4029951e68d0a04d5e30928701f
1/*
2 * Copyright (C) 2006 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.cdma;
18
19import android.app.ActivityManagerNative;
20import android.content.Context;
21import android.content.ContentValues;
22import android.content.Intent;
23import android.content.res.Configuration;
24import android.content.SharedPreferences;
25import android.database.SQLException;
26import android.net.Uri;
27import android.os.AsyncResult;
28import android.os.Handler;
29import android.os.Message;
30import android.os.PowerManager;
31import android.os.PowerManager.WakeLock;
32import android.os.Registrant;
33import android.os.RegistrantList;
34import android.os.RemoteException;
35import android.os.SystemProperties;
36import android.preference.PreferenceManager;
37import android.provider.Telephony;
38import android.telephony.CellLocation;
39import android.telephony.PhoneNumberUtils;
40import android.telephony.ServiceState;
41import android.telephony.SignalStrength;
42import android.text.TextUtils;
43import android.util.Log;
44
45import com.android.internal.telephony.cat.CatService;
46import com.android.internal.telephony.Call;
47import com.android.internal.telephony.CallStateException;
48import com.android.internal.telephony.CommandException;
49import com.android.internal.telephony.CommandsInterface;
50import com.android.internal.telephony.Connection;
51import com.android.internal.telephony.DataConnection;
52import com.android.internal.telephony.MccTable;
53import com.android.internal.telephony.IccCard;
54import com.android.internal.telephony.IccException;
55import com.android.internal.telephony.IccFileHandler;
56import com.android.internal.telephony.IccPhoneBookInterfaceManager;
57import com.android.internal.telephony.IccSmsInterfaceManager;
58import com.android.internal.telephony.MmiCode;
59import com.android.internal.telephony.OperatorInfo;
60import com.android.internal.telephony.Phone;
61import com.android.internal.telephony.PhoneBase;
62import com.android.internal.telephony.PhoneNotifier;
63import com.android.internal.telephony.PhoneProxy;
64import com.android.internal.telephony.PhoneSubInfo;
65import com.android.internal.telephony.ServiceStateTracker;
66import com.android.internal.telephony.TelephonyIntents;
67import com.android.internal.telephony.TelephonyProperties;
68import com.android.internal.telephony.UUSInfo;
69
70import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
71import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
72import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
73
74import java.util.ArrayList;
75import java.util.List;
76
77
78import java.util.regex.Matcher;
79import java.util.regex.Pattern;
80
81/**
82 * {@hide}
83 */
84public class CDMAPhone extends PhoneBase {
85    static final String LOG_TAG = "CDMA";
86    private static final boolean DBG = true;
87
88    // Default Emergency Callback Mode exit timer
89    private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
90
91    static final String VM_COUNT_CDMA = "vm_count_key_cdma";
92    private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
93    private String mVmNumber = null;
94
95    static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
96    static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
97
98    // Instance Variables
99    CdmaCallTracker mCT;
100    CdmaSMSDispatcher mSMS;
101    CdmaServiceStateTracker mSST;
102    RuimRecords mRuimRecords;
103    RuimCard mRuimCard;
104    ArrayList <CdmaMmiCode> mPendingMmis = new ArrayList<CdmaMmiCode>();
105    RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager;
106    RuimSmsInterfaceManager mRuimSmsInterfaceManager;
107    PhoneSubInfo mSubInfo;
108    EriManager mEriManager;
109    WakeLock mWakeLock;
110    CatService mCcatService;
111
112    // mNvLoadedRegistrants are informed after the EVENT_NV_READY
113    private RegistrantList mNvLoadedRegistrants = new RegistrantList();
114
115    // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
116    private RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
117
118    // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
119    private RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
120
121    // mEcmExitRespRegistrant is informed after the phone has been exited
122    //the emergency callback mode
123    //keep track of if phone is in emergency callback mode
124    private boolean mIsPhoneInEcmState;
125    private Registrant mEcmExitRespRegistrant;
126    private String mEsn;
127    private String mMeid;
128    // string to define how the carrier specifies its own ota sp number
129    private String mCarrierOtaSpNumSchema;
130
131    // A runnable which is used to automatically exit from Ecm after a period of time.
132    private Runnable mExitEcmRunnable = new Runnable() {
133        public void run() {
134            exitEmergencyCallbackMode();
135        }
136    };
137
138    Registrant mPostDialHandler;
139
140
141    // Constructors
142    public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
143        this(context,ci,notifier, false);
144    }
145
146    public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
147            boolean unitTestMode) {
148        super(notifier, context, ci, unitTestMode);
149
150        mCM.setPhoneType(Phone.PHONE_TYPE_CDMA);
151        mCT = new CdmaCallTracker(this);
152        mSST = new CdmaServiceStateTracker (this);
153        mSMS = new CdmaSMSDispatcher(this);
154        mIccFileHandler = new RuimFileHandler(this);
155        mRuimRecords = new RuimRecords(this);
156        mDataConnection = new CdmaDataConnectionTracker (this);
157        mRuimCard = new RuimCard(this);
158        mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this);
159        mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this, mSMS);
160        mSubInfo = new PhoneSubInfo(this);
161        mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
162        mCcatService = CatService.getInstance(mCM, mRuimRecords, mContext,
163                mIccFileHandler, mRuimCard);
164
165        mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
166        mRuimRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
167        mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
168        mCM.registerForOn(this, EVENT_RADIO_ON, null);
169        mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
170        mSST.registerForNetworkAttach(this, EVENT_REGISTERED_TO_NETWORK, null);
171        mCM.registerForNVReady(this, EVENT_NV_READY, null);
172        mCM.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
173
174        PowerManager pm
175            = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
176        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG);
177
178        //Change the system setting
179        SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
180                new Integer(Phone.PHONE_TYPE_CDMA).toString());
181
182        // This is needed to handle phone process crashes
183        String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
184        mIsPhoneInEcmState = inEcm.equals("true");
185        if (mIsPhoneInEcmState) {
186            // Send a message which will invoke handleExitEmergencyCallbackMode
187            mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
188        }
189
190        // get the string that specifies the carrier OTA Sp number
191        mCarrierOtaSpNumSchema = SystemProperties.get(
192                TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,"");
193
194        // Sets operator alpha property by retrieving from build-time system property
195        String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
196        setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha);
197
198        // Sets operator numeric property by retrieving from build-time system property
199        String operatorNumeric = SystemProperties.get("ro.cdma.home.operator.numeric");
200        setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operatorNumeric);
201
202        // Sets iso country property by retrieving from build-time system property
203        setIsoCountryProperty(operatorNumeric);
204
205        // Sets current entry in the telephony carrier table
206        updateCurrentCarrierInProvider(operatorNumeric);
207
208        // Notify voicemails.
209        notifier.notifyMessageWaitingChanged(this);
210    }
211
212    public void dispose() {
213        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
214            super.dispose();
215
216            //Unregister from all former registered events
217            mRuimRecords.unregisterForRecordsLoaded(this); //EVENT_RUIM_RECORDS_LOADED
218            mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
219            mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
220            mCM.unregisterForOn(this); //EVENT_RADIO_ON
221            mCM.unregisterForNVReady(this); //EVENT_NV_READY
222            mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
223            mCM.unSetOnSuppServiceNotification(this);
224            removeCallbacks(mExitEcmRunnable);
225
226            mPendingMmis.clear();
227
228            //Force all referenced classes to unregister their former registered events
229            mCT.dispose();
230            mDataConnection.dispose();
231            mSST.dispose();
232            mSMS.dispose();
233            mIccFileHandler.dispose(); // instance of RuimFileHandler
234            mRuimRecords.dispose();
235            mRuimCard.dispose();
236            mRuimPhoneBookInterfaceManager.dispose();
237            mRuimSmsInterfaceManager.dispose();
238            mSubInfo.dispose();
239            mEriManager.dispose();
240            mCcatService.dispose();
241        }
242    }
243
244    public void removeReferences() {
245            this.mRuimPhoneBookInterfaceManager = null;
246            this.mRuimSmsInterfaceManager = null;
247            this.mSMS = null;
248            this.mSubInfo = null;
249            this.mRuimRecords = null;
250            this.mIccFileHandler = null;
251            this.mRuimCard = null;
252            this.mDataConnection = null;
253            this.mCT = null;
254            this.mSST = null;
255            this.mEriManager = null;
256            this.mCcatService = null;
257            this.mExitEcmRunnable = null;
258    }
259
260    protected void finalize() {
261        if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized");
262        if (mWakeLock.isHeld()) {
263            Log.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
264            mWakeLock.release();
265        }
266    }
267
268    public ServiceState getServiceState() {
269        return mSST.ss;
270    }
271
272    public Phone.State getState() {
273        return mCT.state;
274    }
275
276    public String getPhoneName() {
277        return "CDMA";
278    }
279
280    public int getPhoneType() {
281        return Phone.PHONE_TYPE_CDMA;
282    }
283
284    public boolean canTransfer() {
285        Log.e(LOG_TAG, "canTransfer: not possible in CDMA");
286        return false;
287    }
288
289    public CdmaCall getRingingCall() {
290        return mCT.ringingCall;
291    }
292
293    public void setMute(boolean muted) {
294        mCT.setMute(muted);
295    }
296
297    public boolean getMute() {
298        return mCT.getMute();
299    }
300
301    public void conference() throws CallStateException {
302        // three way calls in CDMA will be handled by feature codes
303        Log.e(LOG_TAG, "conference: not possible in CDMA");
304    }
305
306    public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
307        this.mCM.setPreferredVoicePrivacy(enable, onComplete);
308    }
309
310    public void getEnhancedVoicePrivacy(Message onComplete) {
311        this.mCM.getPreferredVoicePrivacy(onComplete);
312    }
313
314    public void clearDisconnected() {
315        mCT.clearDisconnected();
316    }
317
318    public DataActivityState getDataActivityState() {
319        DataActivityState ret = DataActivityState.NONE;
320
321        if (mSST.getCurrentCdmaDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
322
323            switch (mDataConnection.getActivity()) {
324                case DATAIN:
325                    ret = DataActivityState.DATAIN;
326                break;
327
328                case DATAOUT:
329                    ret = DataActivityState.DATAOUT;
330                break;
331
332                case DATAINANDOUT:
333                    ret = DataActivityState.DATAINANDOUT;
334                break;
335
336                case DORMANT:
337                    ret = DataActivityState.DORMANT;
338                break;
339            }
340        }
341        return ret;
342    }
343
344    /*package*/ void
345    notifySignalStrength() {
346        mNotifier.notifySignalStrength(this);
347    }
348
349    public Connection
350    dial (String dialString) throws CallStateException {
351        // Need to make sure dialString gets parsed properly
352        String newDialString = PhoneNumberUtils.stripSeparators(dialString);
353        return mCT.dial(newDialString);
354    }
355
356    public Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException {
357        throw new CallStateException("Sending UUS information NOT supported in CDMA!");
358    }
359
360    public SignalStrength getSignalStrength() {
361        return mSST.mSignalStrength;
362    }
363
364    public boolean
365    getMessageWaitingIndicator() {
366        return (getVoiceMessageCount() > 0);
367    }
368
369    public List<? extends MmiCode>
370    getPendingMmiCodes() {
371        return mPendingMmis;
372    }
373
374    public void registerForSuppServiceNotification(
375            Handler h, int what, Object obj) {
376        Log.e(LOG_TAG, "method registerForSuppServiceNotification is NOT supported in CDMA!");
377    }
378
379    public CdmaCall getBackgroundCall() {
380        return mCT.backgroundCall;
381    }
382
383    public boolean handleInCallMmiCommands(String dialString) {
384        Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!");
385        return false;
386    }
387
388    boolean isInCall() {
389        CdmaCall.State foregroundCallState = getForegroundCall().getState();
390        CdmaCall.State backgroundCallState = getBackgroundCall().getState();
391        CdmaCall.State ringingCallState = getRingingCall().getState();
392
393        return (foregroundCallState.isAlive() || backgroundCallState.isAlive() || ringingCallState
394                .isAlive());
395    }
396
397    public void
398    setNetworkSelectionModeAutomatic(Message response) {
399        Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!");
400    }
401
402    public void unregisterForSuppServiceNotification(Handler h) {
403        Log.e(LOG_TAG, "method unregisterForSuppServiceNotification is NOT supported in CDMA!");
404    }
405
406    public void
407    acceptCall() throws CallStateException {
408        mCT.acceptCall();
409    }
410
411    public void
412    rejectCall() throws CallStateException {
413        mCT.rejectCall();
414    }
415
416    public void
417    switchHoldingAndActive() throws CallStateException {
418        mCT.switchWaitingOrHoldingAndActive();
419    }
420
421    public String getLine1Number() {
422        return mSST.getMdnNumber();
423    }
424
425    public String getCdmaPrlVersion(){
426        return mSST.getPrlVersion();
427    }
428
429    public String getCdmaMin() {
430        return mSST.getCdmaMin();
431    }
432
433    public boolean isMinInfoReady() {
434        return mSST.isMinInfoReady();
435    }
436
437    public void getCallWaiting(Message onComplete) {
438        mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
439    }
440
441    public void
442    setRadioPower(boolean power) {
443        mSST.setRadioPower(power);
444    }
445
446    public String getEsn() {
447        return mEsn;
448    }
449
450    public String getMeid() {
451        return mMeid;
452    }
453
454    //returns MEID or ESN in CDMA
455    public String getDeviceId() {
456        String id = getMeid();
457        if ((id == null) || id.matches("^0*$")) {
458            Log.d(LOG_TAG, "getDeviceId(): MEID is not initialized use ESN");
459            id = getEsn();
460        }
461        return id;
462    }
463
464    public String getDeviceSvn() {
465        Log.d(LOG_TAG, "getDeviceSvn(): return 0");
466        return "0";
467    }
468
469    public String getSubscriberId() {
470        return mSST.getImsi();
471    }
472
473    public boolean canConference() {
474        Log.e(LOG_TAG, "canConference: not possible in CDMA");
475        return false;
476    }
477
478    public CellLocation getCellLocation() {
479        return mSST.cellLoc;
480    }
481
482    public CdmaCall getForegroundCall() {
483        return mCT.foregroundCall;
484    }
485
486    public void
487    selectNetworkManually(OperatorInfo network,
488            Message response) {
489        Log.e(LOG_TAG, "selectNetworkManually: not possible in CDMA");
490    }
491
492    public void setOnPostDialCharacter(Handler h, int what, Object obj) {
493        mPostDialHandler = new Registrant(h, what, obj);
494    }
495
496    public boolean handlePinMmi(String dialString) {
497        CdmaMmiCode mmi = CdmaMmiCode.newFromDialString(dialString, this);
498
499        if (mmi == null) {
500            Log.e(LOG_TAG, "Mmi is NULL!");
501            return false;
502        } else if (mmi.isPukCommand()) {
503            mPendingMmis.add(mmi);
504            mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
505            mmi.processCode();
506            return true;
507        }
508        Log.e(LOG_TAG, "Unrecognized mmi!");
509        return false;
510    }
511
512    /**
513     * Removes the given MMI from the pending list and notifies registrants that
514     * it is complete.
515     *
516     * @param mmi MMI that is done
517     */
518    void onMMIDone(CdmaMmiCode mmi) {
519        /*
520         * Only notify complete if it's on the pending list. Otherwise, it's
521         * already been handled (eg, previously canceled).
522         */
523        if (mPendingMmis.remove(mmi)) {
524            mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
525        }
526    }
527
528    public void setLine1Number(String alphaTag, String number, Message onComplete) {
529        Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
530    }
531
532    public IccCard getIccCard() {
533        return mRuimCard;
534    }
535
536    public String getIccSerialNumber() {
537        return mRuimRecords.iccid;
538    }
539
540    public void setCallWaiting(boolean enable, Message onComplete) {
541        Log.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!");
542    }
543
544    public void updateServiceLocation() {
545        mSST.enableSingleLocationUpdate();
546    }
547
548    public void setDataRoamingEnabled(boolean enable) {
549        mDataConnection.setDataOnRoamingEnabled(enable);
550    }
551
552    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
553        mCM.registerForCdmaOtaProvision(h, what, obj);
554    }
555
556    public void unregisterForCdmaOtaStatusChange(Handler h) {
557        mCM.unregisterForCdmaOtaProvision(h);
558    }
559
560    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
561        mSST.registerForSubscriptionInfoReady(h, what, obj);
562    }
563
564    public void unregisterForSubscriptionInfoReady(Handler h) {
565        mSST.unregisterForSubscriptionInfoReady(h);
566    }
567
568    public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
569        mEcmExitRespRegistrant = new Registrant (h, what, obj);
570    }
571
572    public void unsetOnEcbModeExitResponse(Handler h) {
573        mEcmExitRespRegistrant.clear();
574    }
575
576    public void registerForCallWaiting(Handler h, int what, Object obj) {
577        mCT.registerForCallWaiting(h, what, obj);
578    }
579
580    public void unregisterForCallWaiting(Handler h) {
581        mCT.unregisterForCallWaiting(h);
582    }
583
584    public void
585    getNeighboringCids(Message response) {
586        /*
587         * This is currently not implemented.  At least as of June
588         * 2009, there is no neighbor cell information available for
589         * CDMA because some party is resisting making this
590         * information readily available.  Consequently, calling this
591         * function can have no useful effect.  This situation may
592         * (and hopefully will) change in the future.
593         */
594        if (response != null) {
595            CommandException ce = new CommandException(
596                    CommandException.Error.REQUEST_NOT_SUPPORTED);
597            AsyncResult.forMessage(response).exception = ce;
598            response.sendToTarget();
599        }
600    }
601
602    public DataState getDataConnectionState(String apnType) {
603        DataState ret = DataState.DISCONNECTED;
604
605        if (mSST == null) {
606             // Radio Technology Change is ongoning, dispose() and removeReferences() have
607             // already been called
608
609             ret = DataState.DISCONNECTED;
610        } else if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
611            // If we're out of service, open TCP sockets may still work
612            // but no data will flow
613            ret = DataState.DISCONNECTED;
614        } else if (mDataConnection.isApnTypeEnabled(apnType) == false ||
615                mDataConnection.isApnTypeActive(apnType) == false) {
616            ret = DataState.DISCONNECTED;
617        } else {
618            switch (mDataConnection.getState()) {
619                case FAILED:
620                case IDLE:
621                    ret = DataState.DISCONNECTED;
622                break;
623
624                case CONNECTED:
625                case DISCONNECTING:
626                    if ( mCT.state != Phone.State.IDLE
627                            && !mSST.isConcurrentVoiceAndData()) {
628                        ret = DataState.SUSPENDED;
629                    } else {
630                        ret = DataState.CONNECTED;
631                    }
632                break;
633
634                case INITING:
635                case CONNECTING:
636                case SCANNING:
637                    ret = DataState.CONNECTING;
638                break;
639            }
640        }
641
642        return ret;
643    }
644
645    public void sendUssdResponse(String ussdMessge) {
646        Log.e(LOG_TAG, "sendUssdResponse: not possible in CDMA");
647    }
648
649    public void sendDtmf(char c) {
650        if (!PhoneNumberUtils.is12Key(c)) {
651            Log.e(LOG_TAG,
652                    "sendDtmf called with invalid character '" + c + "'");
653        } else {
654            if (mCT.state ==  Phone.State.OFFHOOK) {
655                mCM.sendDtmf(c, null);
656            }
657        }
658    }
659
660    public void startDtmf(char c) {
661        if (!PhoneNumberUtils.is12Key(c)) {
662            Log.e(LOG_TAG,
663                    "startDtmf called with invalid character '" + c + "'");
664        } else {
665            mCM.startDtmf(c, null);
666        }
667    }
668
669    public void stopDtmf() {
670        mCM.stopDtmf(null);
671    }
672
673    public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
674        boolean check = true;
675        for (int itr = 0;itr < dtmfString.length(); itr++) {
676            if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
677                Log.e(LOG_TAG,
678                        "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'");
679                check = false;
680                break;
681            }
682        }
683        if ((mCT.state ==  Phone.State.OFFHOOK)&&(check)) {
684            mCM.sendBurstDtmf(dtmfString, on, off, onComplete);
685        }
686     }
687
688    public void getAvailableNetworks(Message response) {
689        Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
690    }
691
692    public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
693        Log.e(LOG_TAG, "setOutgoingCallerIdDisplay: not possible in CDMA");
694    }
695
696    public void enableLocationUpdates() {
697        mSST.enableLocationUpdates();
698    }
699
700    public void disableLocationUpdates() {
701        mSST.disableLocationUpdates();
702    }
703
704    public void getDataCallList(Message response) {
705        mCM.getDataCallList(response);
706    }
707
708    public boolean getDataRoamingEnabled() {
709        return mDataConnection.getDataOnRoamingEnabled();
710    }
711
712    public List<DataConnection> getCurrentDataConnectionList () {
713        return mDataConnection.getAllDataConnections();
714    }
715
716    public void setVoiceMailNumber(String alphaTag,
717                                   String voiceMailNumber,
718                                   Message onComplete) {
719        Message resp;
720        mVmNumber = voiceMailNumber;
721        resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
722        mRuimRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
723    }
724
725    public String getVoiceMailNumber() {
726        String number = null;
727        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
728        // TODO: The default value of voicemail number should be read from a system property
729        number = sp.getString(VM_NUMBER_CDMA, "*86");
730        return number;
731    }
732
733    /* Returns Number of Voicemails
734     * @hide
735     */
736    public int getVoiceMessageCount() {
737        int voicemailCount =  mRuimRecords.getVoiceMessageCount();
738        // If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility
739        // that phone was power cycled and would have lost the voicemail count.
740        // So get the count from preferences.
741        if (voicemailCount == 0) {
742            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
743            voicemailCount = sp.getInt(VM_COUNT_CDMA, 0);
744        }
745        return voicemailCount;
746    }
747
748    public String getVoiceMailAlphaTag() {
749        // TODO: Where can we get this value has to be clarified with QC.
750        String ret = "";//TODO: Remove = "", if we know where to get this value.
751
752        //ret = mSIMRecords.getVoiceMailAlphaTag();
753
754        if (ret == null || ret.length() == 0) {
755            return mContext.getText(
756                com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
757        }
758
759        return ret;
760    }
761
762    public boolean getIccRecordsLoaded() {
763        return mRuimRecords.getRecordsLoaded();
764    }
765
766    public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
767        Log.e(LOG_TAG, "getCallForwardingOption: not possible in CDMA");
768    }
769
770    public void setCallForwardingOption(int commandInterfaceCFAction,
771            int commandInterfaceCFReason,
772            String dialingNumber,
773            int timerSeconds,
774            Message onComplete) {
775        Log.e(LOG_TAG, "setCallForwardingOption: not possible in CDMA");
776    }
777
778    public void
779    getOutgoingCallerIdDisplay(Message onComplete) {
780        Log.e(LOG_TAG, "getOutgoingCallerIdDisplay: not possible in CDMA");
781    }
782
783    public boolean
784    getCallForwardingIndicator() {
785        Log.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA");
786        return false;
787    }
788
789    public void explicitCallTransfer() {
790        Log.e(LOG_TAG, "explicitCallTransfer: not possible in CDMA");
791    }
792
793    public String getLine1AlphaTag() {
794        Log.e(LOG_TAG, "getLine1AlphaTag: not possible in CDMA");
795        return null;
796    }
797
798   /**
799     * Notify any interested party of a Phone state change  {@link Phone.State}
800     */
801    /*package*/ void notifyPhoneStateChanged() {
802        mNotifier.notifyPhoneState(this);
803    }
804
805    /**
806     * Notify registrants of a change in the call state. This notifies changes in {@link Call.State}
807     * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged.
808     */
809    /*package*/ void notifyPreciseCallStateChanged() {
810        /* we'd love it if this was package-scoped*/
811        super.notifyPreciseCallStateChangedP();
812    }
813
814     void notifyServiceStateChanged(ServiceState ss) {
815         super.notifyServiceStateChangedP(ss);
816     }
817
818     void notifyLocationChanged() {
819         mNotifier.notifyCellLocation(this);
820     }
821
822    /*package*/ void notifyNewRingingConnection(Connection c) {
823        /* we'd love it if this was package-scoped*/
824        super.notifyNewRingingConnectionP(c);
825    }
826
827    /*package*/ void notifyDisconnect(Connection cn) {
828        mDisconnectRegistrants.notifyResult(cn);
829    }
830
831    void notifyUnknownConnection() {
832        mUnknownConnectionRegistrants.notifyResult(this);
833    }
834
835    void sendEmergencyCallbackModeChange(){
836        //Send an Intent
837        Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
838        intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
839        ActivityManagerNative.broadcastStickyIntent(intent,null);
840        if (DBG) Log.d(LOG_TAG, "sendEmergencyCallbackModeChange");
841    }
842
843    /*package*/ void
844    updateMessageWaitingIndicator(boolean mwi) {
845        // this also calls notifyMessageWaitingIndicator()
846        mRuimRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0);
847    }
848
849    /* This function is overloaded to send number of voicemails instead of sending true/false */
850    /*package*/ void
851    updateMessageWaitingIndicator(int mwi) {
852        mRuimRecords.setVoiceMessageWaiting(1, mwi);
853    }
854
855    @Override
856    public void exitEmergencyCallbackMode() {
857        if (mWakeLock.isHeld()) {
858            mWakeLock.release();
859        }
860        // Send a message which will invoke handleExitEmergencyCallbackMode
861        mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
862    }
863
864    private void handleEnterEmergencyCallbackMode(Message msg) {
865        if (DBG) {
866            Log.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
867                    + mIsPhoneInEcmState);
868        }
869        // if phone is not in Ecm mode, and it's changed to Ecm mode
870        if (mIsPhoneInEcmState == false) {
871            mIsPhoneInEcmState = true;
872            // notify change
873            sendEmergencyCallbackModeChange();
874            setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
875
876            // Post this runnable so we will automatically exit
877            // if no one invokes exitEmergencyCallbackMode() directly.
878            long delayInMillis = SystemProperties.getLong(
879                    TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
880            postDelayed(mExitEcmRunnable, delayInMillis);
881            // We don't want to go to sleep while in Ecm
882            mWakeLock.acquire();
883        }
884    }
885
886    private void handleExitEmergencyCallbackMode(Message msg) {
887        AsyncResult ar = (AsyncResult)msg.obj;
888        if (DBG) {
889            Log.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState "
890                    + ar.exception + mIsPhoneInEcmState);
891        }
892        // Remove pending exit Ecm runnable, if any
893        removeCallbacks(mExitEcmRunnable);
894
895        if (mEcmExitRespRegistrant != null) {
896            mEcmExitRespRegistrant.notifyRegistrant(ar);
897        }
898        // if exiting ecm success
899        if (ar.exception == null) {
900            if (mIsPhoneInEcmState) {
901                mIsPhoneInEcmState = false;
902                setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
903            }
904            // send an Intent
905            sendEmergencyCallbackModeChange();
906            // Re-initiate data connection
907            mDataConnection.setInternalDataEnabled(true);
908        }
909    }
910
911    /**
912     * Handle to cancel or restart Ecm timer in emergency call back mode
913     * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
914     * otherwise, restart Ecm timer and notify apps the timer is restarted.
915     */
916    void handleTimerInEmergencyCallbackMode(int action) {
917        switch(action) {
918        case CANCEL_ECM_TIMER:
919            removeCallbacks(mExitEcmRunnable);
920            mEcmTimerResetRegistrants.notifyResult(Boolean.TRUE);
921            break;
922        case RESTART_ECM_TIMER:
923            long delayInMillis = SystemProperties.getLong(
924                    TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
925            postDelayed(mExitEcmRunnable, delayInMillis);
926            mEcmTimerResetRegistrants.notifyResult(Boolean.FALSE);
927            break;
928        default:
929            Log.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
930        }
931    }
932
933    /**
934     * Registration point for Ecm timer reset
935     * @param h handler to notify
936     * @param what User-defined message code
937     * @param obj placed in Message.obj
938     */
939    public void registerForEcmTimerReset(Handler h, int what, Object obj) {
940        mEcmTimerResetRegistrants.addUnique(h, what, obj);
941    }
942
943    public void unregisterForEcmTimerReset(Handler h) {
944        mEcmTimerResetRegistrants.remove(h);
945    }
946
947    @Override
948    public void handleMessage(Message msg) {
949        AsyncResult ar;
950        Message     onComplete;
951
952        switch(msg.what) {
953            case EVENT_RADIO_AVAILABLE: {
954                mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
955
956                mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
957            }
958            break;
959
960            case EVENT_GET_BASEBAND_VERSION_DONE:{
961                ar = (AsyncResult)msg.obj;
962
963                if (ar.exception != null) {
964                    break;
965                }
966
967                if (DBG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
968                setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result);
969            }
970            break;
971
972            case EVENT_GET_DEVICE_IDENTITY_DONE:{
973                ar = (AsyncResult)msg.obj;
974
975                if (ar.exception != null) {
976                    break;
977                }
978                String[] respId = (String[])ar.result;
979                mEsn  =  respId[2];
980                mMeid =  respId[3];
981            }
982            break;
983
984            case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
985                handleEnterEmergencyCallbackMode(msg);
986            }
987            break;
988
989            case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
990                handleExitEmergencyCallbackMode(msg);
991            }
992            break;
993
994            case EVENT_RUIM_RECORDS_LOADED:{
995                Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
996            }
997            break;
998
999            case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{
1000                Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
1001            }
1002            break;
1003
1004            case EVENT_RADIO_ON:{
1005                Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received");
1006            }
1007            break;
1008
1009            case EVENT_SSN:{
1010                Log.d(LOG_TAG, "Event EVENT_SSN Received");
1011            }
1012            break;
1013
1014            case EVENT_REGISTERED_TO_NETWORK:{
1015                Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received");
1016            }
1017            break;
1018
1019            case EVENT_NV_READY:{
1020                Log.d(LOG_TAG, "Event EVENT_NV_READY Received");
1021                //Inform the Service State Tracker
1022                mEriManager.loadEriFile();
1023                mNvLoadedRegistrants.notifyRegistrants();
1024                if(mEriManager.isEriFileLoaded()) {
1025                    // when the ERI file is loaded
1026                    Log.d(LOG_TAG, "ERI read, notify registrants");
1027                    mEriFileLoadedRegistrants.notifyRegistrants();
1028                }
1029            }
1030            break;
1031
1032            case EVENT_SET_VM_NUMBER_DONE:{
1033                ar = (AsyncResult)msg.obj;
1034                if (IccException.class.isInstance(ar.exception)) {
1035                    storeVoiceMailNumber(mVmNumber);
1036                    ar.exception = null;
1037                }
1038                onComplete = (Message) ar.userObj;
1039                if (onComplete != null) {
1040                    AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1041                    onComplete.sendToTarget();
1042                }
1043            }
1044            break;
1045
1046            default:{
1047                super.handleMessage(msg);
1048            }
1049        }
1050    }
1051
1052    /**
1053     * Retrieves the PhoneSubInfo of the CDMAPhone
1054     */
1055    public PhoneSubInfo getPhoneSubInfo() {
1056        return mSubInfo;
1057    }
1058
1059    /**
1060     * Retrieves the IccSmsInterfaceManager of the CDMAPhone
1061     */
1062    public IccSmsInterfaceManager getIccSmsInterfaceManager() {
1063        return mRuimSmsInterfaceManager;
1064    }
1065
1066    /**
1067     * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone
1068     */
1069    public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager() {
1070        return mRuimPhoneBookInterfaceManager;
1071    }
1072
1073    public void registerForNvLoaded(Handler h, int what, Object obj) {
1074        Registrant r = new Registrant (h, what, obj);
1075        mNvLoadedRegistrants.add(r);
1076    }
1077
1078    public void unregisterForNvLoaded(Handler h) {
1079        mNvLoadedRegistrants.remove(h);
1080    }
1081
1082    public void registerForEriFileLoaded(Handler h, int what, Object obj) {
1083        Registrant r = new Registrant (h, what, obj);
1084        mEriFileLoadedRegistrants.add(r);
1085    }
1086
1087    public void unregisterForEriFileLoaded(Handler h) {
1088        mEriFileLoadedRegistrants.remove(h);
1089    }
1090
1091    // override for allowing access from other classes of this package
1092    /**
1093     * {@inheritDoc}
1094     */
1095    public final void setSystemProperty(String property, String value) {
1096        super.setSystemProperty(property, value);
1097    }
1098
1099    /**
1100     * {@inheritDoc}
1101     */
1102    public IccFileHandler getIccFileHandler() {
1103        return this.mIccFileHandler;
1104    }
1105
1106    /**
1107     * Set the TTY mode of the CDMAPhone
1108     */
1109    public void setTTYMode(int ttyMode, Message onComplete) {
1110        this.mCM.setTTYMode(ttyMode, onComplete);
1111    }
1112
1113    /**
1114     * Queries the TTY mode of the CDMAPhone
1115     */
1116    public void queryTTYMode(Message onComplete) {
1117        this.mCM.queryTTYMode(onComplete);
1118    }
1119
1120    /**
1121     * Activate or deactivate cell broadcast SMS.
1122     *
1123     * @param activate 0 = activate, 1 = deactivate
1124     * @param response Callback message is empty on completion
1125     */
1126    public void activateCellBroadcastSms(int activate, Message response) {
1127        mSMS.activateCellBroadcastSms(activate, response);
1128    }
1129
1130    /**
1131     * Query the current configuration of cdma cell broadcast SMS.
1132     *
1133     * @param response Callback message is empty on completion
1134     */
1135    public void getCellBroadcastSmsConfig(Message response) {
1136        mSMS.getCellBroadcastSmsConfig(response);
1137    }
1138
1139    /**
1140     * Configure cdma cell broadcast SMS.
1141     *
1142     * @param response Callback message is empty on completion
1143     */
1144    public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
1145        mSMS.setCellBroadcastConfig(configValuesArray, response);
1146    }
1147
1148    /**
1149     * Returns true if OTA Service Provisioning needs to be performed.
1150     */
1151    @Override
1152    public boolean needsOtaServiceProvisioning() {
1153        return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
1154    }
1155
1156    private static final String IS683A_FEATURE_CODE = "*228";
1157    private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
1158    private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
1159    private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
1160
1161    private static final int IS683_CONST_800MHZ_A_BAND = 0;
1162    private static final int IS683_CONST_800MHZ_B_BAND = 1;
1163    private static final int IS683_CONST_1900MHZ_A_BLOCK = 2;
1164    private static final int IS683_CONST_1900MHZ_B_BLOCK = 3;
1165    private static final int IS683_CONST_1900MHZ_C_BLOCK = 4;
1166    private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
1167    private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
1168    private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
1169    private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
1170
1171    private boolean isIs683OtaSpDialStr(String dialStr) {
1172        int sysSelCodeInt;
1173        boolean isOtaspDialString = false;
1174        int dialStrLen = dialStr.length();
1175
1176        if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) {
1177            if (dialStr.equals(IS683A_FEATURE_CODE)) {
1178                isOtaspDialString = true;
1179            }
1180        } else {
1181            sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
1182            switch (sysSelCodeInt) {
1183                case IS683_CONST_800MHZ_A_BAND:
1184                case IS683_CONST_800MHZ_B_BAND:
1185                case IS683_CONST_1900MHZ_A_BLOCK:
1186                case IS683_CONST_1900MHZ_B_BLOCK:
1187                case IS683_CONST_1900MHZ_C_BLOCK:
1188                case IS683_CONST_1900MHZ_D_BLOCK:
1189                case IS683_CONST_1900MHZ_E_BLOCK:
1190                case IS683_CONST_1900MHZ_F_BLOCK:
1191                    isOtaspDialString = true;
1192                    break;
1193                default:
1194                    break;
1195            }
1196        }
1197        return isOtaspDialString;
1198    }
1199    /**
1200     * This function extracts the system selection code from the dial string.
1201     */
1202    private int extractSelCodeFromOtaSpNum(String dialStr) {
1203        int dialStrLen = dialStr.length();
1204        int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
1205
1206        if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
1207                                   0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
1208            (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
1209                            IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
1210                // Since we checked the condition above, the system selection code
1211                // extracted from dialStr will not cause any exception
1212                sysSelCodeInt = Integer.parseInt (
1213                                dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
1214                                IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
1215        }
1216        if (DBG) Log.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
1217        return sysSelCodeInt;
1218    }
1219
1220    /**
1221     * This function checks if the system selection code extracted from
1222     * the dial string "sysSelCodeInt' is the system selection code specified
1223     * in the carrier ota sp number schema "sch".
1224     */
1225    private boolean
1226    checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) {
1227        boolean isOtaSpNum = false;
1228        try {
1229            // Get how many number of system selection code ranges
1230            int selRc = Integer.parseInt((String)sch[1]);
1231            for (int i = 0; i < selRc; i++) {
1232                if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
1233                    int selMin = Integer.parseInt((String)sch[i+2]);
1234                    int selMax = Integer.parseInt((String)sch[i+3]);
1235                    // Check if the selection code extracted from the dial string falls
1236                    // within any of the range pairs specified in the schema.
1237                    if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
1238                        isOtaSpNum = true;
1239                        break;
1240                    }
1241                }
1242            }
1243        } catch (NumberFormatException ex) {
1244            // If the carrier ota sp number schema is not correct, we still allow dial
1245            // and only log the error:
1246            Log.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
1247        }
1248        return isOtaSpNum;
1249    }
1250
1251    // Define the pattern/format for carrier specified OTASP number schema.
1252    // It separates by comma and/or whitespace.
1253    private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
1254
1255    /**
1256     * The following function checks if a dial string is a carrier specified
1257     * OTASP number or not by checking against the OTASP number schema stored
1258     * in PROPERTY_OTASP_NUM_SCHEMA.
1259     *
1260     * Currently, there are 2 schemas for carriers to specify the OTASP number:
1261     * 1) Use system selection code:
1262     *    The schema is:
1263     *    SELC,the # of code pairs,min1,max1,min2,max2,...
1264     *    e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
1265     *    selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
1266     *
1267     * 2) Use feature code:
1268     *    The schema is:
1269     *    "FC,length of feature code,feature code".
1270     *     e.g "FC,2,*2" indicates that the length of the feature code is 2,
1271     *     and the code itself is "*2".
1272     */
1273    private boolean isCarrierOtaSpNum(String dialStr) {
1274        boolean isOtaSpNum = false;
1275        int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
1276        if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
1277            return isOtaSpNum;
1278        }
1279        // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
1280        if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
1281            Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
1282            if (DBG) {
1283                Log.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
1284            }
1285
1286            if (m.find()) {
1287                String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
1288                // If carrier uses system selection code mechanism
1289                if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
1290                    if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
1291                        isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
1292                    } else {
1293                        if (DBG) {
1294                            Log.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
1295                        }
1296                    }
1297                } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
1298                    int fcLen =  Integer.parseInt((String)sch[1]);
1299                    String fc = (String)sch[2];
1300                    if (dialStr.regionMatches(0,fc,0,fcLen)) {
1301                        isOtaSpNum = true;
1302                    } else {
1303                        if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
1304                    }
1305                } else {
1306                    if (DBG) {
1307                        Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
1308                    }
1309                }
1310            } else {
1311                if (DBG) {
1312                    Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
1313                          mCarrierOtaSpNumSchema);
1314                }
1315            }
1316        } else {
1317            if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
1318        }
1319        return isOtaSpNum;
1320    }
1321
1322    /**
1323     * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
1324     * OTASP dial string.
1325     *
1326     * @param dialStr the number to look up.
1327     * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
1328     */
1329    @Override
1330    public  boolean isOtaSpNumber(String dialStr){
1331        boolean isOtaSpNum = false;
1332        String dialableStr = PhoneNumberUtils.extractNetworkPortionAlt(dialStr);
1333        if (dialableStr != null) {
1334            isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
1335            if (isOtaSpNum == false) {
1336                isOtaSpNum = isCarrierOtaSpNum(dialableStr);
1337            }
1338        }
1339        if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
1340        return isOtaSpNum;
1341    }
1342
1343    @Override
1344    public int getCdmaEriIconIndex() {
1345        return getServiceState().getCdmaEriIconIndex();
1346    }
1347
1348    /**
1349     * Returns the CDMA ERI icon mode,
1350     * 0 - ON
1351     * 1 - FLASHING
1352     */
1353    @Override
1354    public int getCdmaEriIconMode() {
1355        return getServiceState().getCdmaEriIconMode();
1356    }
1357
1358    /**
1359     * Returns the CDMA ERI text,
1360     */
1361    @Override
1362    public String getCdmaEriText() {
1363        int roamInd = getServiceState().getCdmaRoamingIndicator();
1364        int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
1365        return mEriManager.getCdmaEriText(roamInd, defRoamInd);
1366    }
1367
1368    /**
1369     * Store the voicemail number in preferences
1370     */
1371    private void storeVoiceMailNumber(String number) {
1372        // Update the preference value of voicemail number
1373        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1374        SharedPreferences.Editor editor = sp.edit();
1375        editor.putString(VM_NUMBER_CDMA, number);
1376        editor.apply();
1377    }
1378
1379    /**
1380     * Sets PROPERTY_ICC_OPERATOR_ISO_COUNTRY property
1381     *
1382     */
1383    private void setIsoCountryProperty(String operatorNumeric) {
1384        if (TextUtils.isEmpty(operatorNumeric)) {
1385            setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
1386        } else {
1387            String iso = "";
1388            try {
1389                iso = MccTable.countryCodeForMcc(Integer.parseInt(
1390                        operatorNumeric.substring(0,3)));
1391            } catch (NumberFormatException ex) {
1392                Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
1393            } catch (StringIndexOutOfBoundsException ex) {
1394                Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
1395            }
1396
1397            setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, iso);
1398        }
1399    }
1400
1401    /**
1402     * Sets the "current" field in the telephony provider according to the
1403     * build-time operator numeric property
1404     *
1405     * @return true for success; false otherwise.
1406     */
1407    boolean updateCurrentCarrierInProvider(String operatorNumeric) {
1408        if (!TextUtils.isEmpty(operatorNumeric)) {
1409            try {
1410                Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
1411                ContentValues map = new ContentValues();
1412                map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
1413                getContext().getContentResolver().insert(uri, map);
1414
1415                // Updates MCC MNC device configuration information
1416                MccTable.updateMccMncConfiguration(this, operatorNumeric);
1417
1418                return true;
1419            } catch (SQLException e) {
1420                Log.e(LOG_TAG, "Can't store current operator", e);
1421            }
1422        }
1423        return false;
1424    }
1425}
1426