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