• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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;
18 
19 import android.app.ActivityManagerNative;
20 import android.content.BroadcastReceiver;
21 import android.content.ContentValues;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.SharedPreferences;
26 import android.database.SQLException;
27 import android.net.Uri;
28 import android.os.AsyncResult;
29 import android.os.Bundle;
30 import android.os.Handler;
31 import android.os.Message;
32 import android.os.PersistableBundle;
33 import android.os.PowerManager;
34 import android.os.Registrant;
35 import android.os.RegistrantList;
36 import android.os.SystemProperties;
37 import android.os.UserHandle;
38 import android.preference.PreferenceManager;
39 import android.provider.Settings;
40 import android.provider.Telephony;
41 import android.telecom.VideoProfile;
42 import android.telephony.CarrierConfigManager;
43 import android.telephony.CellLocation;
44 import android.telephony.PhoneNumberUtils;
45 import android.telephony.ServiceState;
46 import android.telephony.SubscriptionManager;
47 import android.telephony.TelephonyManager;
48 
49 import android.telephony.cdma.CdmaCellLocation;
50 import android.text.TextUtils;
51 import android.telephony.Rlog;
52 import android.util.Log;
53 
54 import com.android.ims.ImsManager;
55 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
56 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
57 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
58 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
59 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
60 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
61 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
62 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
63 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
64 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
65 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
66 
67 import com.android.internal.annotations.VisibleForTesting;
68 import com.android.internal.telephony.cdma.CdmaMmiCode;
69 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
70 import com.android.internal.telephony.cdma.EriManager;
71 import com.android.internal.telephony.dataconnection.DcTracker;
72 import com.android.internal.telephony.gsm.GsmMmiCode;
73 import com.android.internal.telephony.gsm.SuppServiceNotification;
74 import com.android.internal.telephony.test.SimulatedRadioControl;
75 import com.android.internal.telephony.uicc.IccCardProxy;
76 import com.android.internal.telephony.uicc.IccException;
77 import com.android.internal.telephony.uicc.IccRecords;
78 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
79 import com.android.internal.telephony.uicc.RuimRecords;
80 import com.android.internal.telephony.uicc.SIMRecords;
81 import com.android.internal.telephony.uicc.UiccCard;
82 import com.android.internal.telephony.uicc.UiccCardApplication;
83 import com.android.internal.telephony.uicc.UiccController;
84 import com.android.internal.telephony.uicc.IsimRecords;
85 import com.android.internal.telephony.uicc.IsimUiccRecords;
86 
87 import java.io.FileDescriptor;
88 import java.io.PrintWriter;
89 import java.util.ArrayList;
90 import java.util.List;
91 import java.util.regex.Matcher;
92 import java.util.regex.Pattern;
93 
94 
95 /**
96  * {@hide}
97  */
98 public class GsmCdmaPhone extends Phone {
99     // NOTE that LOG_TAG here is "GsmCdma", which means that log messages
100     // from this file will go into the radio log rather than the main
101     // log.  (Use "adb logcat -b radio" to see them.)
102     public static final String LOG_TAG = "GsmCdmaPhone";
103     private static final boolean DBG = true;
104     private static final boolean VDBG = false; /* STOPSHIP if true */
105 
106     //GSM
107     // Key used to read/write voice mail number
108     private static final String VM_NUMBER = "vm_number_key";
109     // Key used to read/write the SIM IMSI used for storing the voice mail
110     private static final String VM_SIM_IMSI = "vm_sim_imsi_key";
111     /** List of Registrants to receive Supplementary Service Notifications. */
112     private RegistrantList mSsnRegistrants = new RegistrantList();
113 
114     //CDMA
115     // Default Emergency Callback Mode exit timer
116     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
117     private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
118     public static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
119     public static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
120     private CdmaSubscriptionSourceManager mCdmaSSM;
121     public int mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
122     public EriManager mEriManager;
123     private PowerManager.WakeLock mWakeLock;
124     // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
125     private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
126     // mEcmExitRespRegistrant is informed after the phone has been exited
127     //the emergency callback mode
128     //keep track of if phone is in emergency callback mode
129     private boolean mIsPhoneInEcmState;
130     private Registrant mEcmExitRespRegistrant;
131     private String mEsn;
132     private String mMeid;
133     // string to define how the carrier specifies its own ota sp number
134     private String mCarrierOtaSpNumSchema;
135     // A runnable which is used to automatically exit from Ecm after a period of time.
136     private Runnable mExitEcmRunnable = new Runnable() {
137         @Override
138         public void run() {
139             exitEmergencyCallbackMode();
140         }
141     };
142     public static final String PROPERTY_CDMA_HOME_OPERATOR_NUMERIC =
143             "ro.cdma.home.operator.numeric";
144 
145     //CDMALTE
146     /** PHONE_TYPE_CDMA_LTE in addition to RuimRecords needs access to SIMRecords and
147      * IsimUiccRecords
148      */
149     private SIMRecords mSimRecords;
150 
151     //Common
152     // Instance Variables
153     private IsimUiccRecords mIsimUiccRecords;
154     public GsmCdmaCallTracker mCT;
155     public ServiceStateTracker mSST;
156     private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
157     private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
158 
159     private int mPrecisePhoneType;
160 
161     // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
162     private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
163 
164     private String mImei;
165     private String mImeiSv;
166     private String mVmNumber;
167 
168     // Create Cfu (Call forward unconditional) so that dialing number &
169     // mOnComplete (Message object passed by client) can be packed &
170     // given as a single Cfu object as user data to RIL.
171     private static class Cfu {
172         final String mSetCfNumber;
173         final Message mOnComplete;
174 
Cfu(String cfNumber, Message onComplete)175         Cfu(String cfNumber, Message onComplete) {
176             mSetCfNumber = cfNumber;
177             mOnComplete = onComplete;
178         }
179     }
180 
181     private IccSmsInterfaceManager mIccSmsInterfaceManager;
182     private IccCardProxy mIccCardProxy;
183 
184     private boolean mResetModemOnRadioTechnologyChange = false;
185 
186     private int mRilVersion;
187     private boolean mBroadcastEmergencyCallStateChanges = false;
188     // flag to indicate if emergency call end broadcast should be sent
189     boolean mSendEmergencyCallEnd = true;
190 
191     // Constructors
192 
GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory)193     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId,
194                         int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) {
195         this(context, ci, notifier, false, phoneId, precisePhoneType, telephonyComponentFactory);
196     }
197 
GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory)198     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
199                         boolean unitTestMode, int phoneId, int precisePhoneType,
200                         TelephonyComponentFactory telephonyComponentFactory) {
201         super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA",
202                 notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory);
203 
204         // phone type needs to be set before other initialization as other objects rely on it
205         mPrecisePhoneType = precisePhoneType;
206         initOnce(ci);
207         initRatSpecific(precisePhoneType);
208         mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
209         // DcTracker uses SST so needs to be created after it is instantiated
210         mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
211         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
212         logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
213     }
214 
215     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
216         @Override
217         public void onReceive(Context context, Intent intent) {
218             Rlog.d(LOG_TAG, "mBroadcastReceiver: action " + intent.getAction());
219             if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
220                 sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED));
221             }
222         }
223     };
224 
initOnce(CommandsInterface ci)225     private void initOnce(CommandsInterface ci) {
226         if (ci instanceof SimulatedRadioControl) {
227             mSimulatedRadioControl = (SimulatedRadioControl) ci;
228         }
229 
230         mCT = mTelephonyComponentFactory.makeGsmCdmaCallTracker(this);
231         mIccPhoneBookIntManager = mTelephonyComponentFactory.makeIccPhoneBookInterfaceManager(this);
232         PowerManager pm
233                 = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
234         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
235         mIccSmsInterfaceManager = mTelephonyComponentFactory.makeIccSmsInterfaceManager(this);
236         mIccCardProxy = mTelephonyComponentFactory.makeIccCardProxy(mContext, mCi, mPhoneId);
237 
238         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
239         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
240         mCi.registerForOn(this, EVENT_RADIO_ON, null);
241         mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
242 
243         //GSM
244         mCi.setOnUSSD(this, EVENT_USSD, null);
245         mCi.setOnSs(this, EVENT_SS, null);
246 
247         //CDMA
248         mCdmaSSM = mTelephonyComponentFactory.getCdmaSubscriptionSourceManagerInstance(mContext,
249                 mCi, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
250         mEriManager = mTelephonyComponentFactory.makeEriManager(this, mContext,
251                 EriManager.ERI_FROM_XML);
252         mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
253         mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE,
254                 null);
255         // get the string that specifies the carrier OTA Sp number
256         mCarrierOtaSpNumSchema = TelephonyManager.from(mContext).getOtaSpNumberSchemaForPhone(
257                 getPhoneId(), "");
258 
259         mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(
260                 TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);
261 
262         mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
263         mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
264         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
265                 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
266     }
267 
initRatSpecific(int precisePhoneType)268     private void initRatSpecific(int precisePhoneType) {
269         mPendingMMIs.clear();
270         mIccPhoneBookIntManager.updateIccRecords(null);
271         mEsn = null;
272         mMeid = null;
273 
274         mPrecisePhoneType = precisePhoneType;
275 
276         TelephonyManager tm = TelephonyManager.from(mContext);
277         if (isPhoneTypeGsm()) {
278             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
279             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_GSM);
280             mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
281         } else {
282             mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
283             // This is needed to handle phone process crashes
284             String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
285             mIsPhoneInEcmState = inEcm.equals("true");
286             if (mIsPhoneInEcmState) {
287                 // Send a message which will invoke handleExitEmergencyCallbackMode
288                 mCi.exitEmergencyCallbackMode(
289                         obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
290             }
291 
292             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
293             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_CDMA);
294             mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
295             // Sets operator properties by retrieving from build-time system property
296             String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
297             String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
298             logd("init: operatorAlpha='" + operatorAlpha
299                     + "' operatorNumeric='" + operatorNumeric + "'");
300             if (mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP) ==
301                     null || isPhoneTypeCdmaLte()) {
302                 if (!TextUtils.isEmpty(operatorAlpha)) {
303                     logd("init: set 'gsm.sim.operator.alpha' to operator='" + operatorAlpha + "'");
304                     tm.setSimOperatorNameForPhone(mPhoneId, operatorAlpha);
305                 }
306                 if (!TextUtils.isEmpty(operatorNumeric)) {
307                     logd("init: set 'gsm.sim.operator.numeric' to operator='" + operatorNumeric +
308                             "'");
309                     logd("update icc_operator_numeric=" + operatorNumeric);
310                     tm.setSimOperatorNumericForPhone(mPhoneId, operatorNumeric);
311 
312                     SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId());
313                     // Sets iso country property by retrieving from build-time system property
314                     setIsoCountryProperty(operatorNumeric);
315                     // Updates MCC MNC device configuration information
316                     logd("update mccmnc=" + operatorNumeric);
317                     MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
318                 }
319             }
320 
321             // Sets current entry in the telephony carrier table
322             updateCurrentCarrierInProvider(operatorNumeric);
323         }
324     }
325 
326     //CDMA
327     /**
328      * Sets PROPERTY_ICC_OPERATOR_ISO_COUNTRY property
329      *
330      */
setIsoCountryProperty(String operatorNumeric)331     private void setIsoCountryProperty(String operatorNumeric) {
332         TelephonyManager tm = TelephonyManager.from(mContext);
333         if (TextUtils.isEmpty(operatorNumeric)) {
334             logd("setIsoCountryProperty: clear 'gsm.sim.operator.iso-country'");
335             tm.setSimCountryIsoForPhone(mPhoneId, "");
336         } else {
337             String iso = "";
338             try {
339                 iso = MccTable.countryCodeForMcc(Integer.parseInt(
340                         operatorNumeric.substring(0,3)));
341             } catch (NumberFormatException ex) {
342                 Rlog.e(LOG_TAG, "setIsoCountryProperty: countryCodeForMcc error", ex);
343             } catch (StringIndexOutOfBoundsException ex) {
344                 Rlog.e(LOG_TAG, "setIsoCountryProperty: countryCodeForMcc error", ex);
345             }
346 
347             logd("setIsoCountryProperty: set 'gsm.sim.operator.iso-country' to iso=" + iso);
348             tm.setSimCountryIsoForPhone(mPhoneId, iso);
349         }
350     }
351 
isPhoneTypeGsm()352     public boolean isPhoneTypeGsm() {
353         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM;
354     }
355 
isPhoneTypeCdma()356     public boolean isPhoneTypeCdma() {
357         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA;
358     }
359 
isPhoneTypeCdmaLte()360     public boolean isPhoneTypeCdmaLte() {
361         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA_LTE;
362     }
363 
switchPhoneType(int precisePhoneType)364     private void switchPhoneType(int precisePhoneType) {
365         removeCallbacks(mExitEcmRunnable);
366 
367         initRatSpecific(precisePhoneType);
368 
369         mSST.updatePhoneType();
370         setPhoneName(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA");
371         onUpdateIccAvailability();
372         mCT.updatePhoneType();
373 
374         CommandsInterface.RadioState radioState = mCi.getRadioState();
375         if (radioState.isAvailable()) {
376             handleRadioAvailable();
377             if (radioState.isOn()) {
378                 handleRadioOn();
379             }
380         }
381         if (!radioState.isAvailable() || !radioState.isOn()) {
382             handleRadioOffOrNotAvailable();
383         }
384     }
385 
386     @Override
finalize()387     protected void finalize() {
388         if(DBG) logd("GsmCdmaPhone finalized");
389         if (mWakeLock.isHeld()) {
390             Rlog.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
391             mWakeLock.release();
392         }
393     }
394 
395     @Override
getServiceState()396     public ServiceState getServiceState() {
397         if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) {
398             if (mImsPhone != null) {
399                 return ServiceState.mergeServiceStates(
400                         (mSST == null) ? new ServiceState() : mSST.mSS,
401                         mImsPhone.getServiceState());
402             }
403         }
404 
405         if (mSST != null) {
406             return mSST.mSS;
407         } else {
408             // avoid potential NPE in EmergencyCallHelper during Phone switch
409             return new ServiceState();
410         }
411     }
412 
413     @Override
getCellLocation()414     public CellLocation getCellLocation() {
415         if (isPhoneTypeGsm()) {
416             return mSST.getCellLocation();
417         } else {
418             CdmaCellLocation loc = (CdmaCellLocation)mSST.mCellLoc;
419 
420             int mode = Settings.Secure.getInt(getContext().getContentResolver(),
421                     Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
422             if (mode == Settings.Secure.LOCATION_MODE_OFF) {
423                 // clear lat/long values for location privacy
424                 CdmaCellLocation privateLoc = new CdmaCellLocation();
425                 privateLoc.setCellLocationData(loc.getBaseStationId(),
426                         CdmaCellLocation.INVALID_LAT_LONG,
427                         CdmaCellLocation.INVALID_LAT_LONG,
428                         loc.getSystemId(), loc.getNetworkId());
429                 loc = privateLoc;
430             }
431             return loc;
432         }
433     }
434 
435     @Override
getState()436     public PhoneConstants.State getState() {
437         if (mImsPhone != null) {
438             PhoneConstants.State imsState = mImsPhone.getState();
439             if (imsState != PhoneConstants.State.IDLE) {
440                 return imsState;
441             }
442         }
443 
444         return mCT.mState;
445     }
446 
447     @Override
getPhoneType()448     public int getPhoneType() {
449         if (mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM) {
450             return PhoneConstants.PHONE_TYPE_GSM;
451         } else {
452             return PhoneConstants.PHONE_TYPE_CDMA;
453         }
454     }
455 
456     @Override
getServiceStateTracker()457     public ServiceStateTracker getServiceStateTracker() {
458         return mSST;
459     }
460 
461     @Override
getCallTracker()462     public CallTracker getCallTracker() {
463         return mCT;
464     }
465 
466     @Override
updateVoiceMail()467     public void updateVoiceMail() {
468         if (isPhoneTypeGsm()) {
469             int countVoiceMessages = 0;
470             IccRecords r = mIccRecords.get();
471             if (r != null) {
472                 // get voice mail count from SIM
473                 countVoiceMessages = r.getVoiceMessageCount();
474             }
475             int countVoiceMessagesStored = getStoredVoiceMessageCount();
476             if (countVoiceMessages == -1 && countVoiceMessagesStored != 0) {
477                 countVoiceMessages = countVoiceMessagesStored;
478             }
479             logd("updateVoiceMail countVoiceMessages = " + countVoiceMessages
480                     + " subId " + getSubId());
481             setVoiceMessageCount(countVoiceMessages);
482         } else {
483             setVoiceMessageCount(getStoredVoiceMessageCount());
484         }
485     }
486 
487     @Override
488     public List<? extends MmiCode>
getPendingMmiCodes()489     getPendingMmiCodes() {
490         return mPendingMMIs;
491     }
492 
493     @Override
getDataConnectionState(String apnType)494     public PhoneConstants.DataState getDataConnectionState(String apnType) {
495         PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED;
496 
497         if (mSST == null) {
498             // Radio Technology Change is ongoning, dispose() and removeReferences() have
499             // already been called
500 
501             ret = PhoneConstants.DataState.DISCONNECTED;
502         } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE
503                 && (isPhoneTypeCdma() ||
504                 (isPhoneTypeGsm() && !apnType.equals(PhoneConstants.APN_TYPE_EMERGENCY)))) {
505             // If we're out of service, open TCP sockets may still work
506             // but no data will flow
507 
508             // Emergency APN is available even in Out Of Service
509             // Pass the actual State of EPDN
510 
511             ret = PhoneConstants.DataState.DISCONNECTED;
512         } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */
513             switch (mDcTracker.getState(apnType)) {
514                 case RETRYING:
515                 case FAILED:
516                 case IDLE:
517                     ret = PhoneConstants.DataState.DISCONNECTED;
518                 break;
519 
520                 case CONNECTED:
521                 case DISCONNECTING:
522                     if ( mCT.mState != PhoneConstants.State.IDLE
523                             && !mSST.isConcurrentVoiceAndDataAllowed()) {
524                         ret = PhoneConstants.DataState.SUSPENDED;
525                     } else {
526                         ret = PhoneConstants.DataState.CONNECTED;
527                     }
528                 break;
529 
530                 case CONNECTING:
531                 case SCANNING:
532                     ret = PhoneConstants.DataState.CONNECTING;
533                 break;
534             }
535         }
536 
537         logd("getDataConnectionState apnType=" + apnType + " ret=" + ret);
538         return ret;
539     }
540 
541     @Override
getDataActivityState()542     public DataActivityState getDataActivityState() {
543         DataActivityState ret = DataActivityState.NONE;
544 
545         if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
546             switch (mDcTracker.getActivity()) {
547                 case DATAIN:
548                     ret = DataActivityState.DATAIN;
549                 break;
550 
551                 case DATAOUT:
552                     ret = DataActivityState.DATAOUT;
553                 break;
554 
555                 case DATAINANDOUT:
556                     ret = DataActivityState.DATAINANDOUT;
557                 break;
558 
559                 case DORMANT:
560                     ret = DataActivityState.DORMANT;
561                 break;
562 
563                 default:
564                     ret = DataActivityState.NONE;
565                 break;
566             }
567         }
568 
569         return ret;
570     }
571 
572     /**
573      * Notify any interested party of a Phone state change
574      * {@link com.android.internal.telephony.PhoneConstants.State}
575      */
notifyPhoneStateChanged()576     public void notifyPhoneStateChanged() {
577         mNotifier.notifyPhoneState(this);
578     }
579 
580     /**
581      * Notify registrants of a change in the call state. This notifies changes in
582      * {@link com.android.internal.telephony.Call.State}. Use this when changes
583      * in the precise call state are needed, else use notifyPhoneStateChanged.
584      */
notifyPreciseCallStateChanged()585     public void notifyPreciseCallStateChanged() {
586         /* we'd love it if this was package-scoped*/
587         super.notifyPreciseCallStateChangedP();
588     }
589 
notifyNewRingingConnection(Connection c)590     public void notifyNewRingingConnection(Connection c) {
591         super.notifyNewRingingConnectionP(c);
592     }
593 
notifyDisconnect(Connection cn)594     public void notifyDisconnect(Connection cn) {
595         mDisconnectRegistrants.notifyResult(cn);
596 
597         mNotifier.notifyDisconnectCause(cn.getDisconnectCause(), cn.getPreciseDisconnectCause());
598     }
599 
notifyUnknownConnection(Connection cn)600     public void notifyUnknownConnection(Connection cn) {
601         super.notifyUnknownConnectionP(cn);
602     }
603 
604     @Override
isInEmergencyCall()605     public boolean isInEmergencyCall() {
606         if (isPhoneTypeGsm()) {
607             return false;
608         } else {
609             return mCT.isInEmergencyCall();
610         }
611     }
612 
613     @Override
setIsInEmergencyCall()614     protected void setIsInEmergencyCall() {
615         if (!isPhoneTypeGsm()) {
616             mCT.setIsInEmergencyCall();
617         }
618     }
619 
620     @Override
isInEcm()621     public boolean isInEcm() {
622         if (isPhoneTypeGsm()) {
623             return false;
624         } else {
625             return mIsPhoneInEcmState;
626         }
627     }
628 
629     //CDMA
sendEmergencyCallbackModeChange()630     private void sendEmergencyCallbackModeChange(){
631         //Send an Intent
632         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
633         intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
634         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
635         ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
636         if (DBG) logd("sendEmergencyCallbackModeChange");
637     }
638 
639     @Override
sendEmergencyCallStateChange(boolean callActive)640     public void sendEmergencyCallStateChange(boolean callActive) {
641         if (mBroadcastEmergencyCallStateChanges) {
642             if (callActive &&
643                     getServiceState().getRilDataRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
644                 // if emergency call is started while on iwlan, do not send the start or end
645                 // broadcast
646                 mSendEmergencyCallEnd = false;
647                 if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: not sending call start " +
648                         "intent as voice tech is IWLAN");
649             } else if (callActive || mSendEmergencyCallEnd) {
650                 Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
651                 intent.putExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, callActive);
652                 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
653                 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
654                 if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange");
655             } else {
656                 if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: not sending call end " +
657                         "intent as start was not sent");
658                 mSendEmergencyCallEnd = true;
659             }
660         }
661     }
662 
663     @Override
setBroadcastEmergencyCallStateChanges(boolean broadcast)664     public void setBroadcastEmergencyCallStateChanges(boolean broadcast) {
665         mBroadcastEmergencyCallStateChanges = broadcast;
666     }
667 
notifySuppServiceFailed(SuppService code)668     public void notifySuppServiceFailed(SuppService code) {
669         mSuppServiceFailedRegistrants.notifyResult(code);
670     }
671 
notifyServiceStateChanged(ServiceState ss)672     public void notifyServiceStateChanged(ServiceState ss) {
673         super.notifyServiceStateChangedP(ss);
674     }
675 
notifyLocationChanged()676     public void notifyLocationChanged() {
677         mNotifier.notifyCellLocation(this);
678     }
679 
680     @Override
notifyCallForwardingIndicator()681     public void notifyCallForwardingIndicator() {
682         mNotifier.notifyCallForwardingChanged(this);
683     }
684 
685     // override for allowing access from other classes of this package
686     /**
687      * {@inheritDoc}
688      */
689     @Override
setSystemProperty(String property, String value)690     public void setSystemProperty(String property, String value) {
691         if (getUnitTestMode()) {
692             return;
693         }
694         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
695             TelephonyManager.setTelephonyProperty(mPhoneId, property, value);
696         } else {
697             super.setSystemProperty(property, value);
698         }
699     }
700 
701     @Override
registerForSuppServiceNotification( Handler h, int what, Object obj)702     public void registerForSuppServiceNotification(
703             Handler h, int what, Object obj) {
704         mSsnRegistrants.addUnique(h, what, obj);
705         if (mSsnRegistrants.size() == 1) mCi.setSuppServiceNotifications(true, null);
706     }
707 
708     @Override
unregisterForSuppServiceNotification(Handler h)709     public void unregisterForSuppServiceNotification(Handler h) {
710         mSsnRegistrants.remove(h);
711         if (mSsnRegistrants.size() == 0) mCi.setSuppServiceNotifications(false, null);
712     }
713 
714     @Override
registerForSimRecordsLoaded(Handler h, int what, Object obj)715     public void registerForSimRecordsLoaded(Handler h, int what, Object obj) {
716         mSimRecordsLoadedRegistrants.addUnique(h, what, obj);
717     }
718 
719     @Override
unregisterForSimRecordsLoaded(Handler h)720     public void unregisterForSimRecordsLoaded(Handler h) {
721         mSimRecordsLoadedRegistrants.remove(h);
722     }
723 
724     @Override
acceptCall(int videoState)725     public void acceptCall(int videoState) throws CallStateException {
726         Phone imsPhone = mImsPhone;
727         if ( imsPhone != null && imsPhone.getRingingCall().isRinging() ) {
728             imsPhone.acceptCall(videoState);
729         } else {
730             mCT.acceptCall();
731         }
732     }
733 
734     @Override
rejectCall()735     public void rejectCall() throws CallStateException {
736         mCT.rejectCall();
737     }
738 
739     @Override
switchHoldingAndActive()740     public void switchHoldingAndActive() throws CallStateException {
741         mCT.switchWaitingOrHoldingAndActive();
742     }
743 
744     @Override
getIccSerialNumber()745     public String getIccSerialNumber() {
746         IccRecords r = mIccRecords.get();
747         if (!isPhoneTypeGsm() && r == null) {
748             // to get ICCID form SIMRecords because it is on MF.
749             r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP);
750         }
751         return (r != null) ? r.getIccId() : null;
752     }
753 
754     @Override
getFullIccSerialNumber()755     public String getFullIccSerialNumber() {
756         IccRecords r = mIccRecords.get();
757         if (!isPhoneTypeGsm() && r == null) {
758             // to get ICCID form SIMRecords because it is on MF.
759             r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP);
760         }
761         return (r != null) ? r.getFullIccId() : null;
762     }
763 
764     @Override
canConference()765     public boolean canConference() {
766         if (mImsPhone != null && mImsPhone.canConference()) {
767             return true;
768         }
769         if (isPhoneTypeGsm()) {
770             return mCT.canConference();
771         } else {
772             loge("canConference: not possible in CDMA");
773             return false;
774         }
775     }
776 
777     @Override
conference()778     public void conference() {
779         if (mImsPhone != null && mImsPhone.canConference()) {
780             logd("conference() - delegated to IMS phone");
781             try {
782                 mImsPhone.conference();
783             } catch (CallStateException e) {
784                 loge(e.toString());
785             }
786             return;
787         }
788         if (isPhoneTypeGsm()) {
789             mCT.conference();
790         } else {
791             // three way calls in CDMA will be handled by feature codes
792             loge("conference: not possible in CDMA");
793         }
794     }
795 
796     @Override
enableEnhancedVoicePrivacy(boolean enable, Message onComplete)797     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
798         if (isPhoneTypeGsm()) {
799             loge("enableEnhancedVoicePrivacy: not expected on GSM");
800         } else {
801             mCi.setPreferredVoicePrivacy(enable, onComplete);
802         }
803     }
804 
805     @Override
getEnhancedVoicePrivacy(Message onComplete)806     public void getEnhancedVoicePrivacy(Message onComplete) {
807         if (isPhoneTypeGsm()) {
808             loge("getEnhancedVoicePrivacy: not expected on GSM");
809         } else {
810             mCi.getPreferredVoicePrivacy(onComplete);
811         }
812     }
813 
814     @Override
clearDisconnected()815     public void clearDisconnected() {
816         mCT.clearDisconnected();
817     }
818 
819     @Override
canTransfer()820     public boolean canTransfer() {
821         if (isPhoneTypeGsm()) {
822             return mCT.canTransfer();
823         } else {
824             loge("canTransfer: not possible in CDMA");
825             return false;
826         }
827     }
828 
829     @Override
explicitCallTransfer()830     public void explicitCallTransfer() {
831         if (isPhoneTypeGsm()) {
832             mCT.explicitCallTransfer();
833         } else {
834             loge("explicitCallTransfer: not possible in CDMA");
835         }
836     }
837 
838     @Override
getForegroundCall()839     public GsmCdmaCall getForegroundCall() {
840         return mCT.mForegroundCall;
841     }
842 
843     @Override
getBackgroundCall()844     public GsmCdmaCall getBackgroundCall() {
845         return mCT.mBackgroundCall;
846     }
847 
848     @Override
getRingingCall()849     public Call getRingingCall() {
850         Phone imsPhone = mImsPhone;
851         // It returns the ringing call of ImsPhone if the ringing call of GSMPhone isn't ringing.
852         // In CallManager.registerPhone(), it always registers ringing call of ImsPhone, because
853         // the ringing call of GSMPhone isn't ringing. Consequently, it can't answer GSM call
854         // successfully by invoking TelephonyManager.answerRingingCall() since the implementation
855         // in PhoneInterfaceManager.answerRingingCallInternal() could not get the correct ringing
856         // call from CallManager. So we check the ringing call state of imsPhone first as
857         // accpetCall() does.
858         if ( imsPhone != null && imsPhone.getRingingCall().isRinging()) {
859             return imsPhone.getRingingCall();
860         }
861         return mCT.mRingingCall;
862     }
863 
handleCallDeflectionIncallSupplementaryService( String dialString)864     private boolean handleCallDeflectionIncallSupplementaryService(
865             String dialString) {
866         if (dialString.length() > 1) {
867             return false;
868         }
869 
870         if (getRingingCall().getState() != GsmCdmaCall.State.IDLE) {
871             if (DBG) logd("MmiCode 0: rejectCall");
872             try {
873                 mCT.rejectCall();
874             } catch (CallStateException e) {
875                 if (DBG) Rlog.d(LOG_TAG,
876                         "reject failed", e);
877                 notifySuppServiceFailed(Phone.SuppService.REJECT);
878             }
879         } else if (getBackgroundCall().getState() != GsmCdmaCall.State.IDLE) {
880             if (DBG) logd("MmiCode 0: hangupWaitingOrBackground");
881             mCT.hangupWaitingOrBackground();
882         }
883 
884         return true;
885     }
886 
887     //GSM
handleCallWaitingIncallSupplementaryService(String dialString)888     private boolean handleCallWaitingIncallSupplementaryService(String dialString) {
889         int len = dialString.length();
890 
891         if (len > 2) {
892             return false;
893         }
894 
895         GsmCdmaCall call = getForegroundCall();
896 
897         try {
898             if (len > 1) {
899                 char ch = dialString.charAt(1);
900                 int callIndex = ch - '0';
901 
902                 if (callIndex >= 1 && callIndex <= GsmCdmaCallTracker.MAX_CONNECTIONS_GSM) {
903                     if (DBG) logd("MmiCode 1: hangupConnectionByIndex " + callIndex);
904                     mCT.hangupConnectionByIndex(call, callIndex);
905                 }
906             } else {
907                 if (call.getState() != GsmCdmaCall.State.IDLE) {
908                     if (DBG) logd("MmiCode 1: hangup foreground");
909                     //mCT.hangupForegroundResumeBackground();
910                     mCT.hangup(call);
911                 } else {
912                     if (DBG) logd("MmiCode 1: switchWaitingOrHoldingAndActive");
913                     mCT.switchWaitingOrHoldingAndActive();
914                 }
915             }
916         } catch (CallStateException e) {
917             if (DBG) Rlog.d(LOG_TAG,
918                     "hangup failed", e);
919             notifySuppServiceFailed(Phone.SuppService.HANGUP);
920         }
921 
922         return true;
923     }
924 
handleCallHoldIncallSupplementaryService(String dialString)925     private boolean handleCallHoldIncallSupplementaryService(String dialString) {
926         int len = dialString.length();
927 
928         if (len > 2) {
929             return false;
930         }
931 
932         GsmCdmaCall call = getForegroundCall();
933 
934         if (len > 1) {
935             try {
936                 char ch = dialString.charAt(1);
937                 int callIndex = ch - '0';
938                 GsmCdmaConnection conn = mCT.getConnectionByIndex(call, callIndex);
939 
940                 // GsmCdma index starts at 1, up to 5 connections in a call,
941                 if (conn != null && callIndex >= 1 && callIndex <= GsmCdmaCallTracker.MAX_CONNECTIONS_GSM) {
942                     if (DBG) logd("MmiCode 2: separate call " + callIndex);
943                     mCT.separate(conn);
944                 } else {
945                     if (DBG) logd("separate: invalid call index " + callIndex);
946                     notifySuppServiceFailed(Phone.SuppService.SEPARATE);
947                 }
948             } catch (CallStateException e) {
949                 if (DBG) Rlog.d(LOG_TAG, "separate failed", e);
950                 notifySuppServiceFailed(Phone.SuppService.SEPARATE);
951             }
952         } else {
953             try {
954                 if (getRingingCall().getState() != GsmCdmaCall.State.IDLE) {
955                     if (DBG) logd("MmiCode 2: accept ringing call");
956                     mCT.acceptCall();
957                 } else {
958                     if (DBG) logd("MmiCode 2: switchWaitingOrHoldingAndActive");
959                     mCT.switchWaitingOrHoldingAndActive();
960                 }
961             } catch (CallStateException e) {
962                 if (DBG) Rlog.d(LOG_TAG, "switch failed", e);
963                 notifySuppServiceFailed(Phone.SuppService.SWITCH);
964             }
965         }
966 
967         return true;
968     }
969 
handleMultipartyIncallSupplementaryService(String dialString)970     private boolean handleMultipartyIncallSupplementaryService(String dialString) {
971         if (dialString.length() > 1) {
972             return false;
973         }
974 
975         if (DBG) logd("MmiCode 3: merge calls");
976         conference();
977         return true;
978     }
979 
handleEctIncallSupplementaryService(String dialString)980     private boolean handleEctIncallSupplementaryService(String dialString) {
981 
982         int len = dialString.length();
983 
984         if (len != 1) {
985             return false;
986         }
987 
988         if (DBG) logd("MmiCode 4: explicit call transfer");
989         explicitCallTransfer();
990         return true;
991     }
992 
handleCcbsIncallSupplementaryService(String dialString)993     private boolean handleCcbsIncallSupplementaryService(String dialString) {
994         if (dialString.length() > 1) {
995             return false;
996         }
997 
998         Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!");
999         // Treat it as an "unknown" service.
1000         notifySuppServiceFailed(Phone.SuppService.UNKNOWN);
1001         return true;
1002     }
1003 
1004     @Override
handleInCallMmiCommands(String dialString)1005     public boolean handleInCallMmiCommands(String dialString) throws CallStateException {
1006         if (!isPhoneTypeGsm()) {
1007             loge("method handleInCallMmiCommands is NOT supported in CDMA!");
1008             return false;
1009         }
1010 
1011         Phone imsPhone = mImsPhone;
1012         if (imsPhone != null
1013                 && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) {
1014             return imsPhone.handleInCallMmiCommands(dialString);
1015         }
1016 
1017         if (!isInCall()) {
1018             return false;
1019         }
1020 
1021         if (TextUtils.isEmpty(dialString)) {
1022             return false;
1023         }
1024 
1025         boolean result = false;
1026         char ch = dialString.charAt(0);
1027         switch (ch) {
1028             case '0':
1029                 result = handleCallDeflectionIncallSupplementaryService(dialString);
1030                 break;
1031             case '1':
1032                 result = handleCallWaitingIncallSupplementaryService(dialString);
1033                 break;
1034             case '2':
1035                 result = handleCallHoldIncallSupplementaryService(dialString);
1036                 break;
1037             case '3':
1038                 result = handleMultipartyIncallSupplementaryService(dialString);
1039                 break;
1040             case '4':
1041                 result = handleEctIncallSupplementaryService(dialString);
1042                 break;
1043             case '5':
1044                 result = handleCcbsIncallSupplementaryService(dialString);
1045                 break;
1046             default:
1047                 break;
1048         }
1049 
1050         return result;
1051     }
1052 
isInCall()1053     public boolean isInCall() {
1054         GsmCdmaCall.State foregroundCallState = getForegroundCall().getState();
1055         GsmCdmaCall.State backgroundCallState = getBackgroundCall().getState();
1056         GsmCdmaCall.State ringingCallState = getRingingCall().getState();
1057 
1058        return (foregroundCallState.isAlive() ||
1059                 backgroundCallState.isAlive() ||
1060                 ringingCallState.isAlive());
1061     }
1062 
1063     @Override
dial(String dialString, int videoState)1064     public Connection dial(String dialString, int videoState) throws CallStateException {
1065         return dial(dialString, null, videoState, null);
1066     }
1067 
1068     @Override
dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)1069     public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
1070             throws CallStateException {
1071         if (!isPhoneTypeGsm() && uusInfo != null) {
1072             throw new CallStateException("Sending UUS information NOT supported in CDMA!");
1073         }
1074 
1075         boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(dialString);
1076         Phone imsPhone = mImsPhone;
1077 
1078         CarrierConfigManager configManager =
1079                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1080         boolean alwaysTryImsForEmergencyCarrierConfig = configManager.getConfigForSubId(getSubId())
1081                 .getBoolean(CarrierConfigManager.KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL);
1082 
1083         boolean imsUseEnabled = isImsUseEnabled()
1084                  && imsPhone != null
1085                  && (imsPhone.isVolteEnabled() || imsPhone.isWifiCallingEnabled() ||
1086                  (imsPhone.isVideoEnabled() && VideoProfile.isVideo(videoState)))
1087                  && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
1088 
1089         boolean useImsForEmergency = imsPhone != null
1090                 && isEmergency
1091                 && alwaysTryImsForEmergencyCarrierConfig
1092                 && ImsManager.isNonTtyOrTtyOnVolteEnabled(mContext)
1093                 && (imsPhone.getServiceState().getState() != ServiceState.STATE_POWER_OFF);
1094 
1095         String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(PhoneNumberUtils.
1096                 stripSeparators(dialString));
1097         boolean isUt = (dialPart.startsWith("*") || dialPart.startsWith("#"))
1098                 && dialPart.endsWith("#");
1099 
1100         boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled();
1101 
1102         if (DBG) {
1103             logd("imsUseEnabled=" + imsUseEnabled
1104                     + ", useImsForEmergency=" + useImsForEmergency
1105                     + ", useImsForUt=" + useImsForUt
1106                     + ", isUt=" + isUt
1107                     + ", imsPhone=" + imsPhone
1108                     + ", imsPhone.isVolteEnabled()="
1109                     + ((imsPhone != null) ? imsPhone.isVolteEnabled() : "N/A")
1110                     + ", imsPhone.isVowifiEnabled()="
1111                     + ((imsPhone != null) ? imsPhone.isWifiCallingEnabled() : "N/A")
1112                     + ", imsPhone.isVideoEnabled()="
1113                     + ((imsPhone != null) ? imsPhone.isVideoEnabled() : "N/A")
1114                     + ", imsPhone.getServiceState().getState()="
1115                     + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A"));
1116         }
1117 
1118         Phone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mContext);
1119 
1120         if ((imsUseEnabled && (!isUt || useImsForUt)) || useImsForEmergency) {
1121             try {
1122                 if (DBG) logd("Trying IMS PS call");
1123                 return imsPhone.dial(dialString, uusInfo, videoState, intentExtras);
1124             } catch (CallStateException e) {
1125                 if (DBG) logd("IMS PS call exception " + e +
1126                         "imsUseEnabled =" + imsUseEnabled + ", imsPhone =" + imsPhone);
1127                 if (!Phone.CS_FALLBACK.equals(e.getMessage())) {
1128                     CallStateException ce = new CallStateException(e.getMessage());
1129                     ce.setStackTrace(e.getStackTrace());
1130                     throw ce;
1131                 }
1132             }
1133         }
1134 
1135         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE
1136                 && mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) {
1137             throw new CallStateException("cannot dial in current state");
1138         }
1139         if (DBG) logd("Trying (non-IMS) CS call");
1140 
1141         if (isPhoneTypeGsm()) {
1142             return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);
1143         } else {
1144             return dialInternal(dialString, null, videoState, intentExtras);
1145         }
1146     }
1147 
1148     @Override
dialInternal(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)1149     protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
1150                                       Bundle intentExtras)
1151             throws CallStateException {
1152 
1153         // Need to make sure dialString gets parsed properly
1154         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
1155 
1156         if (isPhoneTypeGsm()) {
1157             // handle in-call MMI first if applicable
1158             if (handleInCallMmiCommands(newDialString)) {
1159                 return null;
1160             }
1161 
1162             // Only look at the Network portion for mmi
1163             String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
1164             GsmMmiCode mmi =
1165                     GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
1166             if (DBG) logd("dialing w/ mmi '" + mmi + "'...");
1167 
1168             if (mmi == null) {
1169                 return mCT.dial(newDialString, uusInfo, intentExtras);
1170             } else if (mmi.isTemporaryModeCLIR()) {
1171                 return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
1172             } else {
1173                 mPendingMMIs.add(mmi);
1174                 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1175                 try {
1176                     mmi.processCode();
1177                 } catch (CallStateException e) {
1178                     //do nothing
1179                 }
1180 
1181                 // FIXME should this return null or something else?
1182                 return null;
1183             }
1184         } else {
1185             return mCT.dial(newDialString);
1186         }
1187     }
1188 
1189     @Override
handlePinMmi(String dialString)1190     public boolean handlePinMmi(String dialString) {
1191         MmiCode mmi;
1192         if (isPhoneTypeGsm()) {
1193             mmi = GsmMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
1194         } else {
1195             mmi = CdmaMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
1196         }
1197 
1198         if (mmi != null && mmi.isPinPukCommand()) {
1199             mPendingMMIs.add(mmi);
1200             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1201             try {
1202                 mmi.processCode();
1203             } catch (CallStateException e) {
1204                 //do nothing
1205             }
1206             return true;
1207         }
1208 
1209         loge("Mmi is null or unrecognized!");
1210         return false;
1211     }
1212 
1213     @Override
sendUssdResponse(String ussdMessge)1214     public void sendUssdResponse(String ussdMessge) {
1215         if (isPhoneTypeGsm()) {
1216             GsmMmiCode mmi = GsmMmiCode.newFromUssdUserInput(ussdMessge, this, mUiccApplication.get());
1217             mPendingMMIs.add(mmi);
1218             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1219             mmi.sendUssd(ussdMessge);
1220         } else {
1221             loge("sendUssdResponse: not possible in CDMA");
1222         }
1223     }
1224 
1225     @Override
sendDtmf(char c)1226     public void sendDtmf(char c) {
1227         if (!PhoneNumberUtils.is12Key(c)) {
1228             loge("sendDtmf called with invalid character '" + c + "'");
1229         } else {
1230             if (mCT.mState ==  PhoneConstants.State.OFFHOOK) {
1231                 mCi.sendDtmf(c, null);
1232             }
1233         }
1234     }
1235 
1236     @Override
startDtmf(char c)1237     public void startDtmf(char c) {
1238         if (!PhoneNumberUtils.is12Key(c)) {
1239             loge("startDtmf called with invalid character '" + c + "'");
1240         } else {
1241             mCi.startDtmf(c, null);
1242         }
1243     }
1244 
1245     @Override
stopDtmf()1246     public void stopDtmf() {
1247         mCi.stopDtmf(null);
1248     }
1249 
1250     @Override
sendBurstDtmf(String dtmfString, int on, int off, Message onComplete)1251     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
1252         if (isPhoneTypeGsm()) {
1253             loge("[GsmCdmaPhone] sendBurstDtmf() is a CDMA method");
1254         } else {
1255             boolean check = true;
1256             for (int itr = 0;itr < dtmfString.length(); itr++) {
1257                 if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
1258                     Rlog.e(LOG_TAG,
1259                             "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'");
1260                     check = false;
1261                     break;
1262                 }
1263             }
1264             if (mCT.mState == PhoneConstants.State.OFFHOOK && check) {
1265                 mCi.sendBurstDtmf(dtmfString, on, off, onComplete);
1266             }
1267         }
1268     }
1269 
1270     @Override
setRadioPower(boolean power)1271     public void setRadioPower(boolean power) {
1272         mSST.setRadioPower(power);
1273     }
1274 
storeVoiceMailNumber(String number)1275     private void storeVoiceMailNumber(String number) {
1276         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1277         SharedPreferences.Editor editor = sp.edit();
1278         if (isPhoneTypeGsm()) {
1279             editor.putString(VM_NUMBER + getPhoneId(), number);
1280             editor.apply();
1281             setVmSimImsi(getSubscriberId());
1282         } else {
1283             editor.putString(VM_NUMBER_CDMA + getPhoneId(), number);
1284             editor.apply();
1285         }
1286     }
1287 
1288     @Override
getVoiceMailNumber()1289     public String getVoiceMailNumber() {
1290         String number = null;
1291         if (isPhoneTypeGsm()) {
1292             // Read from the SIM. If its null, try reading from the shared preference area.
1293             IccRecords r = mIccRecords.get();
1294             number = (r != null) ? r.getVoiceMailNumber() : "";
1295             if (TextUtils.isEmpty(number)) {
1296                 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1297                 number = sp.getString(VM_NUMBER + getPhoneId(), null);
1298             }
1299         } else {
1300             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1301             number = sp.getString(VM_NUMBER_CDMA + getPhoneId(), null);
1302         }
1303 
1304         if (TextUtils.isEmpty(number)) {
1305             String[] listArray = getContext().getResources()
1306                 .getStringArray(com.android.internal.R.array.config_default_vm_number);
1307             if (listArray != null && listArray.length > 0) {
1308                 for (int i=0; i<listArray.length; i++) {
1309                     if (!TextUtils.isEmpty(listArray[i])) {
1310                         String[] defaultVMNumberArray = listArray[i].split(";");
1311                         if (defaultVMNumberArray != null && defaultVMNumberArray.length > 0) {
1312                             if (defaultVMNumberArray.length == 1) {
1313                                 number = defaultVMNumberArray[0];
1314                             } else if (defaultVMNumberArray.length == 2 &&
1315                                     !TextUtils.isEmpty(defaultVMNumberArray[1]) &&
1316                                     isMatchGid(defaultVMNumberArray[1])) {
1317                                 number = defaultVMNumberArray[0];
1318                                 break;
1319                             }
1320                         }
1321                     }
1322                 }
1323             }
1324         }
1325 
1326         if (!isPhoneTypeGsm() && TextUtils.isEmpty(number)) {
1327             // Read platform settings for dynamic voicemail number
1328             if (getContext().getResources().getBoolean(com.android.internal
1329                     .R.bool.config_telephony_use_own_number_for_voicemail)) {
1330                 number = getLine1Number();
1331             } else {
1332                 number = "*86";
1333             }
1334         }
1335 
1336         return number;
1337     }
1338 
getVmSimImsi()1339     private String getVmSimImsi() {
1340         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1341         return sp.getString(VM_SIM_IMSI + getPhoneId(), null);
1342     }
1343 
setVmSimImsi(String imsi)1344     private void setVmSimImsi(String imsi) {
1345         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1346         SharedPreferences.Editor editor = sp.edit();
1347         editor.putString(VM_SIM_IMSI + getPhoneId(), imsi);
1348         editor.apply();
1349     }
1350 
1351     @Override
getVoiceMailAlphaTag()1352     public String getVoiceMailAlphaTag() {
1353         String ret = "";
1354 
1355         if (isPhoneTypeGsm()) {
1356             IccRecords r = mIccRecords.get();
1357 
1358             ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
1359         }
1360 
1361         if (ret == null || ret.length() == 0) {
1362             return mContext.getText(
1363                 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
1364         }
1365 
1366         return ret;
1367     }
1368 
1369     @Override
getDeviceId()1370     public String getDeviceId() {
1371         if (isPhoneTypeGsm()) {
1372             return mImei;
1373         } else {
1374             CarrierConfigManager configManager = (CarrierConfigManager)
1375                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1376             boolean force_imei = configManager.getConfigForSubId(getSubId())
1377                     .getBoolean(CarrierConfigManager.KEY_FORCE_IMEI_BOOL);
1378             if (force_imei) return mImei;
1379 
1380             String id = getMeid();
1381             if ((id == null) || id.matches("^0*$")) {
1382                 loge("getDeviceId(): MEID is not initialized use ESN");
1383                 id = getEsn();
1384             }
1385             return id;
1386         }
1387     }
1388 
1389     @Override
getDeviceSvn()1390     public String getDeviceSvn() {
1391         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1392             return mImeiSv;
1393         } else {
1394             loge("getDeviceSvn(): return 0");
1395             return "0";
1396         }
1397     }
1398 
1399     @Override
getIsimRecords()1400     public IsimRecords getIsimRecords() {
1401         return mIsimUiccRecords;
1402     }
1403 
1404     @Override
getImei()1405     public String getImei() {
1406         return mImei;
1407     }
1408 
1409     @Override
getEsn()1410     public String getEsn() {
1411         if (isPhoneTypeGsm()) {
1412             loge("[GsmCdmaPhone] getEsn() is a CDMA method");
1413             return "0";
1414         } else {
1415             return mEsn;
1416         }
1417     }
1418 
1419     @Override
getMeid()1420     public String getMeid() {
1421         if (isPhoneTypeGsm()) {
1422             loge("[GsmCdmaPhone] getMeid() is a CDMA method");
1423             return "0";
1424         } else {
1425             return mMeid;
1426         }
1427     }
1428 
1429     @Override
getNai()1430     public String getNai() {
1431         IccRecords r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP2);
1432         if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
1433             Rlog.v(LOG_TAG, "IccRecords is " + r);
1434         }
1435         return (r != null) ? r.getNAI() : null;
1436     }
1437 
1438     @Override
getSubscriberId()1439     public String getSubscriberId() {
1440         if (isPhoneTypeGsm()) {
1441             IccRecords r = mIccRecords.get();
1442             return (r != null) ? r.getIMSI() : null;
1443         } else if (isPhoneTypeCdma()) {
1444             return mSST.getImsi();
1445         } else { //isPhoneTypeCdmaLte()
1446             return (mSimRecords != null) ? mSimRecords.getIMSI() : "";
1447         }
1448     }
1449 
1450     @Override
getGroupIdLevel1()1451     public String getGroupIdLevel1() {
1452         if (isPhoneTypeGsm()) {
1453             IccRecords r = mIccRecords.get();
1454             return (r != null) ? r.getGid1() : null;
1455         } else if (isPhoneTypeCdma()) {
1456             loge("GID1 is not available in CDMA");
1457             return null;
1458         } else { //isPhoneTypeCdmaLte()
1459             return (mSimRecords != null) ? mSimRecords.getGid1() : "";
1460         }
1461     }
1462 
1463     @Override
getGroupIdLevel2()1464     public String getGroupIdLevel2() {
1465         if (isPhoneTypeGsm()) {
1466             IccRecords r = mIccRecords.get();
1467             return (r != null) ? r.getGid2() : null;
1468         } else if (isPhoneTypeCdma()) {
1469             loge("GID2 is not available in CDMA");
1470             return null;
1471         } else { //isPhoneTypeCdmaLte()
1472             return (mSimRecords != null) ? mSimRecords.getGid2() : "";
1473         }
1474     }
1475 
1476     @Override
getLine1Number()1477     public String getLine1Number() {
1478         if (isPhoneTypeGsm()) {
1479             IccRecords r = mIccRecords.get();
1480             return (r != null) ? r.getMsisdnNumber() : null;
1481         } else {
1482             return mSST.getMdnNumber();
1483         }
1484     }
1485 
1486     @Override
getCdmaPrlVersion()1487     public String getCdmaPrlVersion() {
1488         return mSST.getPrlVersion();
1489     }
1490 
1491     @Override
getCdmaMin()1492     public String getCdmaMin() {
1493         return mSST.getCdmaMin();
1494     }
1495 
1496     @Override
isMinInfoReady()1497     public boolean isMinInfoReady() {
1498         return mSST.isMinInfoReady();
1499     }
1500 
1501     @Override
getMsisdn()1502     public String getMsisdn() {
1503         if (isPhoneTypeGsm()) {
1504             IccRecords r = mIccRecords.get();
1505             return (r != null) ? r.getMsisdnNumber() : null;
1506         } else if (isPhoneTypeCdmaLte()) {
1507             return (mSimRecords != null) ? mSimRecords.getMsisdnNumber() : null;
1508         } else {
1509             loge("getMsisdn: not expected on CDMA");
1510             return null;
1511         }
1512     }
1513 
1514     @Override
getLine1AlphaTag()1515     public String getLine1AlphaTag() {
1516         if (isPhoneTypeGsm()) {
1517             IccRecords r = mIccRecords.get();
1518             return (r != null) ? r.getMsisdnAlphaTag() : null;
1519         } else {
1520             loge("getLine1AlphaTag: not possible in CDMA");
1521             return null;
1522         }
1523     }
1524 
1525     @Override
setLine1Number(String alphaTag, String number, Message onComplete)1526     public boolean setLine1Number(String alphaTag, String number, Message onComplete) {
1527         if (isPhoneTypeGsm()) {
1528             IccRecords r = mIccRecords.get();
1529             if (r != null) {
1530                 r.setMsisdnNumber(alphaTag, number, onComplete);
1531                 return true;
1532             } else {
1533                 return false;
1534             }
1535         } else {
1536             loge("setLine1Number: not possible in CDMA");
1537             return false;
1538         }
1539     }
1540 
1541     @Override
setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete)1542     public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete) {
1543         Message resp;
1544         mVmNumber = voiceMailNumber;
1545         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
1546         IccRecords r = mIccRecords.get();
1547         if (r != null) {
1548             r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
1549         }
1550     }
1551 
isValidCommandInterfaceCFReason(int commandInterfaceCFReason)1552     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
1553         switch (commandInterfaceCFReason) {
1554             case CF_REASON_UNCONDITIONAL:
1555             case CF_REASON_BUSY:
1556             case CF_REASON_NO_REPLY:
1557             case CF_REASON_NOT_REACHABLE:
1558             case CF_REASON_ALL:
1559             case CF_REASON_ALL_CONDITIONAL:
1560                 return true;
1561             default:
1562                 return false;
1563         }
1564     }
1565 
1566     @Override
getSystemProperty(String property, String defValue)1567     public String getSystemProperty(String property, String defValue) {
1568         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1569             if (getUnitTestMode()) {
1570                 return null;
1571             }
1572             return TelephonyManager.getTelephonyProperty(mPhoneId, property, defValue);
1573         } else {
1574             return super.getSystemProperty(property, defValue);
1575         }
1576     }
1577 
isValidCommandInterfaceCFAction(int commandInterfaceCFAction)1578     private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
1579         switch (commandInterfaceCFAction) {
1580             case CF_ACTION_DISABLE:
1581             case CF_ACTION_ENABLE:
1582             case CF_ACTION_REGISTRATION:
1583             case CF_ACTION_ERASURE:
1584                 return true;
1585             default:
1586                 return false;
1587         }
1588     }
1589 
isCfEnable(int action)1590     private boolean isCfEnable(int action) {
1591         return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
1592     }
1593 
1594     @Override
getCallForwardingOption(int commandInterfaceCFReason, Message onComplete)1595     public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
1596         if (isPhoneTypeGsm()) {
1597             Phone imsPhone = mImsPhone;
1598             if ((imsPhone != null)
1599                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1600                     || imsPhone.isUtEnabled())) {
1601                 imsPhone.getCallForwardingOption(commandInterfaceCFReason, onComplete);
1602                 return;
1603             }
1604 
1605             if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
1606                 if (DBG) logd("requesting call forwarding query.");
1607                 Message resp;
1608                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1609                     resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
1610                 } else {
1611                     resp = onComplete;
1612                 }
1613                 mCi.queryCallForwardStatus(commandInterfaceCFReason, 0, null, resp);
1614             }
1615         } else {
1616             loge("getCallForwardingOption: not possible in CDMA");
1617         }
1618     }
1619 
1620     @Override
setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int timerSeconds, Message onComplete)1621     public void setCallForwardingOption(int commandInterfaceCFAction,
1622             int commandInterfaceCFReason,
1623             String dialingNumber,
1624             int timerSeconds,
1625             Message onComplete) {
1626         if (isPhoneTypeGsm()) {
1627             Phone imsPhone = mImsPhone;
1628             if ((imsPhone != null)
1629                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1630                     || imsPhone.isUtEnabled())) {
1631                 imsPhone.setCallForwardingOption(commandInterfaceCFAction,
1632                         commandInterfaceCFReason, dialingNumber, timerSeconds, onComplete);
1633                 return;
1634             }
1635 
1636             if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
1637                     (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
1638 
1639                 Message resp;
1640                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1641                     Cfu cfu = new Cfu(dialingNumber, onComplete);
1642                     resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
1643                             isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cfu);
1644                 } else {
1645                     resp = onComplete;
1646                 }
1647                 mCi.setCallForward(commandInterfaceCFAction,
1648                         commandInterfaceCFReason,
1649                         CommandsInterface.SERVICE_CLASS_VOICE,
1650                         dialingNumber,
1651                         timerSeconds,
1652                         resp);
1653             }
1654         } else {
1655             loge("setCallForwardingOption: not possible in CDMA");
1656         }
1657     }
1658 
1659     @Override
getOutgoingCallerIdDisplay(Message onComplete)1660     public void getOutgoingCallerIdDisplay(Message onComplete) {
1661         if (isPhoneTypeGsm()) {
1662             Phone imsPhone = mImsPhone;
1663             if ((imsPhone != null)
1664                     && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1665                 imsPhone.getOutgoingCallerIdDisplay(onComplete);
1666                 return;
1667             }
1668             mCi.getCLIR(onComplete);
1669         } else {
1670             loge("getOutgoingCallerIdDisplay: not possible in CDMA");
1671         }
1672     }
1673 
1674     @Override
setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete)1675     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
1676         if (isPhoneTypeGsm()) {
1677             Phone imsPhone = mImsPhone;
1678             if ((imsPhone != null)
1679                     && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1680                 imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete);
1681                 return;
1682             }
1683             // Packing CLIR value in the message. This will be required for
1684             // SharedPreference caching, if the message comes back as part of
1685             // a success response.
1686             mCi.setCLIR(commandInterfaceCLIRMode,
1687                     obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
1688         } else {
1689             loge("setOutgoingCallerIdDisplay: not possible in CDMA");
1690         }
1691     }
1692 
1693     @Override
getCallWaiting(Message onComplete)1694     public void getCallWaiting(Message onComplete) {
1695         if (isPhoneTypeGsm()) {
1696             Phone imsPhone = mImsPhone;
1697             if ((imsPhone != null)
1698                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1699                     || imsPhone.isUtEnabled())) {
1700                 imsPhone.getCallWaiting(onComplete);
1701                 return;
1702             }
1703 
1704             //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
1705             //class parameter in call waiting interrogation  to network
1706             mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
1707         } else {
1708             mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
1709         }
1710     }
1711 
1712     @Override
setCallWaiting(boolean enable, Message onComplete)1713     public void setCallWaiting(boolean enable, Message onComplete) {
1714         if (isPhoneTypeGsm()) {
1715             Phone imsPhone = mImsPhone;
1716             if ((imsPhone != null)
1717                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1718                     || imsPhone.isUtEnabled())) {
1719                 imsPhone.setCallWaiting(enable, onComplete);
1720                 return;
1721             }
1722 
1723             mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
1724         } else {
1725             loge("method setCallWaiting is NOT supported in CDMA!");
1726         }
1727     }
1728 
1729     @Override
getAvailableNetworks(Message response)1730     public void getAvailableNetworks(Message response) {
1731         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1732             mCi.getAvailableNetworks(response);
1733         } else {
1734             loge("getAvailableNetworks: not possible in CDMA");
1735         }
1736     }
1737 
1738     @Override
getNeighboringCids(Message response)1739     public void getNeighboringCids(Message response) {
1740         if (isPhoneTypeGsm()) {
1741             mCi.getNeighboringCids(response);
1742         } else {
1743             /*
1744              * This is currently not implemented.  At least as of June
1745              * 2009, there is no neighbor cell information available for
1746              * CDMA because some party is resisting making this
1747              * information readily available.  Consequently, calling this
1748              * function can have no useful effect.  This situation may
1749              * (and hopefully will) change in the future.
1750              */
1751             if (response != null) {
1752                 CommandException ce = new CommandException(
1753                         CommandException.Error.REQUEST_NOT_SUPPORTED);
1754                 AsyncResult.forMessage(response).exception = ce;
1755                 response.sendToTarget();
1756             }
1757         }
1758     }
1759 
1760     @Override
setUiTTYMode(int uiTtyMode, Message onComplete)1761     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
1762        if (mImsPhone != null) {
1763            mImsPhone.setUiTTYMode(uiTtyMode, onComplete);
1764        }
1765     }
1766 
1767     @Override
setMute(boolean muted)1768     public void setMute(boolean muted) {
1769         mCT.setMute(muted);
1770     }
1771 
1772     @Override
getMute()1773     public boolean getMute() {
1774         return mCT.getMute();
1775     }
1776 
1777     @Override
getDataCallList(Message response)1778     public void getDataCallList(Message response) {
1779         mCi.getDataCallList(response);
1780     }
1781 
1782     @Override
updateServiceLocation()1783     public void updateServiceLocation() {
1784         mSST.enableSingleLocationUpdate();
1785     }
1786 
1787     @Override
enableLocationUpdates()1788     public void enableLocationUpdates() {
1789         mSST.enableLocationUpdates();
1790     }
1791 
1792     @Override
disableLocationUpdates()1793     public void disableLocationUpdates() {
1794         mSST.disableLocationUpdates();
1795     }
1796 
1797     @Override
getDataRoamingEnabled()1798     public boolean getDataRoamingEnabled() {
1799         return mDcTracker.getDataOnRoamingEnabled();
1800     }
1801 
1802     @Override
setDataRoamingEnabled(boolean enable)1803     public void setDataRoamingEnabled(boolean enable) {
1804         mDcTracker.setDataOnRoamingEnabled(enable);
1805     }
1806 
1807     @Override
registerForCdmaOtaStatusChange(Handler h, int what, Object obj)1808     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
1809         mCi.registerForCdmaOtaProvision(h, what, obj);
1810     }
1811 
1812     @Override
unregisterForCdmaOtaStatusChange(Handler h)1813     public void unregisterForCdmaOtaStatusChange(Handler h) {
1814         mCi.unregisterForCdmaOtaProvision(h);
1815     }
1816 
1817     @Override
registerForSubscriptionInfoReady(Handler h, int what, Object obj)1818     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
1819         mSST.registerForSubscriptionInfoReady(h, what, obj);
1820     }
1821 
1822     @Override
unregisterForSubscriptionInfoReady(Handler h)1823     public void unregisterForSubscriptionInfoReady(Handler h) {
1824         mSST.unregisterForSubscriptionInfoReady(h);
1825     }
1826 
1827     @Override
setOnEcbModeExitResponse(Handler h, int what, Object obj)1828     public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
1829         mEcmExitRespRegistrant = new Registrant(h, what, obj);
1830     }
1831 
1832     @Override
unsetOnEcbModeExitResponse(Handler h)1833     public void unsetOnEcbModeExitResponse(Handler h) {
1834         mEcmExitRespRegistrant.clear();
1835     }
1836 
1837     @Override
registerForCallWaiting(Handler h, int what, Object obj)1838     public void registerForCallWaiting(Handler h, int what, Object obj) {
1839         mCT.registerForCallWaiting(h, what, obj);
1840     }
1841 
1842     @Override
unregisterForCallWaiting(Handler h)1843     public void unregisterForCallWaiting(Handler h) {
1844         mCT.unregisterForCallWaiting(h);
1845     }
1846 
1847     @Override
getDataEnabled()1848     public boolean getDataEnabled() {
1849         return mDcTracker.getDataEnabled();
1850     }
1851 
1852     @Override
setDataEnabled(boolean enable)1853     public void setDataEnabled(boolean enable) {
1854         mDcTracker.setDataEnabled(enable);
1855     }
1856 
1857     /**
1858      * Removes the given MMI from the pending list and notifies
1859      * registrants that it is complete.
1860      * @param mmi MMI that is done
1861      */
onMMIDone(MmiCode mmi)1862     public void onMMIDone(MmiCode mmi) {
1863 
1864         /* Only notify complete if it's on the pending list.
1865          * Otherwise, it's already been handled (eg, previously canceled).
1866          * The exception is cancellation of an incoming USSD-REQUEST, which is
1867          * not on the list.
1868          */
1869         if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
1870                 ((GsmMmiCode)mmi).isSsInfo()))) {
1871             mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1872         }
1873     }
1874 
onNetworkInitiatedUssd(MmiCode mmi)1875     private void onNetworkInitiatedUssd(MmiCode mmi) {
1876         mMmiCompleteRegistrants.notifyRegistrants(
1877             new AsyncResult(null, mmi, null));
1878     }
1879 
1880     /** ussdMode is one of CommandsInterface.USSD_MODE_* */
onIncomingUSSD(int ussdMode, String ussdMessage)1881     private void onIncomingUSSD (int ussdMode, String ussdMessage) {
1882         if (!isPhoneTypeGsm()) {
1883             loge("onIncomingUSSD: not expected on GSM");
1884         }
1885         boolean isUssdError;
1886         boolean isUssdRequest;
1887         boolean isUssdRelease;
1888 
1889         isUssdRequest
1890             = (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
1891 
1892         isUssdError
1893             = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
1894                 && ussdMode != CommandsInterface.USSD_MODE_REQUEST);
1895 
1896         isUssdRelease = (ussdMode == CommandsInterface.USSD_MODE_NW_RELEASE);
1897 
1898 
1899         // See comments in GsmMmiCode.java
1900         // USSD requests aren't finished until one
1901         // of these two events happen
1902         GsmMmiCode found = null;
1903         for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
1904             if(((GsmMmiCode)mPendingMMIs.get(i)).isPendingUSSD()) {
1905                 found = (GsmMmiCode)mPendingMMIs.get(i);
1906                 break;
1907             }
1908         }
1909 
1910         if (found != null) {
1911             // Complete pending USSD
1912 
1913             if (isUssdRelease) {
1914                 found.onUssdRelease();
1915             } else if (isUssdError) {
1916                 found.onUssdFinishedError();
1917             } else {
1918                 found.onUssdFinished(ussdMessage, isUssdRequest);
1919             }
1920         } else { // pending USSD not found
1921             // The network may initiate its own USSD request
1922 
1923             // ignore everything that isnt a Notify or a Request
1924             // also, discard if there is no message to present
1925             if (!isUssdError && ussdMessage != null) {
1926                 GsmMmiCode mmi;
1927                 mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
1928                                                    isUssdRequest,
1929                                                    GsmCdmaPhone.this,
1930                                                    mUiccApplication.get());
1931                 onNetworkInitiatedUssd(mmi);
1932             }
1933         }
1934     }
1935 
1936     /**
1937      * Make sure the network knows our preferred setting.
1938      */
syncClirSetting()1939     private void syncClirSetting() {
1940         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1941         int clirSetting = sp.getInt(CLIR_KEY + getPhoneId(), -1);
1942         if (clirSetting >= 0) {
1943             mCi.setCLIR(clirSetting, null);
1944         }
1945     }
1946 
handleRadioAvailable()1947     private void handleRadioAvailable() {
1948         mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
1949 
1950         if (isPhoneTypeGsm()) {
1951             mCi.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE));
1952             mCi.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE));
1953         } else {
1954             mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
1955         }
1956         mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
1957         startLceAfterRadioIsAvailable();
1958     }
1959 
handleRadioOn()1960     private void handleRadioOn() {
1961         /* Proactively query voice radio technologies */
1962         mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
1963 
1964         if (!isPhoneTypeGsm()) {
1965             mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
1966         }
1967 
1968         // If this is on APM off, SIM may already be loaded. Send setPreferredNetworkType
1969         // request to RIL to preserve user setting across APM toggling
1970         setPreferredNetworkTypeIfSimLoaded();
1971     }
1972 
handleRadioOffOrNotAvailable()1973     private void handleRadioOffOrNotAvailable() {
1974         if (isPhoneTypeGsm()) {
1975             // Some MMI requests (eg USSD) are not completed
1976             // within the course of a CommandsInterface request
1977             // If the radio shuts off or resets while one of these
1978             // is pending, we need to clean up.
1979 
1980             for (int i = mPendingMMIs.size() - 1; i >= 0; i--) {
1981                 if (((GsmMmiCode) mPendingMMIs.get(i)).isPendingUSSD()) {
1982                     ((GsmMmiCode) mPendingMMIs.get(i)).onUssdFinishedError();
1983                 }
1984             }
1985         }
1986         Phone imsPhone = mImsPhone;
1987         if (imsPhone != null) {
1988             imsPhone.getServiceState().setStateOff();
1989         }
1990         mRadioOffOrNotAvailableRegistrants.notifyRegistrants();
1991     }
1992 
1993     @Override
handleMessage(Message msg)1994     public void handleMessage(Message msg) {
1995         AsyncResult ar;
1996         Message onComplete;
1997 
1998         switch (msg.what) {
1999             case EVENT_RADIO_AVAILABLE: {
2000                 handleRadioAvailable();
2001             }
2002             break;
2003 
2004             case EVENT_GET_DEVICE_IDENTITY_DONE:{
2005                 ar = (AsyncResult)msg.obj;
2006 
2007                 if (ar.exception != null) {
2008                     break;
2009                 }
2010                 String[] respId = (String[])ar.result;
2011                 mImei = respId[0];
2012                 mImeiSv = respId[1];
2013                 mEsn  =  respId[2];
2014                 mMeid =  respId[3];
2015             }
2016             break;
2017 
2018             case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
2019                 handleEnterEmergencyCallbackMode(msg);
2020             }
2021             break;
2022 
2023             case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
2024                 handleExitEmergencyCallbackMode(msg);
2025             }
2026             break;
2027 
2028             case EVENT_RUIM_RECORDS_LOADED:
2029                 logd("Event EVENT_RUIM_RECORDS_LOADED Received");
2030                 updateCurrentCarrierInProvider();
2031                 break;
2032 
2033             case EVENT_RADIO_ON:
2034                 logd("Event EVENT_RADIO_ON Received");
2035                 handleRadioOn();
2036                 break;
2037 
2038             case EVENT_RIL_CONNECTED:
2039                 ar = (AsyncResult) msg.obj;
2040                 if (ar.exception == null && ar.result != null) {
2041                     mRilVersion = (Integer) ar.result;
2042                 } else {
2043                     logd("Unexpected exception on EVENT_RIL_CONNECTED");
2044                     mRilVersion = -1;
2045                 }
2046                 break;
2047 
2048             case EVENT_VOICE_RADIO_TECH_CHANGED:
2049             case EVENT_REQUEST_VOICE_RADIO_TECH_DONE:
2050                 String what = (msg.what == EVENT_VOICE_RADIO_TECH_CHANGED) ?
2051                         "EVENT_VOICE_RADIO_TECH_CHANGED" : "EVENT_REQUEST_VOICE_RADIO_TECH_DONE";
2052                 ar = (AsyncResult) msg.obj;
2053                 if (ar.exception == null) {
2054                     if ((ar.result != null) && (((int[]) ar.result).length != 0)) {
2055                         int newVoiceTech = ((int[]) ar.result)[0];
2056                         logd(what + ": newVoiceTech=" + newVoiceTech);
2057                         phoneObjectUpdater(newVoiceTech);
2058                     } else {
2059                         loge(what + ": has no tech!");
2060                     }
2061                 } else {
2062                     loge(what + ": exception=" + ar.exception);
2063                 }
2064                 break;
2065 
2066             case EVENT_UPDATE_PHONE_OBJECT:
2067                 phoneObjectUpdater(msg.arg1);
2068                 break;
2069 
2070             case EVENT_CARRIER_CONFIG_CHANGED:
2071                 // Only check for the voice radio tech if it not going to be updated by the voice
2072                 // registration changes.
2073                 if (!mContext.getResources().getBoolean(com.android.internal.R.bool.
2074                         config_switch_phone_on_voice_reg_state_change)) {
2075                     mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
2076                 }
2077                 // Force update IMS service
2078                 ImsManager.updateImsServiceConfig(mContext, mPhoneId, true);
2079 
2080                 // Update broadcastEmergencyCallStateChanges
2081                 CarrierConfigManager configMgr = (CarrierConfigManager)
2082                         getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
2083                 PersistableBundle b = configMgr.getConfigForSubId(getSubId());
2084                 if (b != null) {
2085                     boolean broadcastEmergencyCallStateChanges = b.getBoolean(
2086                             CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL);
2087                     logd("broadcastEmergencyCallStateChanges = " +
2088                             broadcastEmergencyCallStateChanges);
2089                     setBroadcastEmergencyCallStateChanges(broadcastEmergencyCallStateChanges);
2090                 } else {
2091                     loge("didn't get broadcastEmergencyCallStateChanges from carrier config");
2092                 }
2093 
2094                 // Changing the cdma roaming settings based carrier config.
2095                 if (b != null) {
2096                     int config_cdma_roaming_mode = b.getInt(
2097                             CarrierConfigManager.KEY_CDMA_ROAMING_MODE_INT);
2098                     int current_cdma_roaming_mode =
2099                             Settings.Global.getInt(getContext().getContentResolver(),
2100                             Settings.Global.CDMA_ROAMING_MODE,
2101                             CarrierConfigManager.CDMA_ROAMING_MODE_RADIO_DEFAULT);
2102                     switch (config_cdma_roaming_mode) {
2103                         // Carrier's cdma_roaming_mode will overwrite the user's previous settings
2104                         // Keep the user's previous setting in global variable which will be used
2105                         // when carrier's setting is turn off.
2106                         case CarrierConfigManager.CDMA_ROAMING_MODE_HOME:
2107                         case CarrierConfigManager.CDMA_ROAMING_MODE_AFFILIATED:
2108                         case CarrierConfigManager.CDMA_ROAMING_MODE_ANY:
2109                             logd("cdma_roaming_mode is going to changed to "
2110                                     + config_cdma_roaming_mode);
2111                             setCdmaRoamingPreference(config_cdma_roaming_mode,
2112                                     obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
2113                             break;
2114 
2115                         // When carrier's setting is turn off, change the cdma_roaming_mode to the
2116                         // previous user's setting
2117                         case CarrierConfigManager.CDMA_ROAMING_MODE_RADIO_DEFAULT:
2118                             if (current_cdma_roaming_mode != config_cdma_roaming_mode) {
2119                                 logd("cdma_roaming_mode is going to changed to "
2120                                         + current_cdma_roaming_mode);
2121                                 setCdmaRoamingPreference(current_cdma_roaming_mode,
2122                                         obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
2123                             }
2124 
2125                         default:
2126                             loge("Invalid cdma_roaming_mode settings: "
2127                                     + config_cdma_roaming_mode);
2128                     }
2129                 } else {
2130                     loge("didn't get the cdma_roaming_mode changes from the carrier config.");
2131                 }
2132 
2133                 // Load the ERI based on carrier config. Carrier might have their specific ERI.
2134                 prepareEri();
2135                 if (!isPhoneTypeGsm()) {
2136                     mSST.pollState();
2137                 }
2138 
2139                 break;
2140 
2141             case EVENT_SET_ROAMING_PREFERENCE_DONE:
2142                 logd("cdma_roaming_mode change is done");
2143                 break;
2144 
2145             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
2146                 logd("EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED");
2147                 mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
2148                 break;
2149 
2150             case EVENT_REGISTERED_TO_NETWORK:
2151                 logd("Event EVENT_REGISTERED_TO_NETWORK Received");
2152                 if (isPhoneTypeGsm()) {
2153                     syncClirSetting();
2154                 }
2155                 break;
2156 
2157             case EVENT_SIM_RECORDS_LOADED:
2158                 if (isPhoneTypeGsm()) {
2159                     updateCurrentCarrierInProvider();
2160 
2161                     // Check if this is a different SIM than the previous one. If so unset the
2162                     // voice mail number.
2163                     String imsi = getVmSimImsi();
2164                     String imsiFromSIM = getSubscriberId();
2165                     if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
2166                         storeVoiceMailNumber(null);
2167                         setVmSimImsi(null);
2168                     }
2169                 }
2170 
2171                 mSimRecordsLoadedRegistrants.notifyRegistrants();
2172                 break;
2173 
2174             case EVENT_GET_BASEBAND_VERSION_DONE:
2175                 ar = (AsyncResult)msg.obj;
2176 
2177                 if (ar.exception != null) {
2178                     break;
2179                 }
2180 
2181                 if (DBG) logd("Baseband version: " + ar.result);
2182                 TelephonyManager.from(mContext).setBasebandVersionForPhone(getPhoneId(),
2183                         (String)ar.result);
2184             break;
2185 
2186             case EVENT_GET_IMEI_DONE:
2187                 ar = (AsyncResult)msg.obj;
2188 
2189                 if (ar.exception != null) {
2190                     break;
2191                 }
2192 
2193                 mImei = (String)ar.result;
2194             break;
2195 
2196             case EVENT_GET_IMEISV_DONE:
2197                 ar = (AsyncResult)msg.obj;
2198 
2199                 if (ar.exception != null) {
2200                     break;
2201                 }
2202 
2203                 mImeiSv = (String)ar.result;
2204             break;
2205 
2206             case EVENT_USSD:
2207                 ar = (AsyncResult)msg.obj;
2208 
2209                 String[] ussdResult = (String[]) ar.result;
2210 
2211                 if (ussdResult.length > 1) {
2212                     try {
2213                         onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
2214                     } catch (NumberFormatException e) {
2215                         Rlog.w(LOG_TAG, "error parsing USSD");
2216                     }
2217                 }
2218             break;
2219 
2220             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: {
2221                 logd("Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
2222                 handleRadioOffOrNotAvailable();
2223                 break;
2224             }
2225 
2226             case EVENT_SSN:
2227                 logd("Event EVENT_SSN Received");
2228                 if (isPhoneTypeGsm()) {
2229                     ar = (AsyncResult) msg.obj;
2230                     SuppServiceNotification not = (SuppServiceNotification) ar.result;
2231                     mSsnRegistrants.notifyRegistrants(ar);
2232                 }
2233                 break;
2234 
2235             case EVENT_SET_CALL_FORWARD_DONE:
2236                 ar = (AsyncResult)msg.obj;
2237                 IccRecords r = mIccRecords.get();
2238                 Cfu cfu = (Cfu) ar.userObj;
2239                 if (ar.exception == null && r != null) {
2240                     setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber);
2241                 }
2242                 if (cfu.mOnComplete != null) {
2243                     AsyncResult.forMessage(cfu.mOnComplete, ar.result, ar.exception);
2244                     cfu.mOnComplete.sendToTarget();
2245                 }
2246                 break;
2247 
2248             case EVENT_SET_VM_NUMBER_DONE:
2249                 ar = (AsyncResult)msg.obj;
2250                 if ((isPhoneTypeGsm() && IccVmNotSupportedException.class.isInstance(ar.exception)) ||
2251                         (!isPhoneTypeGsm() && IccException.class.isInstance(ar.exception))){
2252                     storeVoiceMailNumber(mVmNumber);
2253                     ar.exception = null;
2254                 }
2255                 onComplete = (Message) ar.userObj;
2256                 if (onComplete != null) {
2257                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2258                     onComplete.sendToTarget();
2259                 }
2260                 break;
2261 
2262 
2263             case EVENT_GET_CALL_FORWARD_DONE:
2264                 ar = (AsyncResult)msg.obj;
2265                 if (ar.exception == null) {
2266                     handleCfuQueryResult((CallForwardInfo[])ar.result);
2267                 }
2268                 onComplete = (Message) ar.userObj;
2269                 if (onComplete != null) {
2270                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2271                     onComplete.sendToTarget();
2272                 }
2273                 break;
2274 
2275             case EVENT_SET_NETWORK_AUTOMATIC:
2276                 // Automatic network selection from EF_CSP SIM record
2277                 ar = (AsyncResult) msg.obj;
2278                 if (mSST.mSS.getIsManualSelection()) {
2279                     setNetworkSelectionModeAutomatic((Message) ar.result);
2280                     logd("SET_NETWORK_SELECTION_AUTOMATIC: set to automatic");
2281                 } else {
2282                     // prevent duplicate request which will push current PLMN to low priority
2283                     logd("SET_NETWORK_SELECTION_AUTOMATIC: already automatic, ignore");
2284                 }
2285                 break;
2286 
2287             case EVENT_ICC_RECORD_EVENTS:
2288                 ar = (AsyncResult)msg.obj;
2289                 processIccRecordEvents((Integer)ar.result);
2290                 break;
2291 
2292             case EVENT_SET_CLIR_COMPLETE:
2293                 ar = (AsyncResult)msg.obj;
2294                 if (ar.exception == null) {
2295                     saveClirSetting(msg.arg1);
2296                 }
2297                 onComplete = (Message) ar.userObj;
2298                 if (onComplete != null) {
2299                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2300                     onComplete.sendToTarget();
2301                 }
2302                 break;
2303 
2304             case EVENT_SS:
2305                 ar = (AsyncResult)msg.obj;
2306                 logd("Event EVENT_SS received");
2307                 if (isPhoneTypeGsm()) {
2308                     // SS data is already being handled through MMI codes.
2309                     // So, this result if processed as MMI response would help
2310                     // in re-using the existing functionality.
2311                     GsmMmiCode mmi = new GsmMmiCode(this, mUiccApplication.get());
2312                     mmi.processSsData(ar);
2313                 }
2314                 break;
2315 
2316             case EVENT_GET_RADIO_CAPABILITY:
2317                 ar = (AsyncResult) msg.obj;
2318                 RadioCapability rc = (RadioCapability) ar.result;
2319                 if (ar.exception != null) {
2320                     Rlog.d(LOG_TAG, "get phone radio capability fail, no need to change " +
2321                             "mRadioCapability");
2322                 } else {
2323                     radioCapabilityUpdated(rc);
2324                 }
2325                 Rlog.d(LOG_TAG, "EVENT_GET_RADIO_CAPABILITY: phone rc: " + rc);
2326                 break;
2327 
2328             default:
2329                 super.handleMessage(msg);
2330         }
2331     }
2332 
getUiccCardApplication()2333     public UiccCardApplication getUiccCardApplication() {
2334         if (isPhoneTypeGsm()) {
2335             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP);
2336         } else {
2337             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
2338         }
2339     }
2340 
2341     @Override
onUpdateIccAvailability()2342     protected void onUpdateIccAvailability() {
2343         if (mUiccController == null ) {
2344             return;
2345         }
2346 
2347         UiccCardApplication newUiccApplication = null;
2348 
2349         // Update mIsimUiccRecords
2350         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
2351             newUiccApplication =
2352                     mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS);
2353             IsimUiccRecords newIsimUiccRecords = null;
2354 
2355             if (newUiccApplication != null) {
2356                 newIsimUiccRecords = (IsimUiccRecords) newUiccApplication.getIccRecords();
2357                 if (DBG) logd("New ISIM application found");
2358             }
2359             mIsimUiccRecords = newIsimUiccRecords;
2360         }
2361 
2362         // Update mSimRecords
2363         if (mSimRecords != null) {
2364             mSimRecords.unregisterForRecordsLoaded(this);
2365         }
2366         if (isPhoneTypeCdmaLte()) {
2367             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
2368                     UiccController.APP_FAM_3GPP);
2369             SIMRecords newSimRecords = null;
2370             if (newUiccApplication != null) {
2371                 newSimRecords = (SIMRecords) newUiccApplication.getIccRecords();
2372             }
2373             mSimRecords = newSimRecords;
2374             if (mSimRecords != null) {
2375                 mSimRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
2376             }
2377         } else {
2378             mSimRecords = null;
2379         }
2380 
2381         // Update mIccRecords, mUiccApplication, mIccPhoneBookIntManager
2382         newUiccApplication = getUiccCardApplication();
2383         if (!isPhoneTypeGsm() && newUiccApplication == null) {
2384             logd("can't find 3GPP2 application; trying APP_FAM_3GPP");
2385             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
2386                     UiccController.APP_FAM_3GPP);
2387         }
2388 
2389         UiccCardApplication app = mUiccApplication.get();
2390         if (app != newUiccApplication) {
2391             if (app != null) {
2392                 if (DBG) logd("Removing stale icc objects.");
2393                 if (mIccRecords.get() != null) {
2394                     unregisterForIccRecordEvents();
2395                     mIccPhoneBookIntManager.updateIccRecords(null);
2396                 }
2397                 mIccRecords.set(null);
2398                 mUiccApplication.set(null);
2399             }
2400             if (newUiccApplication != null) {
2401                 if (DBG) {
2402                     logd("New Uicc application found. type = " + newUiccApplication.getType());
2403                 }
2404                 mUiccApplication.set(newUiccApplication);
2405                 mIccRecords.set(newUiccApplication.getIccRecords());
2406                 registerForIccRecordEvents();
2407                 mIccPhoneBookIntManager.updateIccRecords(mIccRecords.get());
2408             }
2409         }
2410     }
2411 
processIccRecordEvents(int eventCode)2412     private void processIccRecordEvents(int eventCode) {
2413         switch (eventCode) {
2414             case IccRecords.EVENT_CFI:
2415                 notifyCallForwardingIndicator();
2416                 break;
2417         }
2418     }
2419 
2420     /**
2421      * Sets the "current" field in the telephony provider according to the SIM's operator
2422      *
2423      * @return true for success; false otherwise.
2424      */
2425     @Override
updateCurrentCarrierInProvider()2426     public boolean updateCurrentCarrierInProvider() {
2427         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
2428             long currentDds = SubscriptionManager.getDefaultDataSubscriptionId();
2429             String operatorNumeric = getOperatorNumeric();
2430 
2431             logd("updateCurrentCarrierInProvider: mSubId = " + getSubId()
2432                     + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric);
2433 
2434             if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) {
2435                 try {
2436                     Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
2437                     ContentValues map = new ContentValues();
2438                     map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
2439                     mContext.getContentResolver().insert(uri, map);
2440                     return true;
2441                 } catch (SQLException e) {
2442                     Rlog.e(LOG_TAG, "Can't store current operator", e);
2443                 }
2444             }
2445             return false;
2446         } else {
2447             return true;
2448         }
2449     }
2450 
2451     //CDMA
2452     /**
2453      * Sets the "current" field in the telephony provider according to the
2454      * build-time operator numeric property
2455      *
2456      * @return true for success; false otherwise.
2457      */
updateCurrentCarrierInProvider(String operatorNumeric)2458     private boolean updateCurrentCarrierInProvider(String operatorNumeric) {
2459         if (isPhoneTypeCdma()
2460                 || (isPhoneTypeCdmaLte() && mUiccController.getUiccCardApplication(mPhoneId,
2461                         UiccController.APP_FAM_3GPP) == null)) {
2462             logd("CDMAPhone: updateCurrentCarrierInProvider called");
2463             if (!TextUtils.isEmpty(operatorNumeric)) {
2464                 try {
2465                     Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
2466                     ContentValues map = new ContentValues();
2467                     map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
2468                     logd("updateCurrentCarrierInProvider from system: numeric=" + operatorNumeric);
2469                     getContext().getContentResolver().insert(uri, map);
2470 
2471                     // Updates MCC MNC device configuration information
2472                     logd("update mccmnc=" + operatorNumeric);
2473                     MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
2474 
2475                     return true;
2476                 } catch (SQLException e) {
2477                     Rlog.e(LOG_TAG, "Can't store current operator", e);
2478                 }
2479             }
2480             return false;
2481         } else { // isPhoneTypeCdmaLte()
2482             if (DBG) logd("updateCurrentCarrierInProvider not updated X retVal=" + true);
2483             return true;
2484         }
2485     }
2486 
handleCfuQueryResult(CallForwardInfo[] infos)2487     private void handleCfuQueryResult(CallForwardInfo[] infos) {
2488         IccRecords r = mIccRecords.get();
2489         if (r != null) {
2490             if (infos == null || infos.length == 0) {
2491                 // Assume the default is not active
2492                 // Set unconditional CFF in SIM to false
2493                 setVoiceCallForwardingFlag(1, false, null);
2494             } else {
2495                 for (int i = 0, s = infos.length; i < s; i++) {
2496                     if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
2497                         setVoiceCallForwardingFlag(1, (infos[i].status == 1),
2498                             infos[i].number);
2499                         // should only have the one
2500                         break;
2501                     }
2502                 }
2503             }
2504         }
2505     }
2506 
2507     /**
2508      * Retrieves the IccPhoneBookInterfaceManager of the GsmCdmaPhone
2509      */
2510     @Override
getIccPhoneBookInterfaceManager()2511     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
2512         return mIccPhoneBookIntManager;
2513     }
2514 
2515     //CDMA
registerForEriFileLoaded(Handler h, int what, Object obj)2516     public void registerForEriFileLoaded(Handler h, int what, Object obj) {
2517         Registrant r = new Registrant (h, what, obj);
2518         mEriFileLoadedRegistrants.add(r);
2519     }
2520 
2521     //CDMA
unregisterForEriFileLoaded(Handler h)2522     public void unregisterForEriFileLoaded(Handler h) {
2523         mEriFileLoadedRegistrants.remove(h);
2524     }
2525 
2526     //CDMA
prepareEri()2527     public void prepareEri() {
2528         if (mEriManager == null) {
2529             Rlog.e(LOG_TAG, "PrepareEri: Trying to access stale objects");
2530             return;
2531         }
2532         mEriManager.loadEriFile();
2533         if(mEriManager.isEriFileLoaded()) {
2534             // when the ERI file is loaded
2535             logd("ERI read, notify registrants");
2536             mEriFileLoadedRegistrants.notifyRegistrants();
2537         }
2538     }
2539 
2540     //CDMA
isEriFileLoaded()2541     public boolean isEriFileLoaded() {
2542         return mEriManager.isEriFileLoaded();
2543     }
2544 
2545 
2546     /**
2547      * Activate or deactivate cell broadcast SMS.
2548      *
2549      * @param activate 0 = activate, 1 = deactivate
2550      * @param response Callback message is empty on completion
2551      */
2552     @Override
activateCellBroadcastSms(int activate, Message response)2553     public void activateCellBroadcastSms(int activate, Message response) {
2554         loge("[GsmCdmaPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
2555         response.sendToTarget();
2556     }
2557 
2558     /**
2559      * Query the current configuration of cdma cell broadcast SMS.
2560      *
2561      * @param response Callback message is empty on completion
2562      */
2563     @Override
getCellBroadcastSmsConfig(Message response)2564     public void getCellBroadcastSmsConfig(Message response) {
2565         loge("[GsmCdmaPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
2566         response.sendToTarget();
2567     }
2568 
2569     /**
2570      * Configure cdma cell broadcast SMS.
2571      *
2572      * @param response Callback message is empty on completion
2573      */
2574     @Override
setCellBroadcastSmsConfig(int[] configValuesArray, Message response)2575     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
2576         loge("[GsmCdmaPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
2577         response.sendToTarget();
2578     }
2579 
2580     /**
2581      * Returns true if OTA Service Provisioning needs to be performed.
2582      */
2583     @Override
needsOtaServiceProvisioning()2584     public boolean needsOtaServiceProvisioning() {
2585         if (isPhoneTypeGsm()) {
2586             return false;
2587         } else {
2588             return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
2589         }
2590     }
2591 
2592     @Override
isCspPlmnEnabled()2593     public boolean isCspPlmnEnabled() {
2594         IccRecords r = mIccRecords.get();
2595         return (r != null) ? r.isCspPlmnEnabled() : false;
2596     }
2597 
isManualNetSelAllowed()2598     public boolean isManualNetSelAllowed() {
2599 
2600         int nwMode = Phone.PREFERRED_NT_MODE;
2601         int subId = getSubId();
2602 
2603         nwMode = android.provider.Settings.Global.getInt(mContext.getContentResolver(),
2604                     android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, nwMode);
2605 
2606         logd("isManualNetSelAllowed in mode = " + nwMode);
2607         /*
2608          *  For multimode targets in global mode manual network
2609          *  selection is disallowed
2610          */
2611         if (isManualSelProhibitedInGlobalMode()
2612                 && ((nwMode == Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
2613                         || (nwMode == Phone.NT_MODE_GLOBAL)) ){
2614             logd("Manual selection not supported in mode = " + nwMode);
2615             return false;
2616         } else {
2617             logd("Manual selection is supported in mode = " + nwMode);
2618         }
2619 
2620         /*
2621          *  Single mode phone with - GSM network modes/global mode
2622          *  LTE only for 3GPP
2623          *  LTE centric + 3GPP Legacy
2624          *  Note: the actual enabling/disabling manual selection for these
2625          *  cases will be controlled by csp
2626          */
2627         return true;
2628     }
2629 
isManualSelProhibitedInGlobalMode()2630     private boolean isManualSelProhibitedInGlobalMode() {
2631         boolean isProhibited = false;
2632         final String configString = getContext().getResources().getString(com.android.internal.
2633                 R.string.prohibit_manual_network_selection_in_gobal_mode);
2634 
2635         if (!TextUtils.isEmpty(configString)) {
2636             String[] configArray = configString.split(";");
2637 
2638             if (configArray != null &&
2639                     ((configArray.length == 1 && configArray[0].equalsIgnoreCase("true")) ||
2640                         (configArray.length == 2 && !TextUtils.isEmpty(configArray[1]) &&
2641                             configArray[0].equalsIgnoreCase("true") &&
2642                             isMatchGid(configArray[1])))) {
2643                             isProhibited = true;
2644             }
2645         }
2646         logd("isManualNetSelAllowedInGlobal in current carrier is " + isProhibited);
2647         return isProhibited;
2648     }
2649 
registerForIccRecordEvents()2650     private void registerForIccRecordEvents() {
2651         IccRecords r = mIccRecords.get();
2652         if (r == null) {
2653             return;
2654         }
2655         if (isPhoneTypeGsm()) {
2656             r.registerForNetworkSelectionModeAutomatic(
2657                     this, EVENT_SET_NETWORK_AUTOMATIC, null);
2658             r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
2659             r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
2660         } else {
2661             r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
2662         }
2663     }
2664 
unregisterForIccRecordEvents()2665     private void unregisterForIccRecordEvents() {
2666         IccRecords r = mIccRecords.get();
2667         if (r == null) {
2668             return;
2669         }
2670         r.unregisterForNetworkSelectionModeAutomatic(this);
2671         r.unregisterForRecordsEvents(this);
2672         r.unregisterForRecordsLoaded(this);
2673     }
2674 
2675     @Override
exitEmergencyCallbackMode()2676     public void exitEmergencyCallbackMode() {
2677         if (isPhoneTypeGsm()) {
2678             if (mImsPhone != null) {
2679                 mImsPhone.exitEmergencyCallbackMode();
2680             }
2681         } else {
2682             if (mWakeLock.isHeld()) {
2683                 mWakeLock.release();
2684             }
2685             // Send a message which will invoke handleExitEmergencyCallbackMode
2686             mCi.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
2687         }
2688     }
2689 
2690     //CDMA
handleEnterEmergencyCallbackMode(Message msg)2691     private void handleEnterEmergencyCallbackMode(Message msg) {
2692         if (DBG) {
2693             Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
2694                     + mIsPhoneInEcmState);
2695         }
2696         // if phone is not in Ecm mode, and it's changed to Ecm mode
2697         if (mIsPhoneInEcmState == false) {
2698             setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
2699             mIsPhoneInEcmState = true;
2700             // notify change
2701             sendEmergencyCallbackModeChange();
2702 
2703             // Post this runnable so we will automatically exit
2704             // if no one invokes exitEmergencyCallbackMode() directly.
2705             long delayInMillis = SystemProperties.getLong(
2706                     TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
2707             postDelayed(mExitEcmRunnable, delayInMillis);
2708             // We don't want to go to sleep while in Ecm
2709             mWakeLock.acquire();
2710         }
2711     }
2712 
2713     //CDMA
handleExitEmergencyCallbackMode(Message msg)2714     private void handleExitEmergencyCallbackMode(Message msg) {
2715         AsyncResult ar = (AsyncResult)msg.obj;
2716         if (DBG) {
2717             Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState "
2718                     + ar.exception + mIsPhoneInEcmState);
2719         }
2720         // Remove pending exit Ecm runnable, if any
2721         removeCallbacks(mExitEcmRunnable);
2722 
2723         if (mEcmExitRespRegistrant != null) {
2724             mEcmExitRespRegistrant.notifyRegistrant(ar);
2725         }
2726         // if exiting ecm success
2727         if (ar.exception == null) {
2728             if (mIsPhoneInEcmState) {
2729                 setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
2730                 mIsPhoneInEcmState = false;
2731             }
2732 
2733             // release wakeLock
2734             if (mWakeLock.isHeld()) {
2735                 mWakeLock.release();
2736             }
2737 
2738             // send an Intent
2739             sendEmergencyCallbackModeChange();
2740             // Re-initiate data connection
2741             mDcTracker.setInternalDataEnabled(true);
2742             notifyEmergencyCallRegistrants(false);
2743         }
2744     }
2745 
2746     //CDMA
notifyEmergencyCallRegistrants(boolean started)2747     public void notifyEmergencyCallRegistrants(boolean started) {
2748         mEmergencyCallToggledRegistrants.notifyResult(started ? 1 : 0);
2749     }
2750 
2751     //CDMA
2752     /**
2753      * Handle to cancel or restart Ecm timer in emergency call back mode
2754      * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
2755      * otherwise, restart Ecm timer and notify apps the timer is restarted.
2756      */
handleTimerInEmergencyCallbackMode(int action)2757     public void handleTimerInEmergencyCallbackMode(int action) {
2758         switch(action) {
2759             case CANCEL_ECM_TIMER:
2760                 removeCallbacks(mExitEcmRunnable);
2761                 mEcmTimerResetRegistrants.notifyResult(Boolean.TRUE);
2762                 break;
2763             case RESTART_ECM_TIMER:
2764                 long delayInMillis = SystemProperties.getLong(
2765                         TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
2766                 postDelayed(mExitEcmRunnable, delayInMillis);
2767                 mEcmTimerResetRegistrants.notifyResult(Boolean.FALSE);
2768                 break;
2769             default:
2770                 Rlog.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
2771         }
2772     }
2773 
2774     //CDMA
2775     private static final String IS683A_FEATURE_CODE = "*228";
2776     private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
2777     private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
2778     private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
2779 
2780     private static final int IS683_CONST_800MHZ_A_BAND = 0;
2781     private static final int IS683_CONST_800MHZ_B_BAND = 1;
2782     private static final int IS683_CONST_1900MHZ_A_BLOCK = 2;
2783     private static final int IS683_CONST_1900MHZ_B_BLOCK = 3;
2784     private static final int IS683_CONST_1900MHZ_C_BLOCK = 4;
2785     private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
2786     private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
2787     private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
2788     private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
2789 
2790     // Define the pattern/format for carrier specified OTASP number schema.
2791     // It separates by comma and/or whitespace.
2792     private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
2793 
2794     //CDMA
isIs683OtaSpDialStr(String dialStr)2795     private static boolean isIs683OtaSpDialStr(String dialStr) {
2796         int sysSelCodeInt;
2797         boolean isOtaspDialString = false;
2798         int dialStrLen = dialStr.length();
2799 
2800         if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) {
2801             if (dialStr.equals(IS683A_FEATURE_CODE)) {
2802                 isOtaspDialString = true;
2803             }
2804         } else {
2805             sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
2806             switch (sysSelCodeInt) {
2807                 case IS683_CONST_800MHZ_A_BAND:
2808                 case IS683_CONST_800MHZ_B_BAND:
2809                 case IS683_CONST_1900MHZ_A_BLOCK:
2810                 case IS683_CONST_1900MHZ_B_BLOCK:
2811                 case IS683_CONST_1900MHZ_C_BLOCK:
2812                 case IS683_CONST_1900MHZ_D_BLOCK:
2813                 case IS683_CONST_1900MHZ_E_BLOCK:
2814                 case IS683_CONST_1900MHZ_F_BLOCK:
2815                     isOtaspDialString = true;
2816                     break;
2817                 default:
2818                     break;
2819             }
2820         }
2821         return isOtaspDialString;
2822     }
2823 
2824     //CDMA
2825     /**
2826      * This function extracts the system selection code from the dial string.
2827      */
extractSelCodeFromOtaSpNum(String dialStr)2828     private static int extractSelCodeFromOtaSpNum(String dialStr) {
2829         int dialStrLen = dialStr.length();
2830         int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
2831 
2832         if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
2833                 0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
2834                 (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
2835                         IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
2836             // Since we checked the condition above, the system selection code
2837             // extracted from dialStr will not cause any exception
2838             sysSelCodeInt = Integer.parseInt (
2839                     dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
2840                             IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
2841         }
2842         if (DBG) Rlog.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
2843         return sysSelCodeInt;
2844     }
2845 
2846     //CDMA
2847     /**
2848      * This function checks if the system selection code extracted from
2849      * the dial string "sysSelCodeInt' is the system selection code specified
2850      * in the carrier ota sp number schema "sch".
2851      */
checkOtaSpNumBasedOnSysSelCode(int sysSelCodeInt, String sch[])2852     private static boolean checkOtaSpNumBasedOnSysSelCode(int sysSelCodeInt, String sch[]) {
2853         boolean isOtaSpNum = false;
2854         try {
2855             // Get how many number of system selection code ranges
2856             int selRc = Integer.parseInt(sch[1]);
2857             for (int i = 0; i < selRc; i++) {
2858                 if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
2859                     int selMin = Integer.parseInt(sch[i+2]);
2860                     int selMax = Integer.parseInt(sch[i+3]);
2861                     // Check if the selection code extracted from the dial string falls
2862                     // within any of the range pairs specified in the schema.
2863                     if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
2864                         isOtaSpNum = true;
2865                         break;
2866                     }
2867                 }
2868             }
2869         } catch (NumberFormatException ex) {
2870             // If the carrier ota sp number schema is not correct, we still allow dial
2871             // and only log the error:
2872             Rlog.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
2873         }
2874         return isOtaSpNum;
2875     }
2876 
2877     //CDMA
2878     /**
2879      * The following function checks if a dial string is a carrier specified
2880      * OTASP number or not by checking against the OTASP number schema stored
2881      * in PROPERTY_OTASP_NUM_SCHEMA.
2882      *
2883      * Currently, there are 2 schemas for carriers to specify the OTASP number:
2884      * 1) Use system selection code:
2885      *    The schema is:
2886      *    SELC,the # of code pairs,min1,max1,min2,max2,...
2887      *    e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
2888      *    selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
2889      *
2890      * 2) Use feature code:
2891      *    The schema is:
2892      *    "FC,length of feature code,feature code".
2893      *     e.g "FC,2,*2" indicates that the length of the feature code is 2,
2894      *     and the code itself is "*2".
2895      */
isCarrierOtaSpNum(String dialStr)2896     private boolean isCarrierOtaSpNum(String dialStr) {
2897         boolean isOtaSpNum = false;
2898         int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
2899         if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
2900             return isOtaSpNum;
2901         }
2902         // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
2903         if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
2904             Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
2905             if (DBG) {
2906                 Rlog.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
2907             }
2908 
2909             if (m.find()) {
2910                 String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
2911                 // If carrier uses system selection code mechanism
2912                 if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
2913                     if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
2914                         isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
2915                     } else {
2916                         if (DBG) {
2917                             Rlog.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
2918                         }
2919                     }
2920                 } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
2921                     int fcLen =  Integer.parseInt(sch[1]);
2922                     String fc = sch[2];
2923                     if (dialStr.regionMatches(0,fc,0,fcLen)) {
2924                         isOtaSpNum = true;
2925                     } else {
2926                         if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
2927                     }
2928                 } else {
2929                     if (DBG) {
2930                         Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
2931                     }
2932                 }
2933             } else {
2934                 if (DBG) {
2935                     Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
2936                             mCarrierOtaSpNumSchema);
2937                 }
2938             }
2939         } else {
2940             if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
2941         }
2942         return isOtaSpNum;
2943     }
2944 
2945     /**
2946      * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
2947      * OTASP dial string.
2948      *
2949      * @param dialStr the number to look up.
2950      * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
2951      */
2952     @Override
isOtaSpNumber(String dialStr)2953     public  boolean isOtaSpNumber(String dialStr) {
2954         if (isPhoneTypeGsm()) {
2955             return super.isOtaSpNumber(dialStr);
2956         } else {
2957             boolean isOtaSpNum = false;
2958             String dialableStr = PhoneNumberUtils.extractNetworkPortionAlt(dialStr);
2959             if (dialableStr != null) {
2960                 isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
2961                 if (isOtaSpNum == false) {
2962                     isOtaSpNum = isCarrierOtaSpNum(dialableStr);
2963                 }
2964             }
2965             if (DBG) Rlog.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
2966             return isOtaSpNum;
2967         }
2968     }
2969 
2970     @Override
getCdmaEriIconIndex()2971     public int getCdmaEriIconIndex() {
2972         if (isPhoneTypeGsm()) {
2973             return super.getCdmaEriIconIndex();
2974         } else {
2975             return getServiceState().getCdmaEriIconIndex();
2976         }
2977     }
2978 
2979     /**
2980      * Returns the CDMA ERI icon mode,
2981      * 0 - ON
2982      * 1 - FLASHING
2983      */
2984     @Override
getCdmaEriIconMode()2985     public int getCdmaEriIconMode() {
2986         if (isPhoneTypeGsm()) {
2987             return super.getCdmaEriIconMode();
2988         } else {
2989             return getServiceState().getCdmaEriIconMode();
2990         }
2991     }
2992 
2993     /**
2994      * Returns the CDMA ERI text,
2995      */
2996     @Override
getCdmaEriText()2997     public String getCdmaEriText() {
2998         if (isPhoneTypeGsm()) {
2999             return super.getCdmaEriText();
3000         } else {
3001             int roamInd = getServiceState().getCdmaRoamingIndicator();
3002             int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
3003             return mEriManager.getCdmaEriText(roamInd, defRoamInd);
3004         }
3005     }
3006 
phoneObjectUpdater(int newVoiceRadioTech)3007     private void phoneObjectUpdater(int newVoiceRadioTech) {
3008         logd("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech);
3009 
3010         // Check for a voice over lte replacement
3011         if (ServiceState.isLte(newVoiceRadioTech)
3012                 || (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) {
3013             CarrierConfigManager configMgr = (CarrierConfigManager)
3014                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
3015             PersistableBundle b = configMgr.getConfigForSubId(getSubId());
3016             if (b != null) {
3017                 int volteReplacementRat =
3018                         b.getInt(CarrierConfigManager.KEY_VOLTE_REPLACEMENT_RAT_INT);
3019                 logd("phoneObjectUpdater: volteReplacementRat=" + volteReplacementRat);
3020                 if (volteReplacementRat != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
3021                     newVoiceRadioTech = volteReplacementRat;
3022                 }
3023             } else {
3024                 loge("phoneObjectUpdater: didn't get volteReplacementRat from carrier config");
3025             }
3026         }
3027 
3028         if(mRilVersion == 6 && getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
3029             /*
3030              * On v6 RIL, when LTE_ON_CDMA is TRUE, always create CDMALTEPhone
3031              * irrespective of the voice radio tech reported.
3032              */
3033             if (getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
3034                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Use CDMA Phone" +
3035                         " newVoiceRadioTech=" + newVoiceRadioTech +
3036                         " mActivePhone=" + getPhoneName());
3037                 return;
3038             } else {
3039                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Switch to CDMALTEPhone" +
3040                         " newVoiceRadioTech=" + newVoiceRadioTech +
3041                         " mActivePhone=" + getPhoneName());
3042                 newVoiceRadioTech = ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT;
3043             }
3044         } else {
3045 
3046             // If the device is shutting down, then there is no need to switch to the new phone
3047             // which might send unnecessary attach request to the modem.
3048             if (isShuttingDown()) {
3049                 logd("Device is shutting down. No need to switch phone now.");
3050                 return;
3051             }
3052 
3053             boolean matchCdma = ServiceState.isCdma(newVoiceRadioTech);
3054             boolean matchGsm = ServiceState.isGsm(newVoiceRadioTech);
3055             if ((matchCdma && getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) ||
3056                     (matchGsm && getPhoneType() == PhoneConstants.PHONE_TYPE_GSM)) {
3057                 // Nothing changed. Keep phone as it is.
3058                 logd("phoneObjectUpdater: No change ignore," +
3059                         " newVoiceRadioTech=" + newVoiceRadioTech +
3060                         " mActivePhone=" + getPhoneName());
3061                 return;
3062             }
3063             if (!matchCdma && !matchGsm) {
3064                 loge("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech +
3065                         " doesn't match either CDMA or GSM - error! No phone change");
3066                 return;
3067             }
3068         }
3069 
3070         if (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
3071             // We need some voice phone object to be active always, so never
3072             // delete the phone without anything to replace it with!
3073             logd("phoneObjectUpdater: Unknown rat ignore, "
3074                     + " newVoiceRadioTech=Unknown. mActivePhone=" + getPhoneName());
3075             return;
3076         }
3077 
3078         boolean oldPowerState = false; // old power state to off
3079         if (mResetModemOnRadioTechnologyChange) {
3080             if (mCi.getRadioState().isOn()) {
3081                 oldPowerState = true;
3082                 logd("phoneObjectUpdater: Setting Radio Power to Off");
3083                 mCi.setRadioPower(false, null);
3084             }
3085         }
3086 
3087         switchVoiceRadioTech(newVoiceRadioTech);
3088 
3089         if (mResetModemOnRadioTechnologyChange && oldPowerState) { // restore power state
3090             logd("phoneObjectUpdater: Resetting Radio");
3091             mCi.setRadioPower(oldPowerState, null);
3092         }
3093 
3094         // update voice radio tech in icc card proxy
3095         mIccCardProxy.setVoiceRadioTech(newVoiceRadioTech);
3096 
3097         // Send an Intent to the PhoneApp that we had a radio technology change
3098         Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
3099         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
3100         intent.putExtra(PhoneConstants.PHONE_NAME_KEY, getPhoneName());
3101         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
3102         ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
3103     }
3104 
switchVoiceRadioTech(int newVoiceRadioTech)3105     private void switchVoiceRadioTech(int newVoiceRadioTech) {
3106 
3107         String outgoingPhoneName = getPhoneName();
3108 
3109         logd("Switching Voice Phone : " + outgoingPhoneName + " >>> "
3110                 + (ServiceState.isGsm(newVoiceRadioTech) ? "GSM" : "CDMA"));
3111 
3112         if (ServiceState.isCdma(newVoiceRadioTech)) {
3113             switchPhoneType(PhoneConstants.PHONE_TYPE_CDMA_LTE);
3114         } else if (ServiceState.isGsm(newVoiceRadioTech)) {
3115             switchPhoneType(PhoneConstants.PHONE_TYPE_GSM);
3116         } else {
3117             loge("deleteAndCreatePhone: newVoiceRadioTech=" + newVoiceRadioTech +
3118                     " is not CDMA or GSM (error) - aborting!");
3119             return;
3120         }
3121     }
3122 
3123     @Override
getIccSmsInterfaceManager()3124     public IccSmsInterfaceManager getIccSmsInterfaceManager(){
3125         return mIccSmsInterfaceManager;
3126     }
3127 
3128     @Override
updatePhoneObject(int voiceRadioTech)3129     public void updatePhoneObject(int voiceRadioTech) {
3130         logd("updatePhoneObject: radioTechnology=" + voiceRadioTech);
3131         sendMessage(obtainMessage(EVENT_UPDATE_PHONE_OBJECT, voiceRadioTech, 0, null));
3132     }
3133 
3134     @Override
setImsRegistrationState(boolean registered)3135     public void setImsRegistrationState(boolean registered) {
3136         mSST.setImsRegistrationState(registered);
3137     }
3138 
3139     @Override
getIccRecordsLoaded()3140     public boolean getIccRecordsLoaded() {
3141         return mIccCardProxy.getIccRecordsLoaded();
3142     }
3143 
3144     @Override
getIccCard()3145     public IccCard getIccCard() {
3146         return mIccCardProxy;
3147     }
3148 
3149     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)3150     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3151         pw.println("GsmCdmaPhone extends:");
3152         super.dump(fd, pw, args);
3153         pw.println(" mPrecisePhoneType=" + mPrecisePhoneType);
3154         pw.println(" mCT=" + mCT);
3155         pw.println(" mSST=" + mSST);
3156         pw.println(" mPendingMMIs=" + mPendingMMIs);
3157         pw.println(" mIccPhoneBookIntManager=" + mIccPhoneBookIntManager);
3158         if (VDBG) pw.println(" mImei=" + mImei);
3159         if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
3160         if (VDBG) pw.println(" mVmNumber=" + mVmNumber);
3161         pw.println(" mCdmaSSM=" + mCdmaSSM);
3162         pw.println(" mCdmaSubscriptionSource=" + mCdmaSubscriptionSource);
3163         pw.println(" mEriManager=" + mEriManager);
3164         pw.println(" mWakeLock=" + mWakeLock);
3165         pw.println(" mIsPhoneInEcmState=" + mIsPhoneInEcmState);
3166         if (VDBG) pw.println(" mEsn=" + mEsn);
3167         if (VDBG) pw.println(" mMeid=" + mMeid);
3168         pw.println(" mCarrierOtaSpNumSchema=" + mCarrierOtaSpNumSchema);
3169         if (!isPhoneTypeGsm()) {
3170             pw.println(" getCdmaEriIconIndex()=" + getCdmaEriIconIndex());
3171             pw.println(" getCdmaEriIconMode()=" + getCdmaEriIconMode());
3172             pw.println(" getCdmaEriText()=" + getCdmaEriText());
3173             pw.println(" isMinInfoReady()=" + isMinInfoReady());
3174         }
3175         pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled());
3176         pw.flush();
3177         pw.println("++++++++++++++++++++++++++++++++");
3178 
3179         try {
3180             mIccCardProxy.dump(fd, pw, args);
3181         } catch (Exception e) {
3182             e.printStackTrace();
3183         }
3184         pw.flush();
3185         pw.println("++++++++++++++++++++++++++++++++");
3186     }
3187 
3188     @Override
setOperatorBrandOverride(String brand)3189     public boolean setOperatorBrandOverride(String brand) {
3190         if (mUiccController == null) {
3191             return false;
3192         }
3193 
3194         UiccCard card = mUiccController.getUiccCard(getPhoneId());
3195         if (card == null) {
3196             return false;
3197         }
3198 
3199         boolean status = card.setOperatorBrandOverride(brand);
3200 
3201         // Refresh.
3202         if (status) {
3203             IccRecords iccRecords = mIccRecords.get();
3204             if (iccRecords != null) {
3205                 TelephonyManager.from(mContext).setSimOperatorNameForPhone(
3206                         getPhoneId(), iccRecords.getServiceProviderName());
3207             }
3208             if (mSST != null) {
3209                 mSST.pollState();
3210             }
3211         }
3212         return status;
3213     }
3214 
3215     /**
3216      * @return operator numeric.
3217      */
getOperatorNumeric()3218     private String getOperatorNumeric() {
3219         String operatorNumeric = null;
3220         if (isPhoneTypeGsm()) {
3221             IccRecords r = mIccRecords.get();
3222             if (r != null) {
3223                 operatorNumeric = r.getOperatorNumeric();
3224             }
3225         } else { //isPhoneTypeCdmaLte()
3226             IccRecords curIccRecords = null;
3227             if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_NV) {
3228                 operatorNumeric = SystemProperties.get("ro.cdma.home.operator.numeric");
3229             } else if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_RUIM_SIM) {
3230                 curIccRecords = mSimRecords;
3231                 if (curIccRecords != null) {
3232                     operatorNumeric = curIccRecords.getOperatorNumeric();
3233                 } else {
3234                     curIccRecords = mIccRecords.get();
3235                     if (curIccRecords != null && (curIccRecords instanceof RuimRecords)) {
3236                         RuimRecords csim = (RuimRecords) curIccRecords;
3237                         operatorNumeric = csim.getRUIMOperatorNumeric();
3238                     }
3239                 }
3240             }
3241             if (operatorNumeric == null) {
3242                 loge("getOperatorNumeric: Cannot retrieve operatorNumeric:"
3243                         + " mCdmaSubscriptionSource = " + mCdmaSubscriptionSource +
3244                         " mIccRecords = " + ((curIccRecords != null) ?
3245                         curIccRecords.getRecordsLoaded() : null));
3246             }
3247 
3248             logd("getOperatorNumeric: mCdmaSubscriptionSource = " + mCdmaSubscriptionSource
3249                     + " operatorNumeric = " + operatorNumeric);
3250 
3251         }
3252         return operatorNumeric;
3253     }
3254 
notifyEcbmTimerReset(Boolean flag)3255     public void notifyEcbmTimerReset(Boolean flag) {
3256         mEcmTimerResetRegistrants.notifyResult(flag);
3257     }
3258 
3259     /**
3260      * Registration point for Ecm timer reset
3261      *
3262      * @param h handler to notify
3263      * @param what User-defined message code
3264      * @param obj placed in Message.obj
3265      */
3266     @Override
registerForEcmTimerReset(Handler h, int what, Object obj)3267     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
3268         mEcmTimerResetRegistrants.addUnique(h, what, obj);
3269     }
3270 
3271     @Override
unregisterForEcmTimerReset(Handler h)3272     public void unregisterForEcmTimerReset(Handler h) {
3273         mEcmTimerResetRegistrants.remove(h);
3274     }
3275 
3276     /**
3277      * Sets the SIM voice message waiting indicator records.
3278      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
3279      * @param countWaiting The number of messages waiting, if known. Use
3280      *                     -1 to indicate that an unknown number of
3281      *                      messages are waiting
3282      */
3283     @Override
setVoiceMessageWaiting(int line, int countWaiting)3284     public void setVoiceMessageWaiting(int line, int countWaiting) {
3285         if (isPhoneTypeGsm()) {
3286             IccRecords r = mIccRecords.get();
3287             if (r != null) {
3288                 r.setVoiceMessageWaiting(line, countWaiting);
3289             } else {
3290                 logd("SIM Records not found, MWI not updated");
3291             }
3292         } else {
3293             setVoiceMessageCount(countWaiting);
3294         }
3295     }
3296 
logd(String s)3297     private void logd(String s) {
3298         Rlog.d(LOG_TAG, "[GsmCdmaPhone] " + s);
3299     }
3300 
loge(String s)3301     private void loge(String s) {
3302         Rlog.e(LOG_TAG, "[GsmCdmaPhone] " + s);
3303     }
3304 
3305     @Override
isUtEnabled()3306     public boolean isUtEnabled() {
3307         Phone imsPhone = mImsPhone;
3308         if (imsPhone != null) {
3309             return imsPhone.isUtEnabled();
3310         } else {
3311             logd("isUtEnabled: called for GsmCdma");
3312             return false;
3313         }
3314     }
3315 
getDtmfToneDelayKey()3316     public String getDtmfToneDelayKey() {
3317         return isPhoneTypeGsm() ?
3318                 CarrierConfigManager.KEY_GSM_DTMF_TONE_DELAY_INT :
3319                 CarrierConfigManager.KEY_CDMA_DTMF_TONE_DELAY_INT;
3320     }
3321 
3322     @VisibleForTesting
getWakeLock()3323     public PowerManager.WakeLock getWakeLock() {
3324         return mWakeLock;
3325     }
3326 
3327 }
3328