• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.internal.telephony.cdma;
18 
19 import android.app.ActivityManagerNative;
20 import android.content.Context;
21 import android.content.ContentValues;
22 import android.content.Intent;
23 import android.content.res.Configuration;
24 import android.content.SharedPreferences;
25 import android.database.SQLException;
26 import android.net.Uri;
27 import android.os.AsyncResult;
28 import android.os.Handler;
29 import android.os.Message;
30 import android.os.PowerManager;
31 import android.os.PowerManager.WakeLock;
32 import android.os.Registrant;
33 import android.os.RegistrantList;
34 import android.os.RemoteException;
35 import android.os.SystemProperties;
36 import android.preference.PreferenceManager;
37 import android.provider.Telephony;
38 import android.telephony.CellLocation;
39 import android.telephony.PhoneNumberUtils;
40 import android.telephony.ServiceState;
41 import android.telephony.SignalStrength;
42 import android.text.TextUtils;
43 import android.util.Log;
44 
45 import com.android.internal.telephony.Call;
46 import com.android.internal.telephony.CallStateException;
47 import com.android.internal.telephony.CommandException;
48 import com.android.internal.telephony.CommandsInterface;
49 import com.android.internal.telephony.Connection;
50 import com.android.internal.telephony.DataConnection;
51 import com.android.internal.telephony.MccTable;
52 import com.android.internal.telephony.IccCard;
53 import com.android.internal.telephony.IccException;
54 import com.android.internal.telephony.IccFileHandler;
55 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
56 import com.android.internal.telephony.IccSmsInterfaceManager;
57 import com.android.internal.telephony.MmiCode;
58 import com.android.internal.telephony.Phone;
59 import com.android.internal.telephony.PhoneBase;
60 import com.android.internal.telephony.PhoneNotifier;
61 import com.android.internal.telephony.PhoneProxy;
62 import com.android.internal.telephony.PhoneSubInfo;
63 import com.android.internal.telephony.TelephonyIntents;
64 import com.android.internal.telephony.TelephonyProperties;
65 
66 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
67 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
68 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
69 
70 import java.util.List;
71 
72 
73 import java.util.regex.Matcher;
74 import java.util.regex.Pattern;
75 
76 /**
77  * {@hide}
78  */
79 public class CDMAPhone extends PhoneBase {
80     static final String LOG_TAG = "CDMA";
81     private static final boolean DBG = true;
82 
83     // Min values used to by needsActivation
84     private static final String UNACTIVATED_MIN2_VALUE = "000000";
85     private static final String UNACTIVATED_MIN_VALUE = "1111110111";
86 
87     // Default Emergency Callback Mode exit timer
88     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
89 
90     static final String VM_COUNT_CDMA = "vm_count_key_cdma";
91     private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
92     private String mVmNumber = null;
93 
94     static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
95     static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
96 
97     // Instance Variables
98     CdmaCallTracker mCT;
99     CdmaSMSDispatcher mSMS;
100     CdmaServiceStateTracker mSST;
101     RuimFileHandler mRuimFileHandler;
102     RuimRecords mRuimRecords;
103     RuimCard mRuimCard;
104     RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager;
105     RuimSmsInterfaceManager mRuimSmsInterfaceManager;
106     PhoneSubInfo mSubInfo;
107     EriManager mEriManager;
108     WakeLock mWakeLock;
109 
110 
111     // mNvLoadedRegistrants are informed after the EVENT_NV_READY
112     private RegistrantList mNvLoadedRegistrants = new RegistrantList();
113 
114     // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
115     private RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
116 
117     // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
118     private RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
119 
120     // mEcmExitRespRegistrant is informed after the phone has been exited
121     //the emergency callback mode
122     //keep track of if phone is in emergency callback mode
123     private boolean mIsPhoneInEcmState;
124     private Registrant mEcmExitRespRegistrant;
125     private String mEsn;
126     private String mMeid;
127     // string to define how the carrier specifies its own ota sp number
128     private String mCarrierOtaSpNumSchema;
129 
130     // A runnable which is used to automatically exit from Ecm after a period of time.
131     private Runnable mExitEcmRunnable = new Runnable() {
132         public void run() {
133             exitEmergencyCallbackMode();
134         }
135     };
136 
137     Registrant mPostDialHandler;
138 
139 
140     // Constructors
CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier)141     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
142         this(context,ci,notifier, false);
143     }
144 
CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode)145     public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
146             boolean unitTestMode) {
147         super(notifier, context, ci, unitTestMode);
148 
149         mCM.setPhoneType(Phone.PHONE_TYPE_CDMA);
150         mCT = new CdmaCallTracker(this);
151         mSST = new CdmaServiceStateTracker (this);
152         mSMS = new CdmaSMSDispatcher(this);
153         mIccFileHandler = new RuimFileHandler(this);
154         mRuimRecords = new RuimRecords(this);
155         mDataConnection = new CdmaDataConnectionTracker (this);
156         mRuimCard = new RuimCard(this);
157         mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this);
158         mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this);
159         mSubInfo = new PhoneSubInfo(this);
160         mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
161 
162         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
163         mRuimRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
164         mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
165         mCM.registerForOn(this, EVENT_RADIO_ON, null);
166         mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
167         mSST.registerForNetworkAttach(this, EVENT_REGISTERED_TO_NETWORK, null);
168         mCM.registerForNVReady(this, EVENT_NV_READY, null);
169         mCM.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
170 
171         PowerManager pm
172             = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
173         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG);
174 
175         //Change the system setting
176         SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
177                 new Integer(Phone.PHONE_TYPE_CDMA).toString());
178 
179         // This is needed to handle phone process crashes
180         String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
181         mIsPhoneInEcmState = inEcm.equals("true");
182         if (mIsPhoneInEcmState) {
183             // Send a message which will invoke handleExitEmergencyCallbackMode
184             mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
185         }
186 
187         // get the string that specifies the carrier OTA Sp number
188         mCarrierOtaSpNumSchema = SystemProperties.get(
189                 TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,"");
190 
191         // Sets operator alpha property by retrieving from build-time system property
192         String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
193         setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha);
194 
195         // Sets operator numeric property by retrieving from build-time system property
196         String operatorNumeric = SystemProperties.get("ro.cdma.home.operator.numeric");
197         setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operatorNumeric);
198 
199         // Sets iso country property by retrieving from build-time system property
200         setIsoCountryProperty(operatorNumeric);
201 
202         // Sets current entry in the telephony carrier table
203         updateCurrentCarrierInProvider(operatorNumeric);
204 
205         // Updates MCC MNC device configuration information
206         MccTable.updateMccMncConfiguration(this, operatorNumeric);
207 
208 
209         // Notify voicemails.
210         notifier.notifyMessageWaitingChanged(this);
211     }
212 
dispose()213     public void dispose() {
214         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
215             super.dispose();
216 
217             //Unregister from all former registered events
218             mRuimRecords.unregisterForRecordsLoaded(this); //EVENT_RUIM_RECORDS_LOADED
219             mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
220             mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
221             mCM.unregisterForOn(this); //EVENT_RADIO_ON
222             mCM.unregisterForNVReady(this); //EVENT_NV_READY
223             mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
224             mCM.unSetOnSuppServiceNotification(this);
225 
226             //Force all referenced classes to unregister their former registered events
227             mCT.dispose();
228             mDataConnection.dispose();
229             mSST.dispose();
230             mSMS.dispose();
231             mIccFileHandler.dispose(); // instance of RuimFileHandler
232             mRuimRecords.dispose();
233             mRuimCard.dispose();
234             mRuimPhoneBookInterfaceManager.dispose();
235             mRuimSmsInterfaceManager.dispose();
236             mSubInfo.dispose();
237             mEriManager.dispose();
238         }
239     }
240 
removeReferences()241     public void removeReferences() {
242             this.mRuimPhoneBookInterfaceManager = null;
243             this.mRuimSmsInterfaceManager = null;
244             this.mSMS = null;
245             this.mSubInfo = null;
246             this.mRuimRecords = null;
247             this.mIccFileHandler = null;
248             this.mRuimCard = null;
249             this.mDataConnection = null;
250             this.mCT = null;
251             this.mSST = null;
252             this.mEriManager = null;
253     }
254 
finalize()255     protected void finalize() {
256         if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized");
257         if (mWakeLock.isHeld()) {
258             Log.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
259             mWakeLock.release();
260         }
261     }
262 
getServiceState()263     public ServiceState getServiceState() {
264         int roamInd = mSST.ss.getCdmaRoamingIndicator();
265         int defRoamInd = mSST.ss.getCdmaDefaultRoamingIndicator();
266 
267         mSST.ss.setCdmaEriIconIndex(mEriManager.getCdmaEriIconIndex(roamInd, defRoamInd));
268         mSST.ss.setCdmaEriIconMode(mEriManager.getCdmaEriIconMode(roamInd, defRoamInd));
269 
270         return mSST.ss;
271     }
272 
getState()273     public Phone.State getState() {
274         return mCT.state;
275     }
276 
getPhoneName()277     public String getPhoneName() {
278         return "CDMA";
279     }
280 
getPhoneType()281     public int getPhoneType() {
282         return Phone.PHONE_TYPE_CDMA;
283     }
284 
canTransfer()285     public boolean canTransfer() {
286         Log.e(LOG_TAG, "canTransfer: not possible in CDMA");
287         return false;
288     }
289 
getRingingCall()290     public CdmaCall getRingingCall() {
291         return mCT.ringingCall;
292     }
293 
setMute(boolean muted)294     public void setMute(boolean muted) {
295         mCT.setMute(muted);
296     }
297 
getMute()298     public boolean getMute() {
299         return mCT.getMute();
300     }
301 
conference()302     public void conference() throws CallStateException {
303         // three way calls in CDMA will be handled by feature codes
304         Log.e(LOG_TAG, "conference: not possible in CDMA");
305     }
306 
enableEnhancedVoicePrivacy(boolean enable, Message onComplete)307     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
308         this.mCM.setPreferredVoicePrivacy(enable, onComplete);
309     }
310 
getEnhancedVoicePrivacy(Message onComplete)311     public void getEnhancedVoicePrivacy(Message onComplete) {
312         this.mCM.getPreferredVoicePrivacy(onComplete);
313     }
314 
clearDisconnected()315     public void clearDisconnected() {
316         mCT.clearDisconnected();
317     }
318 
getDataActivityState()319     public DataActivityState getDataActivityState() {
320         DataActivityState ret = DataActivityState.NONE;
321 
322         if (mSST.getCurrentCdmaDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
323 
324             switch (mDataConnection.getActivity()) {
325                 case DATAIN:
326                     ret = DataActivityState.DATAIN;
327                 break;
328 
329                 case DATAOUT:
330                     ret = DataActivityState.DATAOUT;
331                 break;
332 
333                 case DATAINANDOUT:
334                     ret = DataActivityState.DATAINANDOUT;
335                 break;
336 
337                 case DORMANT:
338                     ret = DataActivityState.DORMANT;
339                 break;
340             }
341         }
342         return ret;
343     }
344 
345     /*package*/ void
notifySignalStrength()346     notifySignalStrength() {
347         mNotifier.notifySignalStrength(this);
348     }
349 
350     public Connection
dial(String dialString)351     dial (String dialString) throws CallStateException {
352         // Need to make sure dialString gets parsed properly
353         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
354         return mCT.dial(newDialString);
355     }
356 
getSignalStrength()357     public SignalStrength getSignalStrength() {
358         return mSST.mSignalStrength;
359     }
360 
361     public boolean
getMessageWaitingIndicator()362     getMessageWaitingIndicator() {
363         return (getVoiceMessageCount() > 0);
364     }
365 
366     public List<? extends MmiCode>
getPendingMmiCodes()367     getPendingMmiCodes() {
368         Log.e(LOG_TAG, "method getPendingMmiCodes is NOT supported in CDMA!");
369         return null;
370     }
371 
registerForSuppServiceNotification( Handler h, int what, Object obj)372     public void registerForSuppServiceNotification(
373             Handler h, int what, Object obj) {
374         Log.e(LOG_TAG, "method registerForSuppServiceNotification is NOT supported in CDMA!");
375     }
376 
getBackgroundCall()377     public CdmaCall getBackgroundCall() {
378         return mCT.backgroundCall;
379     }
380 
handleInCallMmiCommands(String dialString)381     public boolean handleInCallMmiCommands(String dialString) {
382         Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!");
383         return false;
384     }
385 
386     public void
setNetworkSelectionModeAutomatic(Message response)387     setNetworkSelectionModeAutomatic(Message response) {
388         Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!");
389     }
390 
unregisterForSuppServiceNotification(Handler h)391     public void unregisterForSuppServiceNotification(Handler h) {
392         Log.e(LOG_TAG, "method unregisterForSuppServiceNotification is NOT supported in CDMA!");
393     }
394 
395     public void
acceptCall()396     acceptCall() throws CallStateException {
397         mCT.acceptCall();
398     }
399 
400     public void
rejectCall()401     rejectCall() throws CallStateException {
402         mCT.rejectCall();
403     }
404 
405     public void
switchHoldingAndActive()406     switchHoldingAndActive() throws CallStateException {
407         mCT.switchWaitingOrHoldingAndActive();
408     }
409 
getLine1Number()410     public String getLine1Number() {
411         return mSST.getMdnNumber();
412     }
413 
getCdmaPrlVersion()414     public String getCdmaPrlVersion(){
415         return mSST.getPrlVersion();
416     }
417 
getCdmaMin()418     public String getCdmaMin() {
419         return mSST.getCdmaMin();
420     }
421 
isMinInfoReady()422     public boolean isMinInfoReady() {
423         return mSST.isMinInfoReady();
424     }
425 
getCallWaiting(Message onComplete)426     public void getCallWaiting(Message onComplete) {
427         mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
428     }
429 
430     public void
setRadioPower(boolean power)431     setRadioPower(boolean power) {
432         mSST.setRadioPower(power);
433     }
434 
getEsn()435     public String getEsn() {
436         return mEsn;
437     }
438 
getMeid()439     public String getMeid() {
440         return mMeid;
441     }
442 
443     //returns MEID in CDMA
getDeviceId()444     public String getDeviceId() {
445         return getMeid();
446     }
447 
getDeviceSvn()448     public String getDeviceSvn() {
449         Log.d(LOG_TAG, "getDeviceSvn(): return 0");
450         return "0";
451     }
452 
getSubscriberId()453     public String getSubscriberId() {
454         return mSST.getImsi();
455     }
456 
canConference()457     public boolean canConference() {
458         Log.e(LOG_TAG, "canConference: not possible in CDMA");
459         return false;
460     }
461 
getCellLocation()462     public CellLocation getCellLocation() {
463         return mSST.cellLoc;
464     }
465 
disableDataConnectivity()466     public boolean disableDataConnectivity() {
467         return mDataConnection.setDataEnabled(false);
468     }
469 
getForegroundCall()470     public CdmaCall getForegroundCall() {
471         return mCT.foregroundCall;
472     }
473 
474     public void
selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network, Message response)475     selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network,
476             Message response) {
477         Log.e(LOG_TAG, "selectNetworkManually: not possible in CDMA");
478     }
479 
setOnPostDialCharacter(Handler h, int what, Object obj)480     public void setOnPostDialCharacter(Handler h, int what, Object obj) {
481         mPostDialHandler = new Registrant(h, what, obj);
482     }
483 
handlePinMmi(String dialString)484     public boolean handlePinMmi(String dialString) {
485         Log.e(LOG_TAG, "method handlePinMmi is NOT supported in CDMA!");
486         return false;
487     }
488 
isDataConnectivityPossible()489     public boolean isDataConnectivityPossible() {
490         boolean noData = mDataConnection.getDataEnabled() &&
491                 getDataConnectionState() == DataState.DISCONNECTED;
492         return !noData && getIccCard().getState() == IccCard.State.READY &&
493                 getServiceState().getState() == ServiceState.STATE_IN_SERVICE &&
494                 (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());
495     }
496 
setLine1Number(String alphaTag, String number, Message onComplete)497     public void setLine1Number(String alphaTag, String number, Message onComplete) {
498         Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
499     }
500 
getIccCard()501     public IccCard getIccCard() {
502         return mRuimCard;
503     }
504 
getIccSerialNumber()505     public String getIccSerialNumber() {
506         return mRuimRecords.iccid;
507     }
508 
setCallWaiting(boolean enable, Message onComplete)509     public void setCallWaiting(boolean enable, Message onComplete) {
510         Log.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!");
511     }
512 
updateServiceLocation()513     public void updateServiceLocation() {
514         mSST.enableSingleLocationUpdate();
515     }
516 
setDataRoamingEnabled(boolean enable)517     public void setDataRoamingEnabled(boolean enable) {
518         mDataConnection.setDataOnRoamingEnabled(enable);
519     }
520 
registerForCdmaOtaStatusChange(Handler h, int what, Object obj)521     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
522         mCM.registerForCdmaOtaProvision(h, what, obj);
523     }
524 
unregisterForCdmaOtaStatusChange(Handler h)525     public void unregisterForCdmaOtaStatusChange(Handler h) {
526         mCM.unregisterForCdmaOtaProvision(h);
527     }
528 
registerForSubscriptionInfoReady(Handler h, int what, Object obj)529     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
530         mSST.registerForSubscriptionInfoReady(h, what, obj);
531     }
532 
unregisterForSubscriptionInfoReady(Handler h)533     public void unregisterForSubscriptionInfoReady(Handler h) {
534         mSST.unregisterForSubscriptionInfoReady(h);
535     }
536 
setOnEcbModeExitResponse(Handler h, int what, Object obj)537     public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
538         mEcmExitRespRegistrant = new Registrant (h, what, obj);
539     }
540 
unsetOnEcbModeExitResponse(Handler h)541     public void unsetOnEcbModeExitResponse(Handler h) {
542         mEcmExitRespRegistrant.clear();
543     }
544 
registerForCallWaiting(Handler h, int what, Object obj)545     public void registerForCallWaiting(Handler h, int what, Object obj) {
546         mCT.registerForCallWaiting(h, what, obj);
547     }
548 
unregisterForCallWaiting(Handler h)549     public void unregisterForCallWaiting(Handler h) {
550         mCT.unregisterForCallWaiting(h);
551     }
552 
553     public void
getNeighboringCids(Message response)554     getNeighboringCids(Message response) {
555         /*
556          * This is currently not implemented.  At least as of June
557          * 2009, there is no neighbor cell information available for
558          * CDMA because some party is resisting making this
559          * information readily available.  Consequently, calling this
560          * function can have no useful effect.  This situation may
561          * (and hopefully will) change in the future.
562          */
563         if (response != null) {
564             CommandException ce = new CommandException(
565                     CommandException.Error.REQUEST_NOT_SUPPORTED);
566             AsyncResult.forMessage(response).exception = ce;
567             response.sendToTarget();
568         }
569     }
570 
getDataConnectionState()571     public DataState getDataConnectionState() {
572         DataState ret = DataState.DISCONNECTED;
573 
574         if ((SystemProperties.get("adb.connected", "").length() > 0)
575                 && (SystemProperties.get("android.net.use-adb-networking", "")
576                         .length() > 0)) {
577             // We're connected to an ADB host and we have USB networking
578             // turned on. No matter what the radio state is,
579             // we report data connected
580 
581             ret = DataState.CONNECTED;
582         } else if (mSST == null) {
583              // Radio Technology Change is ongoning, dispose() and removeReferences() have
584              // already been called
585 
586              ret = DataState.DISCONNECTED;
587         } else if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
588             // If we're out of service, open TCP sockets may still work
589             // but no data will flow
590             ret = DataState.DISCONNECTED;
591         } else {
592             switch (mDataConnection.getState()) {
593                 case FAILED:
594                 case IDLE:
595                     ret = DataState.DISCONNECTED;
596                 break;
597 
598                 case CONNECTED:
599                 case DISCONNECTING:
600                     if ( mCT.state != Phone.State.IDLE
601                             && !mSST.isConcurrentVoiceAndData()) {
602                         ret = DataState.SUSPENDED;
603                     } else {
604                         ret = DataState.CONNECTED;
605                     }
606                 break;
607 
608                 case INITING:
609                 case CONNECTING:
610                 case SCANNING:
611                     ret = DataState.CONNECTING;
612                 break;
613             }
614         }
615 
616         return ret;
617     }
618 
sendUssdResponse(String ussdMessge)619     public void sendUssdResponse(String ussdMessge) {
620         Log.e(LOG_TAG, "sendUssdResponse: not possible in CDMA");
621     }
622 
sendDtmf(char c)623     public void sendDtmf(char c) {
624         if (!PhoneNumberUtils.is12Key(c)) {
625             Log.e(LOG_TAG,
626                     "sendDtmf called with invalid character '" + c + "'");
627         } else {
628             if (mCT.state ==  Phone.State.OFFHOOK) {
629                 mCM.sendDtmf(c, null);
630             }
631         }
632     }
633 
startDtmf(char c)634     public void startDtmf(char c) {
635         if (!PhoneNumberUtils.is12Key(c)) {
636             Log.e(LOG_TAG,
637                     "startDtmf called with invalid character '" + c + "'");
638         } else {
639             mCM.startDtmf(c, null);
640         }
641     }
642 
stopDtmf()643     public void stopDtmf() {
644         mCM.stopDtmf(null);
645     }
646 
sendBurstDtmf(String dtmfString, int on, int off, Message onComplete)647     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
648         boolean check = true;
649         for (int itr = 0;itr < dtmfString.length(); itr++) {
650             if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
651                 Log.e(LOG_TAG,
652                         "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'");
653                 check = false;
654                 break;
655             }
656         }
657         if ((mCT.state ==  Phone.State.OFFHOOK)&&(check)) {
658             mCM.sendBurstDtmf(dtmfString, on, off, onComplete);
659         }
660      }
661 
getAvailableNetworks(Message response)662     public void getAvailableNetworks(Message response) {
663         Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
664     }
665 
setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete)666     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
667         Log.e(LOG_TAG, "setOutgoingCallerIdDisplay: not possible in CDMA");
668     }
669 
enableLocationUpdates()670     public void enableLocationUpdates() {
671         mSST.enableLocationUpdates();
672     }
673 
disableLocationUpdates()674     public void disableLocationUpdates() {
675         mSST.disableLocationUpdates();
676     }
677 
678     /**
679      * @deprecated
680      */
getPdpContextList(Message response)681     public void getPdpContextList(Message response) {
682         getDataCallList(response);
683     }
684 
getDataCallList(Message response)685     public void getDataCallList(Message response) {
686         mCM.getDataCallList(response);
687     }
688 
getDataRoamingEnabled()689     public boolean getDataRoamingEnabled() {
690         return mDataConnection.getDataOnRoamingEnabled();
691     }
692 
getCurrentDataConnectionList()693     public List<DataConnection> getCurrentDataConnectionList () {
694         return mDataConnection.getAllDataConnections();
695     }
696 
setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete)697     public void setVoiceMailNumber(String alphaTag,
698                                    String voiceMailNumber,
699                                    Message onComplete) {
700         Message resp;
701         mVmNumber = voiceMailNumber;
702         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
703         mRuimRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
704     }
705 
getVoiceMailNumber()706     public String getVoiceMailNumber() {
707         String number = null;
708         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
709         // TODO(Moto): The default value of voicemail number should be read from a system property
710         number = sp.getString(VM_NUMBER_CDMA, "*86");
711         return number;
712     }
713 
714     /* Returns Number of Voicemails
715      * @hide
716      */
getVoiceMessageCount()717     public int getVoiceMessageCount() {
718         int voicemailCount =  mRuimRecords.getVoiceMessageCount();
719         // If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility
720         // that phone was power cycled and would have lost the voicemail count.
721         // So get the count from preferences.
722         if (voicemailCount == 0) {
723             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
724             voicemailCount = sp.getInt(VM_COUNT_CDMA, 0);
725         }
726         return voicemailCount;
727     }
728 
getVoiceMailAlphaTag()729     public String getVoiceMailAlphaTag() {
730         // TODO: Where can we get this value has to be clarified with QC.
731         String ret = "";//TODO: Remove = "", if we know where to get this value.
732 
733         //ret = mSIMRecords.getVoiceMailAlphaTag();
734 
735         if (ret == null || ret.length() == 0) {
736             return mContext.getText(
737                 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
738         }
739 
740         return ret;
741     }
742 
enableDataConnectivity()743     public boolean enableDataConnectivity() {
744 
745         // block data activities when phone is in emergency callback mode
746         if (mIsPhoneInEcmState) {
747             Intent intent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS);
748             ActivityManagerNative.broadcastStickyIntent(intent, null);
749             return false;
750         } else if ((mCT.state == Phone.State.OFFHOOK) && mCT.isInEmergencyCall()) {
751             // Do not allow data call to be enabled when emergency call is going on
752             return false;
753         } else {
754             return mDataConnection.setDataEnabled(true);
755         }
756     }
757 
getIccRecordsLoaded()758     public boolean getIccRecordsLoaded() {
759         return mRuimRecords.getRecordsLoaded();
760     }
761 
getCallForwardingOption(int commandInterfaceCFReason, Message onComplete)762     public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
763         Log.e(LOG_TAG, "getCallForwardingOption: not possible in CDMA");
764     }
765 
setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int timerSeconds, Message onComplete)766     public void setCallForwardingOption(int commandInterfaceCFAction,
767             int commandInterfaceCFReason,
768             String dialingNumber,
769             int timerSeconds,
770             Message onComplete) {
771         Log.e(LOG_TAG, "setCallForwardingOption: not possible in CDMA");
772     }
773 
774     public void
getOutgoingCallerIdDisplay(Message onComplete)775     getOutgoingCallerIdDisplay(Message onComplete) {
776         Log.e(LOG_TAG, "getOutgoingCallerIdDisplay: not possible in CDMA");
777     }
778 
779     public boolean
getCallForwardingIndicator()780     getCallForwardingIndicator() {
781         Log.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA");
782         return false;
783     }
784 
explicitCallTransfer()785     public void explicitCallTransfer() {
786         Log.e(LOG_TAG, "explicitCallTransfer: not possible in CDMA");
787     }
788 
getLine1AlphaTag()789     public String getLine1AlphaTag() {
790         Log.e(LOG_TAG, "getLine1AlphaTag: not possible in CDMA");
791         return null;
792     }
793 
794    /**
795      * Notify any interested party of a Phone state change  {@link Phone.State}
796      */
notifyPhoneStateChanged()797     /*package*/ void notifyPhoneStateChanged() {
798         mNotifier.notifyPhoneState(this);
799     }
800 
801     /**
802      * Notify registrants of a change in the call state. This notifies changes in {@link Call.State}
803      * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged.
804      */
notifyPreciseCallStateChanged()805     /*package*/ void notifyPreciseCallStateChanged() {
806         /* we'd love it if this was package-scoped*/
807         super.notifyPreciseCallStateChangedP();
808     }
809 
notifyServiceStateChanged(ServiceState ss)810      void notifyServiceStateChanged(ServiceState ss) {
811          // TODO this seems really inefficient.  Can't we calc this when the fundamentals change and store in the
812          // service state?
813          ss.setCdmaEriIconIndex(this.getCdmaEriIconIndex());
814          ss.setCdmaEriIconMode(this.getCdmaEriIconMode());
815          super.notifyServiceStateChangedP(ss);
816      }
817 
notifyLocationChanged()818      void notifyLocationChanged() {
819          mNotifier.notifyCellLocation(this);
820      }
821 
notifyNewRingingConnection(Connection c)822     /*package*/ void notifyNewRingingConnection(Connection c) {
823         /* we'd love it if this was package-scoped*/
824         super.notifyNewRingingConnectionP(c);
825     }
826 
notifyDisconnect(Connection cn)827     /*package*/ void notifyDisconnect(Connection cn) {
828         mDisconnectRegistrants.notifyResult(cn);
829     }
830 
notifyUnknownConnection()831     void notifyUnknownConnection() {
832         mUnknownConnectionRegistrants.notifyResult(this);
833     }
834 
sendEmergencyCallbackModeChange()835     void sendEmergencyCallbackModeChange(){
836         //Send an Intent
837         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
838         intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
839         ActivityManagerNative.broadcastStickyIntent(intent,null);
840         if (DBG) Log.d(LOG_TAG, "sendEmergencyCallbackModeChange");
841     }
842 
843     /*package*/ void
updateMessageWaitingIndicator(boolean mwi)844     updateMessageWaitingIndicator(boolean mwi) {
845         // this also calls notifyMessageWaitingIndicator()
846         mRuimRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0);
847     }
848 
849     /* This function is overloaded to send number of voicemails instead of sending true/false */
850     /*package*/ void
updateMessageWaitingIndicator(int mwi)851     updateMessageWaitingIndicator(int mwi) {
852         mRuimRecords.setVoiceMessageWaiting(1, mwi);
853     }
854 
855     /**
856      * Returns true if CDMA OTA Service Provisioning needs to be performed.
857      */
858     /* package */ boolean
needsOtaServiceProvisioning()859     needsOtaServiceProvisioning() {
860         String cdmaMin = getCdmaMin();
861         boolean needsProvisioning;
862         if (cdmaMin == null || (cdmaMin.length() < 6)) {
863             if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: illegal cdmaMin='"
864                                     + cdmaMin + "' assume provisioning needed.");
865             needsProvisioning = true;
866         } else {
867             needsProvisioning = (cdmaMin.equals(UNACTIVATED_MIN_VALUE)
868                     || cdmaMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
869                     || SystemProperties.getBoolean("test_cdma_setup", false);
870         }
871         if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: ret=" + needsProvisioning);
872         return needsProvisioning;
873     }
874 
875     @Override
exitEmergencyCallbackMode()876     public void exitEmergencyCallbackMode() {
877         if (mWakeLock.isHeld()) {
878             mWakeLock.release();
879         }
880         // Send a message which will invoke handleExitEmergencyCallbackMode
881         mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
882     }
883 
handleEnterEmergencyCallbackMode(Message msg)884     private void handleEnterEmergencyCallbackMode(Message msg) {
885         if (DBG) {
886             Log.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
887                     + mIsPhoneInEcmState);
888         }
889         // if phone is not in Ecm mode, and it's changed to Ecm mode
890         if (mIsPhoneInEcmState == false) {
891             mIsPhoneInEcmState = true;
892             // notify change
893             sendEmergencyCallbackModeChange();
894             setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
895 
896             // Post this runnable so we will automatically exit
897             // if no one invokes exitEmergencyCallbackMode() directly.
898             long delayInMillis = SystemProperties.getLong(
899                     TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
900             postDelayed(mExitEcmRunnable, delayInMillis);
901             // We don't want to go to sleep while in Ecm
902             mWakeLock.acquire();
903         }
904     }
905 
handleExitEmergencyCallbackMode(Message msg)906     private void handleExitEmergencyCallbackMode(Message msg) {
907         AsyncResult ar = (AsyncResult)msg.obj;
908         if (DBG) {
909             Log.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState "
910                     + ar.exception + mIsPhoneInEcmState);
911         }
912         // Remove pending exit Ecm runnable, if any
913         removeCallbacks(mExitEcmRunnable);
914 
915         if (mEcmExitRespRegistrant != null) {
916             mEcmExitRespRegistrant.notifyRegistrant(ar);
917         }
918         // if exiting ecm success
919         if (ar.exception == null) {
920             if (mIsPhoneInEcmState) {
921                 mIsPhoneInEcmState = false;
922                 setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
923             }
924             // send an Intent
925             sendEmergencyCallbackModeChange();
926             // Re-initiate data connection
927             mDataConnection.setDataEnabled(true);
928         }
929     }
930 
931     /**
932      * Handle to cancel or restart Ecm timer in emergency call back mode
933      * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
934      * otherwise, restart Ecm timer and notify apps the timer is restarted.
935      */
handleTimerInEmergencyCallbackMode(int action)936     void handleTimerInEmergencyCallbackMode(int action) {
937         switch(action) {
938         case CANCEL_ECM_TIMER:
939             removeCallbacks(mExitEcmRunnable);
940             mEcmTimerResetRegistrants.notifyResult(new Boolean(true));
941             break;
942         case RESTART_ECM_TIMER:
943             long delayInMillis = SystemProperties.getLong(
944                     TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
945             postDelayed(mExitEcmRunnable, delayInMillis);
946             mEcmTimerResetRegistrants.notifyResult(new Boolean(false));
947             break;
948         default:
949             Log.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
950         }
951     }
952 
953     /**
954      * Registration point for Ecm timer reset
955      * @param h handler to notify
956      * @param what User-defined message code
957      * @param obj placed in Message.obj
958      */
registerForEcmTimerReset(Handler h, int what, Object obj)959     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
960         mEcmTimerResetRegistrants.addUnique(h, what, obj);
961     }
962 
unregisterForEcmTimerReset(Handler h)963     public void unregisterForEcmTimerReset(Handler h) {
964         mEcmTimerResetRegistrants.remove(h);
965     }
966 
967     @Override
handleMessage(Message msg)968     public void handleMessage(Message msg) {
969         AsyncResult ar;
970         Message     onComplete;
971 
972         switch(msg.what) {
973             case EVENT_RADIO_AVAILABLE: {
974                 mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
975 
976                 mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
977             }
978             break;
979 
980             case EVENT_GET_BASEBAND_VERSION_DONE:{
981                 ar = (AsyncResult)msg.obj;
982 
983                 if (ar.exception != null) {
984                     break;
985                 }
986 
987                 if (DBG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
988                 setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result);
989             }
990             break;
991 
992             case EVENT_GET_DEVICE_IDENTITY_DONE:{
993                 ar = (AsyncResult)msg.obj;
994 
995                 if (ar.exception != null) {
996                     break;
997                 }
998                 String[] respId = (String[])ar.result;
999                 mEsn  =  respId[2];
1000                 mMeid =  respId[3];
1001             }
1002             break;
1003 
1004             case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
1005                 handleEnterEmergencyCallbackMode(msg);
1006             }
1007             break;
1008 
1009             case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
1010                 handleExitEmergencyCallbackMode(msg);
1011             }
1012             break;
1013 
1014             case EVENT_RUIM_RECORDS_LOADED:{
1015                 Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
1016             }
1017             break;
1018 
1019             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{
1020                 Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
1021             }
1022             break;
1023 
1024             case EVENT_RADIO_ON:{
1025                 Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received");
1026             }
1027             break;
1028 
1029             case EVENT_SSN:{
1030                 Log.d(LOG_TAG, "Event EVENT_SSN Received");
1031             }
1032             break;
1033 
1034             case EVENT_REGISTERED_TO_NETWORK:{
1035                 Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received");
1036             }
1037             break;
1038 
1039             case EVENT_NV_READY:{
1040                 Log.d(LOG_TAG, "Event EVENT_NV_READY Received");
1041                 //Inform the Service State Tracker
1042                 mEriManager.loadEriFile();
1043                 mNvLoadedRegistrants.notifyRegistrants();
1044                 if(mEriManager.isEriFileLoaded()) {
1045                     // when the ERI file is loaded
1046                     Log.d(LOG_TAG, "ERI read, notify registrants");
1047                     mEriFileLoadedRegistrants.notifyRegistrants();
1048                 }
1049             }
1050             break;
1051 
1052             case EVENT_SET_VM_NUMBER_DONE:{
1053                 ar = (AsyncResult)msg.obj;
1054                 if (IccException.class.isInstance(ar.exception)) {
1055                     storeVoiceMailNumber(mVmNumber);
1056                     ar.exception = null;
1057                 }
1058                 onComplete = (Message) ar.userObj;
1059                 if (onComplete != null) {
1060                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1061                     onComplete.sendToTarget();
1062                 }
1063             }
1064             break;
1065 
1066             default:{
1067                 super.handleMessage(msg);
1068             }
1069         }
1070     }
1071 
1072     /**
1073      * Retrieves the PhoneSubInfo of the CDMAPhone
1074      */
getPhoneSubInfo()1075     public PhoneSubInfo getPhoneSubInfo() {
1076         return mSubInfo;
1077     }
1078 
1079     /**
1080      * Retrieves the IccSmsInterfaceManager of the CDMAPhone
1081      */
getIccSmsInterfaceManager()1082     public IccSmsInterfaceManager getIccSmsInterfaceManager() {
1083         return mRuimSmsInterfaceManager;
1084     }
1085 
1086     /**
1087      * Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone
1088      */
getIccPhoneBookInterfaceManager()1089     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager() {
1090         return mRuimPhoneBookInterfaceManager;
1091     }
1092 
registerForNvLoaded(Handler h, int what, Object obj)1093     public void registerForNvLoaded(Handler h, int what, Object obj) {
1094         Registrant r = new Registrant (h, what, obj);
1095         mNvLoadedRegistrants.add(r);
1096     }
1097 
unregisterForNvLoaded(Handler h)1098     public void unregisterForNvLoaded(Handler h) {
1099         mNvLoadedRegistrants.remove(h);
1100     }
1101 
registerForEriFileLoaded(Handler h, int what, Object obj)1102     public void registerForEriFileLoaded(Handler h, int what, Object obj) {
1103         Registrant r = new Registrant (h, what, obj);
1104         mEriFileLoadedRegistrants.add(r);
1105     }
1106 
unregisterForEriFileLoaded(Handler h)1107     public void unregisterForEriFileLoaded(Handler h) {
1108         mEriFileLoadedRegistrants.remove(h);
1109     }
1110 
1111     // override for allowing access from other classes of this package
1112     /**
1113      * {@inheritDoc}
1114      */
setSystemProperty(String property, String value)1115     public final void setSystemProperty(String property, String value) {
1116         super.setSystemProperty(property, value);
1117     }
1118 
1119     /**
1120      * {@inheritDoc}
1121      */
getIccFileHandler()1122     public IccFileHandler getIccFileHandler() {
1123         return this.mIccFileHandler;
1124     }
1125 
1126     /**
1127      * Set the TTY mode of the CDMAPhone
1128      */
setTTYMode(int ttyMode, Message onComplete)1129     public void setTTYMode(int ttyMode, Message onComplete) {
1130         this.mCM.setTTYMode(ttyMode, onComplete);
1131     }
1132 
1133     /**
1134      * Queries the TTY mode of the CDMAPhone
1135      */
queryTTYMode(Message onComplete)1136     public void queryTTYMode(Message onComplete) {
1137         this.mCM.queryTTYMode(onComplete);
1138     }
1139 
1140     /**
1141      * Activate or deactivate cell broadcast SMS.
1142      *
1143      * @param activate 0 = activate, 1 = deactivate
1144      * @param response Callback message is empty on completion
1145      */
activateCellBroadcastSms(int activate, Message response)1146     public void activateCellBroadcastSms(int activate, Message response) {
1147         mSMS.activateCellBroadcastSms(activate, response);
1148     }
1149 
1150     /**
1151      * Query the current configuration of cdma cell broadcast SMS.
1152      *
1153      * @param response Callback message is empty on completion
1154      */
getCellBroadcastSmsConfig(Message response)1155     public void getCellBroadcastSmsConfig(Message response) {
1156         mSMS.getCellBroadcastSmsConfig(response);
1157     }
1158 
1159     /**
1160      * Configure cdma cell broadcast SMS.
1161      *
1162      * @param response Callback message is empty on completion
1163      */
setCellBroadcastSmsConfig(int[] configValuesArray, Message response)1164     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
1165         mSMS.setCellBroadcastConfig(configValuesArray, response);
1166     }
1167 
1168     private static final String IS683A_FEATURE_CODE = "*228";
1169     private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
1170     private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
1171     private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
1172 
1173     private static final int IS683_CONST_800MHZ_A_BAND = 0;
1174     private static final int IS683_CONST_800MHZ_B_BAND = 1;
1175     private static final int IS683_CONST_1900MHZ_A_BLOCK = 2;
1176     private static final int IS683_CONST_1900MHZ_B_BLOCK = 3;
1177     private static final int IS683_CONST_1900MHZ_C_BLOCK = 4;
1178     private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
1179     private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
1180     private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
1181     private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
1182 
isIs683OtaSpDialStr(String dialStr)1183     private boolean isIs683OtaSpDialStr(String dialStr) {
1184         int sysSelCodeInt;
1185         boolean isOtaspDialString = false;
1186         int dialStrLen = dialStr.length();
1187 
1188         if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) {
1189             if (dialStr.equals(IS683A_FEATURE_CODE)) {
1190                 isOtaspDialString = true;
1191             }
1192         } else {
1193             sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
1194             switch (sysSelCodeInt) {
1195                 case IS683_CONST_800MHZ_A_BAND:
1196                 case IS683_CONST_800MHZ_B_BAND:
1197                 case IS683_CONST_1900MHZ_A_BLOCK:
1198                 case IS683_CONST_1900MHZ_B_BLOCK:
1199                 case IS683_CONST_1900MHZ_C_BLOCK:
1200                 case IS683_CONST_1900MHZ_D_BLOCK:
1201                 case IS683_CONST_1900MHZ_E_BLOCK:
1202                 case IS683_CONST_1900MHZ_F_BLOCK:
1203                     isOtaspDialString = true;
1204                     break;
1205                 default:
1206                     break;
1207             }
1208         }
1209         return isOtaspDialString;
1210     }
1211     /**
1212      * This function extracts the system selection code from the dial string.
1213      */
extractSelCodeFromOtaSpNum(String dialStr)1214     private int extractSelCodeFromOtaSpNum(String dialStr) {
1215         int dialStrLen = dialStr.length();
1216         int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
1217 
1218         if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
1219                                    0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
1220             (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
1221                             IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
1222                 // Since we checked the condition above, the system selection code
1223                 // extracted from dialStr will not cause any exception
1224                 sysSelCodeInt = Integer.parseInt (
1225                                 dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
1226                                 IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
1227         }
1228         if (DBG) Log.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
1229         return sysSelCodeInt;
1230     }
1231 
1232     /**
1233      * This function checks if the system selection code extracted from
1234      * the dial string "sysSelCodeInt' is the system selection code specified
1235      * in the carrier ota sp number schema "sch".
1236      */
1237     private boolean
checkOtaSpNumBasedOnSysSelCode(int sysSelCodeInt, String sch[])1238     checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) {
1239         boolean isOtaSpNum = false;
1240         try {
1241             // Get how many number of system selection code ranges
1242             int selRc = Integer.parseInt((String)sch[1]);
1243             for (int i = 0; i < selRc; i++) {
1244                 if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
1245                     int selMin = Integer.parseInt((String)sch[i+2]);
1246                     int selMax = Integer.parseInt((String)sch[i+3]);
1247                     // Check if the selection code extracted from the dial string falls
1248                     // within any of the range pairs specified in the schema.
1249                     if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
1250                         isOtaSpNum = true;
1251                         break;
1252                     }
1253                 }
1254             }
1255         } catch (NumberFormatException ex) {
1256             // If the carrier ota sp number schema is not correct, we still allow dial
1257             // and only log the error:
1258             Log.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
1259         }
1260         return isOtaSpNum;
1261     }
1262 
1263     // Define the pattern/format for carrier specified OTASP number schema.
1264     // It separates by comma and/or whitespace.
1265     private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
1266 
1267     /**
1268      * The following function checks if a dial string is a carrier specified
1269      * OTASP number or not by checking against the OTASP number schema stored
1270      * in PROPERTY_OTASP_NUM_SCHEMA.
1271      *
1272      * Currently, there are 2 schemas for carriers to specify the OTASP number:
1273      * 1) Use system selection code:
1274      *    The schema is:
1275      *    SELC,the # of code pairs,min1,max1,min2,max2,...
1276      *    e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
1277      *    selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
1278      *
1279      * 2) Use feature code:
1280      *    The schema is:
1281      *    "FC,length of feature code,feature code".
1282      *     e.g "FC,2,*2" indicates that the length of the feature code is 2,
1283      *     and the code itself is "*2".
1284      */
isCarrierOtaSpNum(String dialStr)1285     private boolean isCarrierOtaSpNum(String dialStr) {
1286         boolean isOtaSpNum = false;
1287         int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
1288         if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
1289             return isOtaSpNum;
1290         }
1291         // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
1292         if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
1293             Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
1294             if (DBG) {
1295                 Log.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
1296             }
1297 
1298             if (m.find()) {
1299                 String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
1300                 // If carrier uses system selection code mechanism
1301                 if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
1302                     if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
1303                         isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
1304                     } else {
1305                         if (DBG) {
1306                             Log.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
1307                         }
1308                     }
1309                 } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
1310                     int fcLen =  Integer.parseInt((String)sch[1]);
1311                     String fc = (String)sch[2];
1312                     if (dialStr.regionMatches(0,fc,0,fcLen)) {
1313                         isOtaSpNum = true;
1314                     } else {
1315                         if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
1316                     }
1317                 } else {
1318                     if (DBG) {
1319                         Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
1320                     }
1321                 }
1322             } else {
1323                 if (DBG) {
1324                     Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
1325                           mCarrierOtaSpNumSchema);
1326                 }
1327             }
1328         } else {
1329             if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
1330         }
1331         return isOtaSpNum;
1332     }
1333 
1334     /**
1335      * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
1336      * OTASP dial string.
1337      *
1338      * @param dialStr the number to look up.
1339      * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
1340      */
1341     @Override
isOtaSpNumber(String dialStr)1342     public  boolean isOtaSpNumber(String dialStr){
1343         boolean isOtaSpNum = false;
1344         String dialableStr = PhoneNumberUtils.extractNetworkPortion(dialStr);
1345         if (dialableStr != null) {
1346             isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
1347             if (isOtaSpNum == false) {
1348                 isOtaSpNum = isCarrierOtaSpNum(dialableStr);
1349             }
1350         }
1351         if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
1352         return isOtaSpNum;
1353     }
1354 
1355     @Override
getCdmaEriIconIndex()1356     public int getCdmaEriIconIndex() {
1357         int roamInd = getServiceState().getCdmaRoamingIndicator();
1358         int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
1359         return mEriManager.getCdmaEriIconIndex(roamInd, defRoamInd);
1360     }
1361 
1362     /**
1363      * Returns the CDMA ERI icon mode,
1364      * 0 - ON
1365      * 1 - FLASHING
1366      */
1367     @Override
getCdmaEriIconMode()1368     public int getCdmaEriIconMode() {
1369         int roamInd = getServiceState().getCdmaRoamingIndicator();
1370         int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
1371         return mEriManager.getCdmaEriIconMode(roamInd, defRoamInd);
1372     }
1373 
1374     /**
1375      * Returns the CDMA ERI text,
1376      */
1377     @Override
getCdmaEriText()1378     public String getCdmaEriText() {
1379         int roamInd = getServiceState().getCdmaRoamingIndicator();
1380         int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
1381         return mEriManager.getCdmaEriText(roamInd, defRoamInd);
1382     }
1383 
1384     /**
1385      * Store the voicemail number in preferences
1386      */
storeVoiceMailNumber(String number)1387     private void storeVoiceMailNumber(String number) {
1388         // Update the preference value of voicemail number
1389         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1390         SharedPreferences.Editor editor = sp.edit();
1391         editor.putString(VM_NUMBER_CDMA, number);
1392         editor.commit();
1393     }
1394 
1395     /**
1396      * Sets PROPERTY_ICC_OPERATOR_ISO_COUNTRY property
1397      *
1398      */
setIsoCountryProperty(String operatorNumeric)1399     private void setIsoCountryProperty(String operatorNumeric) {
1400         if (TextUtils.isEmpty(operatorNumeric)) {
1401             setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
1402         } else {
1403             String iso = "";
1404             try {
1405                 iso = MccTable.countryCodeForMcc(Integer.parseInt(
1406                         operatorNumeric.substring(0,3)));
1407             } catch (NumberFormatException ex) {
1408                 Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
1409             } catch (StringIndexOutOfBoundsException ex) {
1410                 Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
1411             }
1412 
1413             setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, iso);
1414         }
1415     }
1416 
1417     /**
1418      * Sets the "current" field in the telephony provider according to the build-time
1419      * operator numeric property
1420      *
1421      * @return true for success; false otherwise.
1422      */
1423     // TODO(Moto): move this method into PhoneBase, since it looks identical to
1424     // the one in GsmPhone
updateCurrentCarrierInProvider(String operatorNumeric)1425     private boolean updateCurrentCarrierInProvider(String operatorNumeric) {
1426         if (!TextUtils.isEmpty(operatorNumeric)) {
1427             try {
1428                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
1429                 ContentValues map = new ContentValues();
1430                 map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
1431                 getContext().getContentResolver().insert(uri, map);
1432                 return true;
1433             } catch (SQLException e) {
1434                 Log.e(LOG_TAG, "Can't store current operator", e);
1435             }
1436         }
1437         return false;
1438     }
1439 
1440 }
1441