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