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