CDMAPhone.java revision 9bfbfbd40df381817c0c685b177a2a1d666e101d
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.Context;
21import android.content.Intent;
22import android.os.AsyncResult;
23import android.os.Handler;
24import android.os.Looper;
25import android.os.Message;
26import android.os.Registrant;
27import android.os.RegistrantList;
28import android.os.SystemProperties;
29import android.provider.Settings;
30import android.telephony.CellLocation;
31import android.telephony.PhoneNumberUtils;
32import android.telephony.ServiceState;
33import android.telephony.SignalStrength;
34import android.text.TextUtils;
35import android.util.Log;
36
37import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION;
38
39import com.android.internal.telephony.CallStateException;
40import com.android.internal.telephony.CommandsInterface;
41import com.android.internal.telephony.Connection;
42import com.android.internal.telephony.DataConnection;
43import com.android.internal.telephony.IccCard;
44import com.android.internal.telephony.IccFileHandler;
45import com.android.internal.telephony.IccPhoneBookInterfaceManager;
46import com.android.internal.telephony.IccSmsInterfaceManager;
47import com.android.internal.telephony.MmiCode;
48import com.android.internal.telephony.Phone;
49import com.android.internal.telephony.PhoneBase;
50import com.android.internal.telephony.PhoneNotifier;
51import com.android.internal.telephony.PhoneProxy;
52import com.android.internal.telephony.PhoneSubInfo;
53import com.android.internal.telephony.RILConstants;
54import com.android.internal.telephony.TelephonyIntents;
55import com.android.internal.telephony.TelephonyProperties;
56
57import java.util.ArrayList;
58import java.util.List;
59
60/**
61 * {@hide}
62 */
63public class CDMAPhone extends PhoneBase {
64    static final String LOG_TAG = "CDMA";
65    private static final boolean LOCAL_DEBUG = true;
66
67    //***** Instance Variables
68    CdmaCallTracker mCT;
69    CdmaSMSDispatcher mSMS;
70    CdmaServiceStateTracker mSST;
71    CdmaDataConnectionTracker mDataConnection;
72    RuimFileHandler mRuimFileHandler;
73    RuimRecords mRuimRecords;
74    RuimCard mRuimCard;
75    MyHandler h;
76    RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager;
77    RuimSmsInterfaceManager mRuimSmsInterfaceManager;
78    PhoneSubInfo mSubInfo;
79    EriManager mEriManager;
80
81    // mNvLoadedRegistrants are informed after the EVENT_NV_READY
82    private RegistrantList mNvLoadedRegistrants = new RegistrantList();
83
84    // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
85    private RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
86    private String mEsn;
87    private String mMeid;
88
89    Registrant mPostDialHandler;
90
91
92    //***** Constructors
93    public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
94        this(context,ci,notifier, false);
95    }
96
97    public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
98            boolean unitTestMode) {
99        super(notifier, context, unitTestMode);
100
101        h = new MyHandler();
102        mCM = ci;
103
104        mCM.setPhoneType(RILConstants.CDMA_PHONE);
105        mCT = new CdmaCallTracker(this);
106        mSST = new CdmaServiceStateTracker (this);
107        mSMS = new CdmaSMSDispatcher(this);
108        mIccFileHandler = new RuimFileHandler(this);
109        mRuimRecords = new RuimRecords(this);
110        mDataConnection = new CdmaDataConnectionTracker (this);
111        mRuimCard = new RuimCard(this);
112        mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this);
113        mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this);
114        mSubInfo = new PhoneSubInfo(this);
115        mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
116
117        mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null);
118        mRuimRecords.registerForRecordsLoaded(h, EVENT_RUIM_RECORDS_LOADED, null);
119        mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
120        mCM.registerForOn(h, EVENT_RADIO_ON, null);
121        mCM.setOnSuppServiceNotification(h, EVENT_SSN, null);
122        mCM.setOnCallRing(h, EVENT_CALL_RING, null);
123        mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null);
124        mCM.registerForNVReady(h, EVENT_NV_READY, null);
125        mCM.registerForCdmaCallWaiting(h,EVENT_CDMA_CALL_WAITING,null);
126        mCM.setEmergencyCallbackMode(h, EVENT_EMERGENCY_CALLBACK_MODE, null);
127
128
129        //Change the system setting
130        SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
131                new Integer(RILConstants.CDMA_PHONE).toString());
132    }
133
134    public void dispose() {
135        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
136
137            //Unregister from all former registered events
138            mRuimRecords.unregisterForRecordsLoaded(h); //EVENT_RUIM_RECORDS_LOADED
139            mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE
140            mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
141            mCM.unregisterForOn(h); //EVENT_RADIO_ON
142            mCM.unregisterForNVReady(h); //EVENT_NV_READY
143            mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK
144            mCM.unSetOnSuppServiceNotification(h);
145            mCM.unSetOnCallRing(h);
146            mCM.unregisterForCdmaCallWaiting(h);
147
148            //Force all referenced classes to unregister their former registered events
149            mCT.dispose();
150            mDataConnection.dispose();
151            mSST.dispose();
152            mSMS.dispose();
153            mIccFileHandler.dispose(); // instance of RuimFileHandler
154            mRuimRecords.dispose();
155            mRuimCard.dispose();
156            mRuimPhoneBookInterfaceManager.dispose();
157            mRuimSmsInterfaceManager.dispose();
158            mSubInfo.dispose();
159            mEriManager.dispose();
160        }
161    }
162
163    public void removeReferences() {
164            this.mRuimPhoneBookInterfaceManager = null;
165            this.mRuimSmsInterfaceManager = null;
166            this.mSMS = null;
167            this.mSubInfo = null;
168            this.mRuimRecords = null;
169            this.mIccFileHandler = null;
170            this.mRuimCard = null;
171            this.mDataConnection = null;
172            this.mCT = null;
173            this.mSST = null;
174            this.mEriManager = null;
175    }
176
177    protected void finalize() {
178        if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized");
179    }
180
181
182    //***** Overridden from Phone
183    public ServiceState getServiceState() {
184        return mSST.ss;
185    }
186
187    public Phone.State
188    getState() {
189        return mCT.state;
190    }
191
192    public String
193    getPhoneName() {
194        return "CDMA";
195    }
196
197    public boolean canTransfer() {
198        Log.e(LOG_TAG, "canTransfer: not possible in CDMA");
199        return false;
200    }
201
202    public CdmaCall
203    getRingingCall() {
204        return mCT.ringingCall;
205    }
206
207    public void setMute(boolean muted) {
208        mCT.setMute(muted);
209    }
210
211    public boolean getMute() {
212        return mCT.getMute();
213    }
214
215    public void conference() throws CallStateException {
216        // three way calls in CDMA will be handled by feature codes
217        Log.e(LOG_TAG, "conference: not possible in CDMA");
218    }
219
220    public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
221        this.mCM.setPreferredVoicePrivacy(enable, onComplete);
222    }
223
224    public void getEnhancedVoicePrivacy(Message onComplete) {
225        this.mCM.getPreferredVoicePrivacy(onComplete);
226    }
227
228    public void clearDisconnected() {
229        mCT.clearDisconnected();
230    }
231
232    public DataActivityState getDataActivityState() {
233        DataActivityState ret = DataActivityState.NONE;
234
235        if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.RADIO_TECHNOLOGY_UNKNOWN) {
236
237            switch (mDataConnection.getActivity()) {
238                case DATAIN:
239                    ret = DataActivityState.DATAIN;
240                break;
241
242                case DATAOUT:
243                    ret = DataActivityState.DATAOUT;
244                break;
245
246                case DATAINANDOUT:
247                    ret = DataActivityState.DATAINANDOUT;
248                break;
249
250                case DORMANT:
251                    ret = DataActivityState.DORMANT;
252                break;
253            }
254        }
255        return ret;
256    }
257
258    /*package*/ void
259    notifySignalStrength() {
260        mNotifier.notifySignalStrength(this);
261    }
262
263    public Connection
264    dial (String dialString) throws CallStateException {
265        // Need to make sure dialString gets parsed properly
266        String newDialString = PhoneNumberUtils.stripSeparators(dialString);
267
268        if (!mCT.foregroundCall.isIdle()) {
269            FeatureCode fc = FeatureCode.newFromDialString(newDialString, this);
270            if (fc != null) {
271                //mMmiRegistrants.notifyRegistrants(new AsyncResult(null, fc, null));
272                fc.processCode();
273            } else {
274                FeatureCode digits = new FeatureCode(this);
275                // use dial number as poundString
276                digits.poundString = newDialString;
277                digits.processCode();
278            }
279            return null;
280        } else {
281            return mCT.dial(newDialString);
282        }
283    }
284
285    public SignalStrength getSignalStrength() {
286        return mSST.mSignalStrength;
287    }
288
289    public boolean
290    getMessageWaitingIndicator() {
291        return mRuimRecords.getVoiceMessageWaiting();
292    }
293
294    public List<? extends MmiCode>
295    getPendingMmiCodes() {
296        Log.e(LOG_TAG, "method getPendingMmiCodes is NOT supported in CDMA!");
297        return null;
298    }
299
300    public void registerForSuppServiceNotification(
301            Handler h, int what, Object obj) {
302        Log.e(LOG_TAG, "method registerForSuppServiceNotification is NOT supported in CDMA!");
303    }
304
305    public CdmaCall getBackgroundCall() {
306        return mCT.backgroundCall;
307    }
308
309    public String getGateway(String apnType) {
310        return mDataConnection.getGateway();
311    }
312
313    public boolean handleInCallMmiCommands(String dialString) {
314        Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!");
315        return false;
316    }
317
318    public int enableApnType(String type) {
319        // This request is mainly used to enable MMS APN
320        // In CDMA there is no need to enable/disable a different APN for MMS
321        Log.d(LOG_TAG, "Request to enableApnType("+type+")");
322        if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
323            return Phone.APN_ALREADY_ACTIVE;
324        } else {
325            return Phone.APN_REQUEST_FAILED;
326        }
327    }
328
329    public int disableApnType(String type) {
330        // This request is mainly used to disable MMS APN
331        // In CDMA there is no need to enable/disable a different APN for MMS
332        Log.d(LOG_TAG, "Request to disableApnType("+type+")");
333        if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
334            return Phone.APN_REQUEST_STARTED;
335        } else {
336            return Phone.APN_REQUEST_FAILED;
337        }
338    }
339
340    public String getActiveApn() {
341        Log.d(LOG_TAG, "Request to getActiveApn()");
342        return null;
343    }
344
345    public void
346    setNetworkSelectionModeAutomatic(Message response) {
347        Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!");
348    }
349
350    public void unregisterForSuppServiceNotification(Handler h) {
351        Log.e(LOG_TAG, "method unregisterForSuppServiceNotification is NOT supported in CDMA!");
352    }
353
354    public void
355    acceptCall() throws CallStateException {
356        mCT.acceptCall();
357    }
358
359    public void
360    rejectCall() throws CallStateException {
361        mCT.rejectCall();
362    }
363
364    public void
365    switchHoldingAndActive() throws CallStateException {
366        mCT.switchWaitingOrHoldingAndActive();
367    }
368
369    public String getLine1Number() {
370        return mRuimRecords.getMdnNumber();
371    }
372
373    public String getMin() {
374        return mRuimRecords.getMin();
375    }
376
377    public void getCallWaiting(Message onComplete) {
378        mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
379    }
380
381    public void
382    setRadioPower(boolean power) {
383        mSST.setRadioPower(power);
384    }
385
386    public String getEsn() {
387        return mEsn;
388    }
389
390    public String getMeid() {
391        return mMeid;
392    }
393
394    //returns MEID in CDMA
395    public String getDeviceId() {
396        return getMeid();
397    }
398
399    public String getDeviceSvn() {
400        Log.d(LOG_TAG, "getDeviceSvn(): return 0");
401        return "0";
402    }
403
404    public String getSubscriberId() {
405        Log.e(LOG_TAG, "method getSubscriberId for IMSI is NOT supported in CDMA!");
406        return null;
407    }
408
409    public boolean canConference() {
410        Log.e(LOG_TAG, "canConference: not possible in CDMA");
411        return false;
412    }
413
414    public String getInterfaceName(String apnType) {
415        return mDataConnection.getInterfaceName();
416    }
417
418    public CellLocation getCellLocation() {
419        return mSST.cellLoc;
420    }
421
422    public boolean disableDataConnectivity() {
423        return mDataConnection.setDataEnabled(false);
424    }
425
426    public CdmaCall getForegroundCall() {
427        return mCT.foregroundCall;
428    }
429
430    public void
431    selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network,
432            Message response) {
433        Log.e(LOG_TAG, "selectNetworkManually: not possible in CDMA");
434    }
435
436    public void setOnPostDialCharacter(Handler h, int what, Object obj) {
437        Log.e(LOG_TAG, "setOnPostDialCharacter: not possible in CDMA");
438    }
439
440    public boolean handlePinMmi(String dialString) {
441        Log.e(LOG_TAG, "method handlePinMmi is NOT supported in CDMA!");
442        return false;
443    }
444
445    public boolean isDataConnectivityPossible() {
446        boolean noData = mDataConnection.getDataEnabled() &&
447                getDataConnectionState() == DataState.DISCONNECTED;
448        return !noData && getIccCard().getState() == IccCard.State.READY &&
449                getServiceState().getState() == ServiceState.STATE_IN_SERVICE &&
450                (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());
451    }
452
453    public void setLine1Number(String alphaTag, String number, Message onComplete) {
454        Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
455    }
456
457    public String[] getDnsServers(String apnType) {
458        return mDataConnection.getDnsServers();
459    }
460
461    public IccCard getIccCard() {
462        return mRuimCard;
463    }
464
465    public String getIccSerialNumber() {
466        return mRuimRecords.iccid;
467    }
468
469    public void setCallWaiting(boolean enable, Message onComplete) {
470        Log.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!");
471    }
472
473    public void updateServiceLocation(Message response) {
474        mSST.getLacAndCid(response);
475    }
476
477    public void setDataRoamingEnabled(boolean enable) {
478        mDataConnection.setDataOnRoamingEnabled(enable);
479    }
480
481    public String getIpAddress(String apnType) {
482        return mDataConnection.getIpAddress();
483    }
484
485    public void
486    getNeighboringCids(Message response) {
487        // WINK:TODO: implement after Cupcake merge
488        mCM.getNeighboringCids(response); // workaround.
489    }
490
491    public DataState getDataConnectionState() {
492        DataState ret = DataState.DISCONNECTED;
493
494        if ((SystemProperties.get("adb.connected", "").length() > 0)
495                && (SystemProperties.get("android.net.use-adb-networking", "")
496                        .length() > 0)) {
497            // We're connected to an ADB host and we have USB networking
498            // turned on. No matter what the radio state is,
499            // we report data connected
500
501            ret = DataState.CONNECTED;
502        } else if (mSST == null) {
503             // Radio Technology Change is ongoning, dispose() and removeReferences() have
504             // already been called
505
506             ret = DataState.DISCONNECTED;
507        } else if (mSST.getCurrentCdmaDataConnectionState()
508                == ServiceState.RADIO_TECHNOLOGY_UNKNOWN) {
509            // If we're out of service, open TCP sockets may still work
510            // but no data will flow
511            ret = DataState.DISCONNECTED;
512        } else {
513            switch (mDataConnection.getState()) {
514                case FAILED:
515                case IDLE:
516                    ret = DataState.DISCONNECTED;
517                break;
518
519                case CONNECTED:
520                case DISCONNECTING:
521                    if ( mCT.state != Phone.State.IDLE
522                            && !mSST.isConcurrentVoiceAndData()) {
523                        ret = DataState.SUSPENDED;
524                    } else {
525                        ret = DataState.CONNECTED;
526                    }
527                break;
528
529                case INITING:
530                case CONNECTING:
531                case SCANNING:
532                    ret = DataState.CONNECTING;
533                break;
534            }
535        }
536
537        return ret;
538    }
539
540    public void sendUssdResponse(String ussdMessge) {
541        Log.e(LOG_TAG, "sendUssdResponse: not possible in CDMA");
542    }
543
544    public void sendDtmf(char c) {
545        if (!PhoneNumberUtils.is12Key(c)) {
546            Log.e(LOG_TAG,
547                    "sendDtmf called with invalid character '" + c + "'");
548        } else {
549            if (mCT.state ==  Phone.State.OFFHOOK) {
550                mCM.sendDtmf(c, null);
551            }
552        }
553    }
554
555    public void startDtmf(char c) {
556        if (!PhoneNumberUtils.is12Key(c)) {
557            Log.e(LOG_TAG,
558                    "startDtmf called with invalid character '" + c + "'");
559        } else {
560            mCM.startDtmf(c, null);
561        }
562    }
563
564    public void stopDtmf() {
565        mCM.stopDtmf(null);
566    }
567
568    public void sendBurstDtmf(String dtmfString) {
569        boolean check = true;
570        for (int itr = 0;itr < dtmfString.length(); itr++) {
571            if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
572                Log.e(LOG_TAG,
573                        "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'");
574                check = false;
575                break;
576            }
577        }
578        if ((mCT.state ==  Phone.State.OFFHOOK)&&(check)) {
579            mCM.sendBurstDtmf(dtmfString, null);
580        }
581     }
582
583    public void getAvailableNetworks(Message response) {
584        Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
585    }
586
587    public String[] getActiveApnTypes() {
588        String[] result;
589        Log.d(LOG_TAG, "Request to getActiveApn()");
590        result = new String[1];
591        result[0] = Phone.APN_TYPE_DEFAULT;
592        return result;
593    }
594
595    public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
596        Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
597    }
598
599    public void enableLocationUpdates() {
600        mSST.enableLocationUpdates();
601    }
602
603    /**
604     * @deprecated
605     */
606    public void getPdpContextList(Message response) {
607        getDataCallList(response);
608    }
609
610    public void getDataCallList(Message response) {
611        mCM.getDataCallList(response);
612    }
613
614    public boolean getDataRoamingEnabled() {
615        return mDataConnection.getDataOnRoamingEnabled();
616    }
617
618    public List<DataConnection> getCurrentDataConnectionList () {
619        return mDataConnection.getAllDataConnections();
620    }
621
622    public void setVoiceMailNumber(String alphaTag,
623                                   String voiceMailNumber,
624                                   Message onComplete) {
625        //mSIMRecords.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete);
626        //TODO: Where do we have to store this value has to be clarified with QC
627    }
628
629    public String getVoiceMailNumber() {
630        //TODO: Where can we get this value has to be clarified with QC
631        //return mSIMRecords.getVoiceMailNumber();
632//      throw new RuntimeException();
633        return "12345";
634    }
635
636    public String getVoiceMailAlphaTag() {
637        // TODO: Where can we get this value has to be clarified with QC.
638        String ret = "";//TODO: Remove = "", if we know where to get this value.
639
640        //ret = mSIMRecords.getVoiceMailAlphaTag();
641
642        if (ret == null || ret.length() == 0) {
643            return mContext.getText(
644                com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
645        }
646
647        return ret;
648    }
649
650    public boolean enableDataConnectivity() {
651        return mDataConnection.setDataEnabled(true);
652    }
653
654    public void disableLocationUpdates() {
655        mSST.disableLocationUpdates();
656    }
657
658    public boolean getIccRecordsLoaded() {
659        return mRuimRecords.getRecordsLoaded();
660    }
661
662    public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
663        Log.e(LOG_TAG, "getCallForwardingOption: not possible in CDMA");
664    }
665
666    public void setCallForwardingOption(int commandInterfaceCFAction,
667            int commandInterfaceCFReason,
668            String dialingNumber,
669            int timerSeconds,
670            Message onComplete) {
671        Log.e(LOG_TAG, "setCallForwardingOption: not possible in CDMA");
672    }
673
674    public void
675    getOutgoingCallerIdDisplay(Message onComplete) {
676        Log.e(LOG_TAG, "getOutgoingCallerIdDisplay: not possible in CDMA");
677    }
678
679    public boolean
680    getCallForwardingIndicator() {
681        Log.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA");
682        return false;
683    }
684
685    public void explicitCallTransfer() {
686        Log.e(LOG_TAG, "explicitCallTransfer: not possible in CDMA");
687    }
688
689    public String getLine1AlphaTag() {
690        Log.e(LOG_TAG, "getLine1AlphaTag: not possible in CDMA");
691        return null;
692    }
693
694    /**
695     * Notify any interested party of a Phone state change.
696     */
697    /*package*/ void notifyPhoneStateChanged() {
698        mNotifier.notifyPhoneState(this);
699    }
700
701    /**
702     * Notifies registrants (ie, activities in the Phone app) about
703     * changes to call state (including Phone and Connection changes).
704     */
705    /*package*/ void notifyCallStateChanged() {
706        /* we'd love it if this was package-scoped*/
707        super.notifyCallStateChangedP();
708    }
709
710     void notifyServiceStateChanged(ServiceState ss) {
711         super.notifyServiceStateChangedP(ss);
712     }
713
714     void notifyLocationChanged() {
715         mNotifier.notifyCellLocation(this);
716     }
717
718    /*package*/ void notifyNewRingingConnection(Connection c) {
719        /* we'd love it if this was package-scoped*/
720        super.notifyNewRingingConnectionP(c);
721    }
722
723    /**
724     * Notifiy registrants of a RING event.
725     */
726    void notifyIncomingRing() {
727        AsyncResult ar = new AsyncResult(null, this, null);
728        mIncomingRingRegistrants.notifyRegistrants(ar);
729    }
730
731    /*package*/ void notifyDisconnect(Connection cn) {
732        mDisconnectRegistrants.notifyResult(cn);
733    }
734
735    void notifyUnknownConnection() {
736        mUnknownConnectionRegistrants.notifyResult(this);
737    }
738
739    /*package*/ void
740    updateMessageWaitingIndicator(boolean mwi) {
741        // this also calls notifyMessageWaitingIndicator()
742        mRuimRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0);
743    }
744
745    public void
746    notifyMessageWaitingIndicator() {
747        mNotifier.notifyMessageWaitingChanged(this);
748    }
749
750    /**
751     * Removes the given FC from the pending list and notifies
752     * registrants that it is complete.
753     * @param fc FC that is done
754     */
755    /*package*/ void onFeatureCodeDone(FeatureCode fc) {
756        /* Only notify complete if it's on the pending list.
757         * Otherwise, it's already been handled (eg, previously canceled).
758         * The exception is cancellation of an incoming USSD-REQUEST, which is
759         * not on the list.
760         */
761         mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, fc, null));
762    }
763
764    //***** Inner Classes
765    class MyHandler extends Handler {
766        MyHandler() {
767        }
768
769        MyHandler(Looper l) {
770            super(l);
771        }
772
773        public void handleMessage(Message msg) {
774            AsyncResult ar;
775            Message     onComplete;
776
777            switch(msg.what) {
778                case EVENT_RADIO_AVAILABLE: {
779                    mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
780
781                    mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
782                }
783                break;
784
785                case EVENT_GET_BASEBAND_VERSION_DONE:{
786                    ar = (AsyncResult)msg.obj;
787
788                    if (ar.exception != null) {
789                        break;
790                    }
791
792                    if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
793                    setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result);
794                }
795                break;
796
797                case EVENT_GET_DEVICE_IDENTITY_DONE:{
798                    ar = (AsyncResult)msg.obj;
799
800                    if (ar.exception != null) {
801                        break;
802                    }
803                    String[] respId = (String[])ar.result;
804                    mEsn  =  respId[2];
805                    mMeid =  respId[3];
806                }
807                break;
808
809                case EVENT_EMERGENCY_CALLBACK_MODE: {
810                    Log.d(LOG_TAG, "Event EVENT_EMERGENCY_CALLBACK_MODE Received");
811                    Intent intent =
812                        new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_ENTERED);
813                    ActivityManagerNative.broadcastStickyIntent(intent, null);
814                }
815                case EVENT_RUIM_RECORDS_LOADED:{
816                    Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
817                }
818                break;
819
820                case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{
821                    Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
822                }
823                break;
824
825                case EVENT_RADIO_ON:{
826                    Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received");
827                }
828                break;
829
830                case EVENT_SSN:{
831                    Log.d(LOG_TAG, "Event EVENT_SSN Received");
832                }
833                break;
834
835                case EVENT_CALL_RING:{
836                    Log.d(LOG_TAG, "Event EVENT_CALL_RING Received");
837                }
838                break;
839
840                case EVENT_REGISTERED_TO_NETWORK:{
841                    Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received");
842                }
843                break;
844
845                case EVENT_NV_READY:{
846                    Log.d(LOG_TAG, "Event EVENT_NV_READY Received");
847                    //Inform the Service State Tracker
848                    mEriManager.loadEriFile();
849                    mNvLoadedRegistrants.notifyRegistrants();
850                    if(mEriManager.isEriFileLoaded()) {
851                        // when the ERI file is loaded
852                        Log.d(LOG_TAG, "ERI read, notify registrants");
853                        mEriFileLoadedRegistrants.notifyRegistrants();
854                    }
855                }
856                break;
857
858                case EVENT_CDMA_CALL_WAITING:{
859                    Log.d(LOG_TAG, "Event EVENT_CDMA_CALL_WAITING Received");
860                }
861                break;
862
863                default:{
864                    throw new RuntimeException("unexpected event not handled");
865                }
866            }
867        }
868    }
869
870     /**
871      * Retrieves the PhoneSubInfo of the CDMAPhone
872      */
873     public PhoneSubInfo getPhoneSubInfo(){
874        return mSubInfo;
875     }
876
877     /**
878      * Retrieves the IccSmsInterfaceManager of the CDMAPhone
879      */
880     public IccSmsInterfaceManager getIccSmsInterfaceManager(){
881         return mRuimSmsInterfaceManager;
882     }
883
884     /**
885      * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone
886      */
887     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
888         return mRuimPhoneBookInterfaceManager;
889     }
890
891    public void registerForNvLoaded(Handler h, int what, Object obj) {
892        Registrant r = new Registrant (h, what, obj);
893        mNvLoadedRegistrants.add(r);
894    }
895
896    public void unregisterForNvLoaded(Handler h) {
897        mNvLoadedRegistrants.remove(h);
898    }
899
900    public void registerForEriFileLoaded(Handler h, int what, Object obj) {
901        Registrant r = new Registrant (h, what, obj);
902        mEriFileLoadedRegistrants.add(r);
903    }
904
905    public void unregisterForEriFileLoaded(Handler h) {
906        mEriFileLoadedRegistrants.remove(h);
907    }
908
909     // override for allowing access from other classes of this package
910     /**
911      * {@inheritDoc}
912      */
913     public final void setSystemProperty(String property, String value) {
914         super.setSystemProperty(property, value);
915     }
916
917     /**
918      * {@inheritDoc}
919      */
920     public Handler getHandler(){
921         return h;
922     }
923
924     /**
925      * {@inheritDoc}
926      */
927     public IccFileHandler getIccFileHandler(){
928         return this.mIccFileHandler;
929     }
930
931     /**
932      * Set the TTY mode of the CDMAPhone
933      */
934     public void setTTYMode(int ttyMode, Message onComplete) {
935         this.mCM.setTTYMode(ttyMode, onComplete);
936}
937
938     /**
939      * Queries the TTY mode of the CDMAPhone
940      */
941     public void queryTTYMode(Message onComplete) {
942         this.mCM.queryTTYMode(onComplete);
943     }
944
945     /**
946      * Sends Exit EmergencyCallbackMode Exit request on CDMAPhone
947      */
948     public void exitEmergencyCallbackMode(Message onComplete) {
949         this.mCM.exitEmergencyCallbackMode(onComplete);
950     }
951
952     /**
953      * Activate or deactivate cell broadcast SMS.
954      *
955      * @param activate
956      *            0 = activate, 1 = deactivate
957      * @param response
958      *            Callback message is empty on completion
959      */
960     public void activateCellBroadcastSms(int activate, Message response) {
961         mSMS.activateCellBroadcastSms(activate, response);
962     }
963
964     /**
965      * Query the current configuration of cdma cell broadcast SMS.
966      *
967      * @param response
968      *            Callback message is empty on completion
969      */
970     public void getCellBroadcastSmsConfig(Message response){
971         mSMS.getCellBroadcastSmsConfig(response);
972     }
973
974     /**
975      * Configure cdma cell broadcast SMS.
976      *
977      * @param response
978      *            Callback message is empty on completion
979      */
980     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){
981         mSMS.setCellBroadcastConfig(configValuesArray, response);
982     }
983
984     public void registerForOtaSessionStatus(Handler h, int what, Object obj){
985         mCM.registerForOtaSessionStatus(h, what, obj);
986     }
987
988     public void unregisterForOtaSessionStatus(Handler h){
989         mCM.unregisterForOtaSessionStatus(h);
990     }
991
992/**
993 * TODO(Teleca): The code in getCdmaEriIconIndex, getCdmaEriIconMode & getCdmaEriText share a
994 * lot of logic, refactor.
995 */
996    /**
997     * Returns the CDMA ERI icon index to display,
998     * it returns 1, EriInfo.ROAMING_INDICATOR_OFF, in case there is no icon to display
999     */
1000    @Override
1001    public int getCdmaEriIconIndex() {
1002        int roamInd = getServiceState().getCdmaRoamingIndicator();
1003        int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
1004        int ret = -1;
1005
1006        switch (roamInd) {
1007            // Handling the standard roaming indicator (non-ERI)
1008            case EriInfo.ROAMING_INDICATOR_ON:
1009            case EriInfo.ROAMING_INDICATOR_OFF:
1010            case EriInfo.ROAMING_INDICATOR_FLASH:
1011                Log.d(LOG_TAG, "Using Standard Roaming Indicator (non-ERI): " + roamInd);
1012                ret = roamInd;
1013            break;
1014
1015            // Handling the Enhanced Roaming Indicator (roamInd > 2)
1016            default:
1017                if (!mEriManager.isEriFileLoaded()) {
1018                    /**
1019                     * TODO(Teleca): What is going on here? Conditionals on the variable being
1020                     * switched? Seems unreasonably confusing... Especially since the above comment
1021                     * indicates this should always be true... If we used explicit returns, the
1022                     * switch could be used to filter specific cases for early bail, and the rest
1023                     * could then be dealt with outside the switch...
1024                     */
1025
1026                    if(defRoamInd > 2) {
1027                        Log.d(LOG_TAG, "ERI File not loaded, using: "
1028                                + EriInfo.ROAMING_INDICATOR_FLASH);
1029                        ret = EriInfo.ROAMING_INDICATOR_FLASH;
1030                    } else {
1031                        Log.d(LOG_TAG, "ERI File not loaded, using: " + defRoamInd);
1032                        ret = defRoamInd;
1033                    }
1034                } else if (mEriManager.getEriInfo(roamInd) == null) {
1035                    if(mEriManager.getEriInfo(defRoamInd) == null) {
1036/**
1037 * TODO(Teleca): Why the redundant code? Especially since it results in this very strange looking
1038 * almost-identical conditional... How about calling each version of mEriManager.getEriInfo just
1039 * once, and conditionalizing on the results..
1040 */
1041                        Log.e(LOG_TAG, "Error: ERI entry: " + roamInd
1042                                + " not present, defRoamInd: " + defRoamInd
1043                                + " not defined in ERI file");
1044                        ret = EriInfo.ROAMING_INDICATOR_ON;
1045                    } else {
1046                        int iconIndex = mEriManager.getEriInfo(defRoamInd).mIconIndex;
1047                        Log.d(LOG_TAG, "ERI entry " + roamInd + " not present, using icon: "
1048                                + iconIndex);
1049                        ret = iconIndex;
1050                    }
1051                } else {
1052                    int iconIndex = mEriManager.getEriInfo(roamInd).mIconIndex;
1053                    Log.d(LOG_TAG, "Using ERI icon: " + iconIndex);
1054                    ret = iconIndex;
1055                }
1056            break;
1057        }
1058        return ret;
1059    }
1060
1061    /**
1062     * Returns the CDMA ERI icon mode,
1063     * 0 - ON
1064     * 1 - FLASHING
1065     */
1066    @Override
1067    public int getCdmaEriIconMode() {
1068        int roamInd = getServiceState().getCdmaRoamingIndicator();
1069        int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
1070        int ret = -1;
1071
1072        switch (roamInd) {
1073            // Handling the standard roaming indicator (non-ERI)
1074            case EriInfo.ROAMING_INDICATOR_ON:
1075            case EriInfo.ROAMING_INDICATOR_OFF:
1076                Log.d(LOG_TAG, "Using Standard Roaming Indicator (non-ERI): normal");
1077                ret = EriInfo.ROAMING_ICON_MODE_NORMAL;
1078            break;
1079
1080            case EriInfo.ROAMING_INDICATOR_FLASH:
1081                Log.d(LOG_TAG, "Using Standard Roaming Indicator (non-ERI): flashing");
1082                ret = EriInfo.ROAMING_ICON_MODE_FLASH;
1083            break;
1084
1085            // Handling the Enhanced Roaming Indicator (roamInd > 2)
1086            default:
1087                if (!mEriManager.isEriFileLoaded()) {
1088                    if(defRoamInd > 2) {
1089                        Log.d(LOG_TAG, "ERI File not loaded, defRoamInd > 2, flashing");
1090                        ret = EriInfo.ROAMING_ICON_MODE_FLASH;
1091                    } else {
1092                        switch (defRoamInd) {
1093                            // Handling the standard roaming indicator (non-ERI)
1094                            case EriInfo.ROAMING_INDICATOR_ON:
1095                            case EriInfo.ROAMING_INDICATOR_OFF:
1096                                Log.d(LOG_TAG, "ERI File not loaded, normal");
1097                                ret = EriInfo.ROAMING_ICON_MODE_NORMAL;
1098                            break;
1099
1100                            case EriInfo.ROAMING_INDICATOR_FLASH:
1101                                Log.d(LOG_TAG, "ERI File not loaded, normal");
1102                                ret = EriInfo.ROAMING_ICON_MODE_FLASH;
1103                            break;
1104                        }
1105                    }
1106                } else if (mEriManager.getEriInfo(roamInd) == null) {
1107                    if(mEriManager.getEriInfo(defRoamInd) == null) {
1108                        Log.e(LOG_TAG, "Error: defRoamInd not defined in ERI file, normal");
1109                        ret =  EriInfo.ROAMING_ICON_MODE_NORMAL;
1110                    } else {
1111                        int mode = mEriManager.getEriInfo(defRoamInd).mIconMode;
1112                        Log.d(LOG_TAG, "ERI entry " + roamInd + " not present, icon  mode: "
1113                                + mode);
1114                        ret = mode;
1115                    }
1116                } else {
1117                    int mode = mEriManager.getEriInfo(roamInd).mIconMode;
1118                    Log.d(LOG_TAG, "Using ERI icon mode: " + mode);
1119                    ret = mode;
1120                }
1121            break;
1122        }
1123        return ret;
1124    }
1125
1126    /**
1127     * Returns the CDMA ERI text,
1128     */
1129    @Override
1130    public String getCdmaEriText() {
1131        int roamInd = getServiceState().getCdmaRoamingIndicator();
1132        int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
1133        String ret = "ERI text";
1134
1135        switch (roamInd) {
1136            // Handling the standard roaming indicator (non-ERI)
1137            case EriInfo.ROAMING_INDICATOR_ON:
1138                ret = EriInfo.ROAMING_TEXT_0;
1139            break;
1140            case EriInfo.ROAMING_INDICATOR_OFF:
1141                ret = EriInfo.ROAMING_TEXT_1;
1142            break;
1143            case EriInfo.ROAMING_INDICATOR_FLASH:
1144                ret = EriInfo.ROAMING_TEXT_2;
1145            break;
1146
1147            // Handling the standard ERI
1148            case 3:
1149                ret = EriInfo.ROAMING_TEXT_3;
1150            break;
1151            case 4:
1152                ret = EriInfo.ROAMING_TEXT_4;
1153            break;
1154            case 5:
1155                ret = EriInfo.ROAMING_TEXT_5;
1156            break;
1157            case 6:
1158                ret = EriInfo.ROAMING_TEXT_6;
1159            break;
1160            case 7:
1161                ret = EriInfo.ROAMING_TEXT_7;
1162            break;
1163            case 8:
1164                ret = EriInfo.ROAMING_TEXT_8;
1165            break;
1166            case 9:
1167                ret = EriInfo.ROAMING_TEXT_9;
1168            break;
1169            case 10:
1170                ret = EriInfo.ROAMING_TEXT_10;
1171            break;
1172            case 11:
1173                ret = EriInfo.ROAMING_TEXT_11;
1174            break;
1175            case 12:
1176                ret = EriInfo.ROAMING_TEXT_12;
1177            break;
1178
1179            // Handling the non standard Enhanced Roaming Indicator (roamInd > 63)
1180            default:
1181                if (!mEriManager.isEriFileLoaded()) {
1182                    if(defRoamInd > 2) {
1183                        Log.d(LOG_TAG, "ERI File not loaded, defRoamInd > 2, " +
1184                                EriInfo.ROAMING_TEXT_2);
1185                        ret = EriInfo.ROAMING_TEXT_2;
1186                    } else {
1187                        switch (defRoamInd) {
1188                            // Handling the standard roaming indicator (non-ERI)
1189                            case EriInfo.ROAMING_INDICATOR_ON:
1190                                Log.d(LOG_TAG, "ERI File not loaded, " + EriInfo.ROAMING_TEXT_0);
1191                                ret = EriInfo.ROAMING_TEXT_0;
1192                            break;
1193                            case EriInfo.ROAMING_INDICATOR_OFF:
1194                                Log.d(LOG_TAG, "ERI File not loaded, " + EriInfo.ROAMING_TEXT_1);
1195                                ret = EriInfo.ROAMING_TEXT_1;
1196                            break;
1197                            case EriInfo.ROAMING_INDICATOR_FLASH:
1198                                Log.d(LOG_TAG, "ERI File not loaded, " + EriInfo.ROAMING_TEXT_2);
1199                                ret = EriInfo.ROAMING_TEXT_2;
1200                            break;
1201                        }
1202                    }
1203                } else if (mEriManager.getEriInfo(roamInd) == null) {
1204                    if(mEriManager.getEriInfo(defRoamInd) == null) {
1205                        Log.e(LOG_TAG, "Error: defRoamInd not defined in ERI file, "
1206                                + EriInfo.ROAMING_TEXT_0);
1207                        ret = EriInfo.ROAMING_TEXT_0;
1208                    } else {
1209                        String eriText = mEriManager.getEriInfo(defRoamInd).mEriText;
1210                        Log.d(LOG_TAG, "ERI entry " + roamInd + " not present, eri text: "
1211                                + eriText);
1212                        ret = eriText;
1213                    }
1214                } else {
1215                    String eriText = mEriManager.getEriInfo(roamInd).mEriText;
1216                    Log.d(LOG_TAG, "Using ERI text: " + eriText);
1217                    ret = eriText;
1218                }
1219            break;
1220        }
1221        return ret;
1222    }
1223}
1224