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