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