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