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