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