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