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