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 static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
20 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
21 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
22 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
23 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
24 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
25 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
26 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
27 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
28 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
29 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
30 
31 import android.app.ActivityManager;
32 import android.content.BroadcastReceiver;
33 import android.content.ContentValues;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.IntentFilter;
37 import android.content.SharedPreferences;
38 import android.database.SQLException;
39 import android.net.Uri;
40 import android.os.AsyncResult;
41 import android.os.Bundle;
42 import android.os.Handler;
43 import android.os.Message;
44 import android.os.PersistableBundle;
45 import android.os.PowerManager;
46 import android.os.Registrant;
47 import android.os.RegistrantList;
48 import android.os.ResultReceiver;
49 import android.os.SystemProperties;
50 import android.os.UserHandle;
51 import android.os.WorkSource;
52 import android.preference.PreferenceManager;
53 import android.provider.Settings;
54 import android.provider.Telephony;
55 import android.telecom.VideoProfile;
56 import android.telephony.CarrierConfigManager;
57 import android.telephony.CellLocation;
58 import android.telephony.PhoneNumberUtils;
59 import android.telephony.Rlog;
60 import android.telephony.ServiceState;
61 import android.telephony.SubscriptionInfo;
62 import android.telephony.SubscriptionManager;
63 import android.telephony.TelephonyManager;
64 import android.telephony.UssdResponse;
65 import android.telephony.cdma.CdmaCellLocation;
66 import android.text.TextUtils;
67 import android.util.Log;
68 
69 import com.android.ims.ImsManager;
70 import com.android.internal.annotations.VisibleForTesting;
71 import com.android.internal.telephony.cdma.CdmaMmiCode;
72 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
73 import com.android.internal.telephony.cdma.EriManager;
74 import com.android.internal.telephony.gsm.GsmMmiCode;
75 import com.android.internal.telephony.gsm.SuppServiceNotification;
76 import com.android.internal.telephony.imsphone.ImsPhone;
77 import com.android.internal.telephony.test.SimulatedRadioControl;
78 import com.android.internal.telephony.uicc.IccCardProxy;
79 import com.android.internal.telephony.uicc.IccException;
80 import com.android.internal.telephony.uicc.IccRecords;
81 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
82 import com.android.internal.telephony.uicc.IsimRecords;
83 import com.android.internal.telephony.uicc.IsimUiccRecords;
84 import com.android.internal.telephony.uicc.RuimRecords;
85 import com.android.internal.telephony.uicc.SIMRecords;
86 import com.android.internal.telephony.uicc.UiccCard;
87 import com.android.internal.telephony.uicc.UiccCardApplication;
88 import com.android.internal.telephony.uicc.UiccController;
89 
90 import java.io.FileDescriptor;
91 import java.io.PrintWriter;
92 import java.util.ArrayDeque;
93 import java.util.ArrayList;
94 import java.util.Deque;
95 import java.util.List;
96 import java.util.regex.Matcher;
97 import java.util.regex.Pattern;
98 
99 /**
100  * {@hide}
101  */
102 public class GsmCdmaPhone extends Phone {
103     // NOTE that LOG_TAG here is "GsmCdma", which means that log messages
104     // from this file will go into the radio log rather than the main
105     // log.  (Use "adb logcat -b radio" to see them.)
106     public static final String LOG_TAG = "GsmCdmaPhone";
107     private static final boolean DBG = true;
108     private static final boolean VDBG = false; /* STOPSHIP if true */
109 
110     //GSM
111     // Key used to read/write voice mail number
112     private static final String VM_NUMBER = "vm_number_key";
113     // Key used to read/write the SIM IMSI used for storing the voice mail
114     private static final String VM_SIM_IMSI = "vm_sim_imsi_key";
115     /** List of Registrants to receive Supplementary Service Notifications. */
116     private RegistrantList mSsnRegistrants = new RegistrantList();
117 
118     //CDMA
119     // Default Emergency Callback Mode exit timer
120     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
121     private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
122     public static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
123     public static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
124     private CdmaSubscriptionSourceManager mCdmaSSM;
125     public int mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
126     public EriManager mEriManager;
127     private PowerManager.WakeLock mWakeLock;
128     // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
129     private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
130     // mEcmExitRespRegistrant is informed after the phone has been exited
131     private Registrant mEcmExitRespRegistrant;
132     private String mEsn;
133     private String mMeid;
134     // string to define how the carrier specifies its own ota sp number
135     private String mCarrierOtaSpNumSchema;
136 
137     // A runnable which is used to automatically exit from Ecm after a period of time.
138     private Runnable mExitEcmRunnable = new Runnable() {
139         @Override
140         public void run() {
141             exitEmergencyCallbackMode();
142         }
143     };
144     public static final String PROPERTY_CDMA_HOME_OPERATOR_NUMERIC =
145             "ro.cdma.home.operator.numeric";
146 
147     //CDMALTE
148     /** PHONE_TYPE_CDMA_LTE in addition to RuimRecords needs access to SIMRecords and
149      * IsimUiccRecords
150      */
151     private SIMRecords mSimRecords;
152 
153     //Common
154     // Instance Variables
155     private IsimUiccRecords mIsimUiccRecords;
156     public GsmCdmaCallTracker mCT;
157     public ServiceStateTracker mSST;
158     private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
159     private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
160     private DeviceStateMonitor mDeviceStateMonitor;
161 
162     private int mPrecisePhoneType;
163 
164     // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
165     private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
166 
167     private String mImei;
168     private String mImeiSv;
169     private String mVmNumber;
170 
171     // Create Cfu (Call forward unconditional) so that dialing number &
172     // mOnComplete (Message object passed by client) can be packed &
173     // given as a single Cfu object as user data to RIL.
174     private static class Cfu {
175         final String mSetCfNumber;
176         final Message mOnComplete;
177 
Cfu(String cfNumber, Message onComplete)178         Cfu(String cfNumber, Message onComplete) {
179             mSetCfNumber = cfNumber;
180             mOnComplete = onComplete;
181         }
182     }
183 
184     private IccSmsInterfaceManager mIccSmsInterfaceManager;
185     private IccCardProxy mIccCardProxy;
186 
187     private boolean mResetModemOnRadioTechnologyChange = false;
188 
189     private int mRilVersion;
190     private boolean mBroadcastEmergencyCallStateChanges = false;
191 
192     // Constructors
193 
GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory)194     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId,
195                         int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) {
196         this(context, ci, notifier, false, phoneId, precisePhoneType, telephonyComponentFactory);
197     }
198 
GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory)199     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
200                         boolean unitTestMode, int phoneId, int precisePhoneType,
201                         TelephonyComponentFactory telephonyComponentFactory) {
202         super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA",
203                 notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory);
204 
205         // phone type needs to be set before other initialization as other objects rely on it
206         mPrecisePhoneType = precisePhoneType;
207         initOnce(ci);
208         initRatSpecific(precisePhoneType);
209         mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
210         // DcTracker uses SST so needs to be created after it is instantiated
211         mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
212         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
213         mDeviceStateMonitor = mTelephonyComponentFactory.makeDeviceStateMonitor(this);
214         logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
215     }
216 
217     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
218         @Override
219         public void onReceive(Context context, Intent intent) {
220             Rlog.d(LOG_TAG, "mBroadcastReceiver: action " + intent.getAction());
221             if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
222                 sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED));
223             }
224         }
225     };
226 
initOnce(CommandsInterface ci)227     private void initOnce(CommandsInterface ci) {
228         if (ci instanceof SimulatedRadioControl) {
229             mSimulatedRadioControl = (SimulatedRadioControl) ci;
230         }
231 
232         mCT = mTelephonyComponentFactory.makeGsmCdmaCallTracker(this);
233         mIccPhoneBookIntManager = mTelephonyComponentFactory.makeIccPhoneBookInterfaceManager(this);
234         PowerManager pm
235                 = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
236         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
237         mIccSmsInterfaceManager = mTelephonyComponentFactory.makeIccSmsInterfaceManager(this);
238         mIccCardProxy = mTelephonyComponentFactory.makeIccCardProxy(mContext, mCi, mPhoneId);
239 
240         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
241         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
242         mCi.registerForOn(this, EVENT_RADIO_ON, null);
243         mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
244 
245         //GSM
246         mCi.setOnUSSD(this, EVENT_USSD, null);
247         mCi.setOnSs(this, EVENT_SS, null);
248 
249         //CDMA
250         mCdmaSSM = mTelephonyComponentFactory.getCdmaSubscriptionSourceManagerInstance(mContext,
251                 mCi, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
252         mEriManager = mTelephonyComponentFactory.makeEriManager(this, mContext,
253                 EriManager.ERI_FROM_XML);
254         mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
255         mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE,
256                 null);
257         // get the string that specifies the carrier OTA Sp number
258         mCarrierOtaSpNumSchema = TelephonyManager.from(mContext).getOtaSpNumberSchemaForPhone(
259                 getPhoneId(), "");
260 
261         mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(
262                 TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);
263 
264         mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
265         mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
266         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
267                 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
268     }
269 
initRatSpecific(int precisePhoneType)270     private void initRatSpecific(int precisePhoneType) {
271         mPendingMMIs.clear();
272         mIccPhoneBookIntManager.updateIccRecords(null);
273         mEsn = null;
274         mMeid = null;
275 
276         mPrecisePhoneType = precisePhoneType;
277 
278         TelephonyManager tm = TelephonyManager.from(mContext);
279         if (isPhoneTypeGsm()) {
280             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
281             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_GSM);
282             mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
283         } else {
284             mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
285             // This is needed to handle phone process crashes
286             mIsPhoneInEcmState = getInEcmMode();
287             if (mIsPhoneInEcmState) {
288                 // Send a message which will invoke handleExitEmergencyCallbackMode
289                 mCi.exitEmergencyCallbackMode(
290                         obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
291             }
292 
293             mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA);
294             tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_CDMA);
295             mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
296             // Sets operator properties by retrieving from build-time system property
297             String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
298             String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
299             logd("init: operatorAlpha='" + operatorAlpha
300                     + "' operatorNumeric='" + operatorNumeric + "'");
301             if (mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP) ==
302                     null || isPhoneTypeCdmaLte()) {
303                 if (!TextUtils.isEmpty(operatorAlpha)) {
304                     logd("init: set 'gsm.sim.operator.alpha' to operator='" + operatorAlpha + "'");
305                     tm.setSimOperatorNameForPhone(mPhoneId, operatorAlpha);
306                 }
307                 if (!TextUtils.isEmpty(operatorNumeric)) {
308                     logd("init: set 'gsm.sim.operator.numeric' to operator='" + operatorNumeric +
309                             "'");
310                     logd("update icc_operator_numeric=" + operatorNumeric);
311                     tm.setSimOperatorNumericForPhone(mPhoneId, operatorNumeric);
312 
313                     SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId());
314                     // Sets iso country property by retrieving from build-time system property
315                     setIsoCountryProperty(operatorNumeric);
316                     // Updates MCC MNC device configuration information
317                     logd("update mccmnc=" + operatorNumeric);
318                     MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
319                 }
320             }
321 
322             // Sets current entry in the telephony carrier table
323             updateCurrentCarrierInProvider(operatorNumeric);
324         }
325     }
326 
327     //CDMA
328     /**
329      * Sets PROPERTY_ICC_OPERATOR_ISO_COUNTRY property
330      *
331      */
setIsoCountryProperty(String operatorNumeric)332     private void setIsoCountryProperty(String operatorNumeric) {
333         TelephonyManager tm = TelephonyManager.from(mContext);
334         if (TextUtils.isEmpty(operatorNumeric)) {
335             logd("setIsoCountryProperty: clear 'gsm.sim.operator.iso-country'");
336             tm.setSimCountryIsoForPhone(mPhoneId, "");
337         } else {
338             String iso = "";
339             try {
340                 iso = MccTable.countryCodeForMcc(Integer.parseInt(
341                         operatorNumeric.substring(0,3)));
342             } catch (NumberFormatException ex) {
343                 Rlog.e(LOG_TAG, "setIsoCountryProperty: countryCodeForMcc error", ex);
344             } catch (StringIndexOutOfBoundsException ex) {
345                 Rlog.e(LOG_TAG, "setIsoCountryProperty: countryCodeForMcc error", ex);
346             }
347 
348             logd("setIsoCountryProperty: set 'gsm.sim.operator.iso-country' to iso=" + iso);
349             tm.setSimCountryIsoForPhone(mPhoneId, iso);
350         }
351     }
352 
isPhoneTypeGsm()353     public boolean isPhoneTypeGsm() {
354         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM;
355     }
356 
isPhoneTypeCdma()357     public boolean isPhoneTypeCdma() {
358         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA;
359     }
360 
isPhoneTypeCdmaLte()361     public boolean isPhoneTypeCdmaLte() {
362         return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_CDMA_LTE;
363     }
364 
switchPhoneType(int precisePhoneType)365     private void switchPhoneType(int precisePhoneType) {
366         removeCallbacks(mExitEcmRunnable);
367 
368         initRatSpecific(precisePhoneType);
369 
370         mSST.updatePhoneType();
371         setPhoneName(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA");
372         onUpdateIccAvailability();
373         mCT.updatePhoneType();
374 
375         CommandsInterface.RadioState radioState = mCi.getRadioState();
376         if (radioState.isAvailable()) {
377             handleRadioAvailable();
378             if (radioState.isOn()) {
379                 handleRadioOn();
380             }
381         }
382         if (!radioState.isAvailable() || !radioState.isOn()) {
383             handleRadioOffOrNotAvailable();
384         }
385     }
386 
387     @Override
finalize()388     protected void finalize() {
389         if(DBG) logd("GsmCdmaPhone finalized");
390         if (mWakeLock != null && mWakeLock.isHeld()) {
391             Rlog.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
392             mWakeLock.release();
393         }
394     }
395 
396     @Override
getServiceState()397     public ServiceState getServiceState() {
398         if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) {
399             if (mImsPhone != null) {
400                 return ServiceState.mergeServiceStates(
401                         (mSST == null) ? new ServiceState() : mSST.mSS,
402                         mImsPhone.getServiceState());
403             }
404         }
405 
406         if (mSST != null) {
407             return mSST.mSS;
408         } else {
409             // avoid potential NPE in EmergencyCallHelper during Phone switch
410             return new ServiceState();
411         }
412     }
413 
414     @Override
getCellLocation(WorkSource workSource)415     public CellLocation getCellLocation(WorkSource workSource) {
416         if (isPhoneTypeGsm()) {
417             return mSST.getCellLocation(workSource);
418         } else {
419             CdmaCellLocation loc = (CdmaCellLocation)mSST.mCellLoc;
420 
421             int mode = Settings.Secure.getInt(getContext().getContentResolver(),
422                     Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
423             if (mode == Settings.Secure.LOCATION_MODE_OFF) {
424                 // clear lat/long values for location privacy
425                 CdmaCellLocation privateLoc = new CdmaCellLocation();
426                 privateLoc.setCellLocationData(loc.getBaseStationId(),
427                         CdmaCellLocation.INVALID_LAT_LONG,
428                         CdmaCellLocation.INVALID_LAT_LONG,
429                         loc.getSystemId(), loc.getNetworkId());
430                 loc = privateLoc;
431             }
432             return loc;
433         }
434     }
435 
436     @Override
getState()437     public PhoneConstants.State getState() {
438         if (mImsPhone != null) {
439             PhoneConstants.State imsState = mImsPhone.getState();
440             if (imsState != PhoneConstants.State.IDLE) {
441                 return imsState;
442             }
443         }
444 
445         return mCT.mState;
446     }
447 
448     @Override
getPhoneType()449     public int getPhoneType() {
450         if (mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM) {
451             return PhoneConstants.PHONE_TYPE_GSM;
452         } else {
453             return PhoneConstants.PHONE_TYPE_CDMA;
454         }
455     }
456 
457     @Override
getServiceStateTracker()458     public ServiceStateTracker getServiceStateTracker() {
459         return mSST;
460     }
461 
462     @Override
getCallTracker()463     public CallTracker getCallTracker() {
464         return mCT;
465     }
466 
467     @Override
updateVoiceMail()468     public void updateVoiceMail() {
469         if (isPhoneTypeGsm()) {
470             int countVoiceMessages = 0;
471             IccRecords r = mIccRecords.get();
472             if (r != null) {
473                 // get voice mail count from SIM
474                 countVoiceMessages = r.getVoiceMessageCount();
475             }
476             if (countVoiceMessages == IccRecords.DEFAULT_VOICE_MESSAGE_COUNT) {
477                 countVoiceMessages = getStoredVoiceMessageCount();
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         ActivityManager.broadcastStickyIntent(intent, 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             ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
646             if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: callActive " + callActive);
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(getSubId(), 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         // Check non-emergency voice CS call - shouldn't dial when POWER_OFF
1127         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_POWER_OFF /* CS POWER_OFF */
1128                 && !VideoProfile.isVideo(videoState) /* voice call */
1129                 && !isEmergency /* non-emergency call */) {
1130             throw new CallStateException(
1131                 CallStateException.ERROR_POWER_OFF,
1132                 "cannot dial voice call in airplane mode");
1133         }
1134         if (DBG) logd("Trying (non-IMS) CS call");
1135 
1136         if (isPhoneTypeGsm()) {
1137             return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);
1138         } else {
1139             return dialInternal(dialString, null, videoState, intentExtras);
1140         }
1141     }
1142 
1143     /**
1144      * @return {@code true} if the user should be informed of an attempt to dial an international
1145      * number while on WFC only, {@code false} otherwise.
1146      */
isNotificationOfWfcCallRequired(String dialString)1147     public boolean isNotificationOfWfcCallRequired(String dialString) {
1148         CarrierConfigManager configManager =
1149                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1150         PersistableBundle config = configManager.getConfigForSubId(getSubId());
1151 
1152         // Determine if carrier config indicates that international calls over WFC should trigger a
1153         // notification to the user. This is controlled by carrier configuration and is off by
1154         // default.
1155         boolean shouldNotifyInternationalCallOnWfc = config != null
1156                 && config.getBoolean(
1157                         CarrierConfigManager.KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL);
1158 
1159         if (!shouldNotifyInternationalCallOnWfc) {
1160             return false;
1161         }
1162 
1163         Phone imsPhone = mImsPhone;
1164         boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
1165         boolean shouldConfirmCall =
1166                         // Using IMS
1167                         isImsUseEnabled()
1168                         && imsPhone != null
1169                         // VoLTE not available
1170                         && !imsPhone.isVolteEnabled()
1171                         // WFC is available
1172                         && imsPhone.isWifiCallingEnabled()
1173                         && !isEmergency
1174                         // Dialing international number
1175                         && PhoneNumberUtils.isInternationalNumber(dialString, getCountryIso());
1176         return shouldConfirmCall;
1177     }
1178 
1179     @Override
dialInternal(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)1180     protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
1181                                       Bundle intentExtras)
1182             throws CallStateException {
1183         return dialInternal(dialString, uusInfo, videoState, intentExtras, null);
1184     }
1185 
dialInternal(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras, ResultReceiver wrappedCallback)1186     protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
1187                                       Bundle intentExtras, ResultReceiver wrappedCallback)
1188             throws CallStateException {
1189 
1190         // Need to make sure dialString gets parsed properly
1191         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
1192 
1193         if (isPhoneTypeGsm()) {
1194             // handle in-call MMI first if applicable
1195             if (handleInCallMmiCommands(newDialString)) {
1196                 return null;
1197             }
1198 
1199             // Only look at the Network portion for mmi
1200             String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
1201             GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
1202                     mUiccApplication.get(), wrappedCallback);
1203             if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'...");
1204 
1205             if (mmi == null) {
1206                 return mCT.dial(newDialString, uusInfo, intentExtras);
1207             } else if (mmi.isTemporaryModeCLIR()) {
1208                 return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
1209             } else {
1210                 mPendingMMIs.add(mmi);
1211                 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1212                 mmi.processCode();
1213                 return null;
1214             }
1215         } else {
1216             return mCT.dial(newDialString);
1217         }
1218     }
1219 
1220    @Override
handlePinMmi(String dialString)1221     public boolean handlePinMmi(String dialString) {
1222         MmiCode mmi;
1223         if (isPhoneTypeGsm()) {
1224             mmi = GsmMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
1225         } else {
1226             mmi = CdmaMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
1227         }
1228 
1229         if (mmi != null && mmi.isPinPukCommand()) {
1230             mPendingMMIs.add(mmi);
1231             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1232             try {
1233                 mmi.processCode();
1234             } catch (CallStateException e) {
1235                 //do nothing
1236             }
1237             return true;
1238         }
1239 
1240         loge("Mmi is null or unrecognized!");
1241         return false;
1242     }
1243 
sendUssdResponse(String ussdRequest, CharSequence message, int returnCode, ResultReceiver wrappedCallback)1244     private void sendUssdResponse(String ussdRequest, CharSequence message, int returnCode,
1245                                    ResultReceiver wrappedCallback) {
1246         UssdResponse response = new UssdResponse(ussdRequest, message);
1247         Bundle returnData = new Bundle();
1248         returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
1249         wrappedCallback.send(returnCode, returnData);
1250     }
1251 
1252     @Override
handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback)1253     public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
1254         if (!isPhoneTypeGsm() || mPendingMMIs.size() > 0) {
1255             //todo: replace the generic failure with specific error code.
1256             sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
1257                     wrappedCallback );
1258             return true;
1259         }
1260 
1261         // Try over IMS if possible.
1262         Phone imsPhone = mImsPhone;
1263         if ((imsPhone != null)
1264                 && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1265                 || imsPhone.isUtEnabled())) {
1266             try {
1267                 logd("handleUssdRequest: attempting over IMS");
1268                 return imsPhone.handleUssdRequest(ussdRequest, wrappedCallback);
1269             } catch (CallStateException cse) {
1270                 if (!CS_FALLBACK.equals(cse.getMessage())) {
1271                     return false;
1272                 }
1273                 // At this point we've tried over IMS but have been informed we need to handover
1274                 // back to GSM.
1275                 logd("handleUssdRequest: fallback to CS required");
1276             }
1277         }
1278 
1279         // Try USSD over GSM.
1280         try {
1281             dialInternal(ussdRequest, null, VideoProfile.STATE_AUDIO_ONLY, null,
1282                     wrappedCallback);
1283         } catch (Exception e) {
1284             logd("handleUssdRequest: exception" + e);
1285             return false;
1286         }
1287         return true;
1288     }
1289 
1290     @Override
sendUssdResponse(String ussdMessge)1291     public void sendUssdResponse(String ussdMessge) {
1292         if (isPhoneTypeGsm()) {
1293             GsmMmiCode mmi = GsmMmiCode.newFromUssdUserInput(ussdMessge, this, mUiccApplication.get());
1294             mPendingMMIs.add(mmi);
1295             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1296             mmi.sendUssd(ussdMessge);
1297         } else {
1298             loge("sendUssdResponse: not possible in CDMA");
1299         }
1300     }
1301 
1302     @Override
sendDtmf(char c)1303     public void sendDtmf(char c) {
1304         if (!PhoneNumberUtils.is12Key(c)) {
1305             loge("sendDtmf called with invalid character '" + c + "'");
1306         } else {
1307             if (mCT.mState ==  PhoneConstants.State.OFFHOOK) {
1308                 mCi.sendDtmf(c, null);
1309             }
1310         }
1311     }
1312 
1313     @Override
startDtmf(char c)1314     public void startDtmf(char c) {
1315         if (!PhoneNumberUtils.is12Key(c)) {
1316             loge("startDtmf called with invalid character '" + c + "'");
1317         } else {
1318             mCi.startDtmf(c, null);
1319         }
1320     }
1321 
1322     @Override
stopDtmf()1323     public void stopDtmf() {
1324         mCi.stopDtmf(null);
1325     }
1326 
1327     @Override
sendBurstDtmf(String dtmfString, int on, int off, Message onComplete)1328     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
1329         if (isPhoneTypeGsm()) {
1330             loge("[GsmCdmaPhone] sendBurstDtmf() is a CDMA method");
1331         } else {
1332             boolean check = true;
1333             for (int itr = 0;itr < dtmfString.length(); itr++) {
1334                 if (!PhoneNumberUtils.is12Key(dtmfString.charAt(itr))) {
1335                     Rlog.e(LOG_TAG,
1336                             "sendDtmf called with invalid character '" + dtmfString.charAt(itr)+ "'");
1337                     check = false;
1338                     break;
1339                 }
1340             }
1341             if (mCT.mState == PhoneConstants.State.OFFHOOK && check) {
1342                 mCi.sendBurstDtmf(dtmfString, on, off, onComplete);
1343             }
1344         }
1345     }
1346 
1347     @Override
setRadioPower(boolean power)1348     public void setRadioPower(boolean power) {
1349         mSST.setRadioPower(power);
1350     }
1351 
storeVoiceMailNumber(String number)1352     private void storeVoiceMailNumber(String number) {
1353         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1354         SharedPreferences.Editor editor = sp.edit();
1355         if (isPhoneTypeGsm()) {
1356             editor.putString(VM_NUMBER + getPhoneId(), number);
1357             editor.apply();
1358             setVmSimImsi(getSubscriberId());
1359         } else {
1360             editor.putString(VM_NUMBER_CDMA + getPhoneId(), number);
1361             editor.apply();
1362         }
1363     }
1364 
1365     @Override
getVoiceMailNumber()1366     public String getVoiceMailNumber() {
1367         String number = null;
1368         if (isPhoneTypeGsm()) {
1369             // Read from the SIM. If its null, try reading from the shared preference area.
1370             IccRecords r = mIccRecords.get();
1371             number = (r != null) ? r.getVoiceMailNumber() : "";
1372             if (TextUtils.isEmpty(number)) {
1373                 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1374                 number = sp.getString(VM_NUMBER + getPhoneId(), null);
1375             }
1376         } else {
1377             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1378             number = sp.getString(VM_NUMBER_CDMA + getPhoneId(), null);
1379         }
1380 
1381         if (TextUtils.isEmpty(number)) {
1382             CarrierConfigManager configManager = (CarrierConfigManager)
1383                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
1384             PersistableBundle b = configManager.getConfig();
1385             if (b != null) {
1386                 String defaultVmNumber =
1387                         b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING);
1388                 if (!TextUtils.isEmpty(defaultVmNumber)) {
1389                     number = defaultVmNumber;
1390                 }
1391             }
1392         }
1393 
1394         if (!isPhoneTypeGsm() && TextUtils.isEmpty(number)) {
1395             // Read platform settings for dynamic voicemail number
1396             if (getContext().getResources().getBoolean(com.android.internal
1397                     .R.bool.config_telephony_use_own_number_for_voicemail)) {
1398                 number = getLine1Number();
1399             } else {
1400                 number = "*86";
1401             }
1402         }
1403 
1404         return number;
1405     }
1406 
getVmSimImsi()1407     private String getVmSimImsi() {
1408         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1409         return sp.getString(VM_SIM_IMSI + getPhoneId(), null);
1410     }
1411 
setVmSimImsi(String imsi)1412     private void setVmSimImsi(String imsi) {
1413         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1414         SharedPreferences.Editor editor = sp.edit();
1415         editor.putString(VM_SIM_IMSI + getPhoneId(), imsi);
1416         editor.apply();
1417     }
1418 
1419     @Override
getVoiceMailAlphaTag()1420     public String getVoiceMailAlphaTag() {
1421         String ret = "";
1422 
1423         if (isPhoneTypeGsm()) {
1424             IccRecords r = mIccRecords.get();
1425 
1426             ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
1427         }
1428 
1429         if (ret == null || ret.length() == 0) {
1430             return mContext.getText(
1431                 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
1432         }
1433 
1434         return ret;
1435     }
1436 
1437     @Override
getDeviceId()1438     public String getDeviceId() {
1439         if (isPhoneTypeGsm()) {
1440             return mImei;
1441         } else {
1442             CarrierConfigManager configManager = (CarrierConfigManager)
1443                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1444             boolean force_imei = configManager.getConfigForSubId(getSubId())
1445                     .getBoolean(CarrierConfigManager.KEY_FORCE_IMEI_BOOL);
1446             if (force_imei) return mImei;
1447 
1448             String id = getMeid();
1449             if ((id == null) || id.matches("^0*$")) {
1450                 loge("getDeviceId(): MEID is not initialized use ESN");
1451                 id = getEsn();
1452             }
1453             return id;
1454         }
1455     }
1456 
1457     @Override
getDeviceSvn()1458     public String getDeviceSvn() {
1459         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1460             return mImeiSv;
1461         } else {
1462             loge("getDeviceSvn(): return 0");
1463             return "0";
1464         }
1465     }
1466 
1467     @Override
getIsimRecords()1468     public IsimRecords getIsimRecords() {
1469         return mIsimUiccRecords;
1470     }
1471 
1472     @Override
getImei()1473     public String getImei() {
1474         return mImei;
1475     }
1476 
1477     @Override
getEsn()1478     public String getEsn() {
1479         if (isPhoneTypeGsm()) {
1480             loge("[GsmCdmaPhone] getEsn() is a CDMA method");
1481             return "0";
1482         } else {
1483             return mEsn;
1484         }
1485     }
1486 
1487     @Override
getMeid()1488     public String getMeid() {
1489         return mMeid;
1490     }
1491 
1492     @Override
getNai()1493     public String getNai() {
1494         IccRecords r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP2);
1495         if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
1496             Rlog.v(LOG_TAG, "IccRecords is " + r);
1497         }
1498         return (r != null) ? r.getNAI() : null;
1499     }
1500 
1501     @Override
getSubscriberId()1502     public String getSubscriberId() {
1503         if (isPhoneTypeGsm()) {
1504             IccRecords r = mIccRecords.get();
1505             return (r != null) ? r.getIMSI() : null;
1506         } else if (isPhoneTypeCdma()) {
1507             return mSST.getImsi();
1508         } else { //isPhoneTypeCdmaLte()
1509             return (mSimRecords != null) ? mSimRecords.getIMSI() : "";
1510         }
1511     }
1512 
1513     @Override
getGroupIdLevel1()1514     public String getGroupIdLevel1() {
1515         if (isPhoneTypeGsm()) {
1516             IccRecords r = mIccRecords.get();
1517             return (r != null) ? r.getGid1() : null;
1518         } else if (isPhoneTypeCdma()) {
1519             loge("GID1 is not available in CDMA");
1520             return null;
1521         } else { //isPhoneTypeCdmaLte()
1522             return (mSimRecords != null) ? mSimRecords.getGid1() : "";
1523         }
1524     }
1525 
1526     @Override
getGroupIdLevel2()1527     public String getGroupIdLevel2() {
1528         if (isPhoneTypeGsm()) {
1529             IccRecords r = mIccRecords.get();
1530             return (r != null) ? r.getGid2() : null;
1531         } else if (isPhoneTypeCdma()) {
1532             loge("GID2 is not available in CDMA");
1533             return null;
1534         } else { //isPhoneTypeCdmaLte()
1535             return (mSimRecords != null) ? mSimRecords.getGid2() : "";
1536         }
1537     }
1538 
1539     @Override
getLine1Number()1540     public String getLine1Number() {
1541         if (isPhoneTypeGsm()) {
1542             IccRecords r = mIccRecords.get();
1543             return (r != null) ? r.getMsisdnNumber() : null;
1544         } else {
1545             return mSST.getMdnNumber();
1546         }
1547     }
1548 
1549     @Override
getCdmaPrlVersion()1550     public String getCdmaPrlVersion() {
1551         return mSST.getPrlVersion();
1552     }
1553 
1554     @Override
getCdmaMin()1555     public String getCdmaMin() {
1556         return mSST.getCdmaMin();
1557     }
1558 
1559     @Override
isMinInfoReady()1560     public boolean isMinInfoReady() {
1561         return mSST.isMinInfoReady();
1562     }
1563 
1564     @Override
getMsisdn()1565     public String getMsisdn() {
1566         if (isPhoneTypeGsm()) {
1567             IccRecords r = mIccRecords.get();
1568             return (r != null) ? r.getMsisdnNumber() : null;
1569         } else if (isPhoneTypeCdmaLte()) {
1570             return (mSimRecords != null) ? mSimRecords.getMsisdnNumber() : null;
1571         } else {
1572             loge("getMsisdn: not expected on CDMA");
1573             return null;
1574         }
1575     }
1576 
1577     @Override
getLine1AlphaTag()1578     public String getLine1AlphaTag() {
1579         if (isPhoneTypeGsm()) {
1580             IccRecords r = mIccRecords.get();
1581             return (r != null) ? r.getMsisdnAlphaTag() : null;
1582         } else {
1583             loge("getLine1AlphaTag: not possible in CDMA");
1584             return null;
1585         }
1586     }
1587 
1588     @Override
setLine1Number(String alphaTag, String number, Message onComplete)1589     public boolean setLine1Number(String alphaTag, String number, Message onComplete) {
1590         if (isPhoneTypeGsm()) {
1591             IccRecords r = mIccRecords.get();
1592             if (r != null) {
1593                 r.setMsisdnNumber(alphaTag, number, onComplete);
1594                 return true;
1595             } else {
1596                 return false;
1597             }
1598         } else {
1599             loge("setLine1Number: not possible in CDMA");
1600             return false;
1601         }
1602     }
1603 
1604     @Override
setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete)1605     public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete) {
1606         Message resp;
1607         mVmNumber = voiceMailNumber;
1608         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
1609         IccRecords r = mIccRecords.get();
1610         if (r != null) {
1611             r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
1612         }
1613     }
1614 
isValidCommandInterfaceCFReason(int commandInterfaceCFReason)1615     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
1616         switch (commandInterfaceCFReason) {
1617             case CF_REASON_UNCONDITIONAL:
1618             case CF_REASON_BUSY:
1619             case CF_REASON_NO_REPLY:
1620             case CF_REASON_NOT_REACHABLE:
1621             case CF_REASON_ALL:
1622             case CF_REASON_ALL_CONDITIONAL:
1623                 return true;
1624             default:
1625                 return false;
1626         }
1627     }
1628 
1629     @Override
getSystemProperty(String property, String defValue)1630     public String getSystemProperty(String property, String defValue) {
1631         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1632             if (getUnitTestMode()) {
1633                 return null;
1634             }
1635             return TelephonyManager.getTelephonyProperty(mPhoneId, property, defValue);
1636         } else {
1637             return super.getSystemProperty(property, defValue);
1638         }
1639     }
1640 
isValidCommandInterfaceCFAction(int commandInterfaceCFAction)1641     private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
1642         switch (commandInterfaceCFAction) {
1643             case CF_ACTION_DISABLE:
1644             case CF_ACTION_ENABLE:
1645             case CF_ACTION_REGISTRATION:
1646             case CF_ACTION_ERASURE:
1647                 return true;
1648             default:
1649                 return false;
1650         }
1651     }
1652 
isCfEnable(int action)1653     private boolean isCfEnable(int action) {
1654         return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
1655     }
1656 
1657     @Override
getCallForwardingOption(int commandInterfaceCFReason, Message onComplete)1658     public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
1659         if (isPhoneTypeGsm()) {
1660             Phone imsPhone = mImsPhone;
1661             if ((imsPhone != null)
1662                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1663                     || imsPhone.isUtEnabled())) {
1664                 imsPhone.getCallForwardingOption(commandInterfaceCFReason, onComplete);
1665                 return;
1666             }
1667 
1668             if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
1669                 if (DBG) logd("requesting call forwarding query.");
1670                 Message resp;
1671                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1672                     resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
1673                 } else {
1674                     resp = onComplete;
1675                 }
1676                 mCi.queryCallForwardStatus(commandInterfaceCFReason, 0, null, resp);
1677             }
1678         } else {
1679             loge("getCallForwardingOption: not possible in CDMA");
1680         }
1681     }
1682 
1683     @Override
setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int timerSeconds, Message onComplete)1684     public void setCallForwardingOption(int commandInterfaceCFAction,
1685             int commandInterfaceCFReason,
1686             String dialingNumber,
1687             int timerSeconds,
1688             Message onComplete) {
1689         if (isPhoneTypeGsm()) {
1690             Phone imsPhone = mImsPhone;
1691             if ((imsPhone != null)
1692                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1693                     || imsPhone.isUtEnabled())) {
1694                 imsPhone.setCallForwardingOption(commandInterfaceCFAction,
1695                         commandInterfaceCFReason, dialingNumber, timerSeconds, onComplete);
1696                 return;
1697             }
1698 
1699             if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
1700                     (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
1701 
1702                 Message resp;
1703                 if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1704                     Cfu cfu = new Cfu(dialingNumber, onComplete);
1705                     resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
1706                             isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cfu);
1707                 } else {
1708                     resp = onComplete;
1709                 }
1710                 mCi.setCallForward(commandInterfaceCFAction,
1711                         commandInterfaceCFReason,
1712                         CommandsInterface.SERVICE_CLASS_VOICE,
1713                         dialingNumber,
1714                         timerSeconds,
1715                         resp);
1716             }
1717         } else {
1718             loge("setCallForwardingOption: not possible in CDMA");
1719         }
1720     }
1721 
1722     @Override
getOutgoingCallerIdDisplay(Message onComplete)1723     public void getOutgoingCallerIdDisplay(Message onComplete) {
1724         if (isPhoneTypeGsm()) {
1725             Phone imsPhone = mImsPhone;
1726             if ((imsPhone != null)
1727                     && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1728                 imsPhone.getOutgoingCallerIdDisplay(onComplete);
1729                 return;
1730             }
1731             mCi.getCLIR(onComplete);
1732         } else {
1733             loge("getOutgoingCallerIdDisplay: not possible in CDMA");
1734         }
1735     }
1736 
1737     @Override
setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete)1738     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
1739         if (isPhoneTypeGsm()) {
1740             Phone imsPhone = mImsPhone;
1741             if ((imsPhone != null)
1742                     && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1743                 imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete);
1744                 return;
1745             }
1746             // Packing CLIR value in the message. This will be required for
1747             // SharedPreference caching, if the message comes back as part of
1748             // a success response.
1749             mCi.setCLIR(commandInterfaceCLIRMode,
1750                     obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
1751         } else {
1752             loge("setOutgoingCallerIdDisplay: not possible in CDMA");
1753         }
1754     }
1755 
1756     @Override
getCallWaiting(Message onComplete)1757     public void getCallWaiting(Message onComplete) {
1758         if (isPhoneTypeGsm()) {
1759             Phone imsPhone = mImsPhone;
1760             if ((imsPhone != null)
1761                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1762                     || imsPhone.isUtEnabled())) {
1763                 imsPhone.getCallWaiting(onComplete);
1764                 return;
1765             }
1766 
1767             //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
1768             //class parameter in call waiting interrogation  to network
1769             mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
1770         } else {
1771             mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
1772         }
1773     }
1774 
1775     @Override
setCallWaiting(boolean enable, Message onComplete)1776     public void setCallWaiting(boolean enable, Message onComplete) {
1777         if (isPhoneTypeGsm()) {
1778             Phone imsPhone = mImsPhone;
1779             if ((imsPhone != null)
1780                     && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
1781                     || imsPhone.isUtEnabled())) {
1782                 imsPhone.setCallWaiting(enable, onComplete);
1783                 return;
1784             }
1785 
1786             mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
1787         } else {
1788             loge("method setCallWaiting is NOT supported in CDMA!");
1789         }
1790     }
1791 
1792     @Override
getAvailableNetworks(Message response)1793     public void getAvailableNetworks(Message response) {
1794         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
1795             mCi.getAvailableNetworks(response);
1796         } else {
1797             loge("getAvailableNetworks: not possible in CDMA");
1798         }
1799     }
1800 
1801     @Override
getNeighboringCids(Message response, WorkSource workSource)1802     public void getNeighboringCids(Message response, WorkSource workSource) {
1803         if (isPhoneTypeGsm()) {
1804             mCi.getNeighboringCids(response, workSource);
1805         } else {
1806             /*
1807              * This is currently not implemented.  At least as of June
1808              * 2009, there is no neighbor cell information available for
1809              * CDMA because some party is resisting making this
1810              * information readily available.  Consequently, calling this
1811              * function can have no useful effect.  This situation may
1812              * (and hopefully will) change in the future.
1813              */
1814             if (response != null) {
1815                 CommandException ce = new CommandException(
1816                         CommandException.Error.REQUEST_NOT_SUPPORTED);
1817                 AsyncResult.forMessage(response).exception = ce;
1818                 response.sendToTarget();
1819             }
1820         }
1821     }
1822 
1823     @Override
setUiTTYMode(int uiTtyMode, Message onComplete)1824     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
1825        if (mImsPhone != null) {
1826            mImsPhone.setUiTTYMode(uiTtyMode, onComplete);
1827        }
1828     }
1829 
1830     @Override
setMute(boolean muted)1831     public void setMute(boolean muted) {
1832         mCT.setMute(muted);
1833     }
1834 
1835     @Override
getMute()1836     public boolean getMute() {
1837         return mCT.getMute();
1838     }
1839 
1840     @Override
getDataCallList(Message response)1841     public void getDataCallList(Message response) {
1842         mCi.getDataCallList(response);
1843     }
1844 
1845     @Override
updateServiceLocation()1846     public void updateServiceLocation() {
1847         mSST.enableSingleLocationUpdate();
1848     }
1849 
1850     @Override
enableLocationUpdates()1851     public void enableLocationUpdates() {
1852         mSST.enableLocationUpdates();
1853     }
1854 
1855     @Override
disableLocationUpdates()1856     public void disableLocationUpdates() {
1857         mSST.disableLocationUpdates();
1858     }
1859 
1860     @Override
getDataRoamingEnabled()1861     public boolean getDataRoamingEnabled() {
1862         return mDcTracker.getDataRoamingEnabled();
1863     }
1864 
1865     @Override
setDataRoamingEnabled(boolean enable)1866     public void setDataRoamingEnabled(boolean enable) {
1867         mDcTracker.setDataRoamingEnabled(enable);
1868     }
1869 
1870     @Override
registerForCdmaOtaStatusChange(Handler h, int what, Object obj)1871     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
1872         mCi.registerForCdmaOtaProvision(h, what, obj);
1873     }
1874 
1875     @Override
unregisterForCdmaOtaStatusChange(Handler h)1876     public void unregisterForCdmaOtaStatusChange(Handler h) {
1877         mCi.unregisterForCdmaOtaProvision(h);
1878     }
1879 
1880     @Override
registerForSubscriptionInfoReady(Handler h, int what, Object obj)1881     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
1882         mSST.registerForSubscriptionInfoReady(h, what, obj);
1883     }
1884 
1885     @Override
unregisterForSubscriptionInfoReady(Handler h)1886     public void unregisterForSubscriptionInfoReady(Handler h) {
1887         mSST.unregisterForSubscriptionInfoReady(h);
1888     }
1889 
1890     @Override
setOnEcbModeExitResponse(Handler h, int what, Object obj)1891     public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
1892         mEcmExitRespRegistrant = new Registrant(h, what, obj);
1893     }
1894 
1895     @Override
unsetOnEcbModeExitResponse(Handler h)1896     public void unsetOnEcbModeExitResponse(Handler h) {
1897         mEcmExitRespRegistrant.clear();
1898     }
1899 
1900     @Override
registerForCallWaiting(Handler h, int what, Object obj)1901     public void registerForCallWaiting(Handler h, int what, Object obj) {
1902         mCT.registerForCallWaiting(h, what, obj);
1903     }
1904 
1905     @Override
unregisterForCallWaiting(Handler h)1906     public void unregisterForCallWaiting(Handler h) {
1907         mCT.unregisterForCallWaiting(h);
1908     }
1909 
1910     @Override
getDataEnabled()1911     public boolean getDataEnabled() {
1912         return mDcTracker.getDataEnabled();
1913     }
1914 
1915     @Override
setDataEnabled(boolean enable)1916     public void setDataEnabled(boolean enable) {
1917         mDcTracker.setDataEnabled(enable);
1918     }
1919 
1920     /**
1921      * Removes the given MMI from the pending list and notifies
1922      * registrants that it is complete.
1923      * @param mmi MMI that is done
1924      */
onMMIDone(MmiCode mmi)1925     public void onMMIDone(MmiCode mmi) {
1926 
1927         /* Only notify complete if it's on the pending list.
1928          * Otherwise, it's already been handled (eg, previously canceled).
1929          * The exception is cancellation of an incoming USSD-REQUEST, which is
1930          * not on the list.
1931          */
1932         if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
1933                 ((GsmMmiCode)mmi).isSsInfo()))) {
1934 
1935             ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
1936             if (receiverCallback != null) {
1937                 Rlog.i(LOG_TAG, "onMMIDone: invoking callback: " + mmi);
1938                 int returnCode = (mmi.getState() ==  MmiCode.State.COMPLETE) ?
1939                     TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
1940                 sendUssdResponse(mmi.getDialString(), mmi.getMessage(), returnCode,
1941                         receiverCallback );
1942             } else {
1943                 Rlog.i(LOG_TAG, "onMMIDone: notifying registrants: " + mmi);
1944                 mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
1945             }
1946         } else {
1947             Rlog.i(LOG_TAG, "onMMIDone: invalid response or already handled; ignoring: " + mmi);
1948         }
1949     }
1950 
supports3gppCallForwardingWhileRoaming()1951     public boolean supports3gppCallForwardingWhileRoaming() {
1952         CarrierConfigManager configManager = (CarrierConfigManager)
1953                 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
1954         PersistableBundle b = configManager.getConfig();
1955         if (b != null) {
1956             return b.getBoolean(
1957                     CarrierConfigManager.KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
1958         } else {
1959             // Default value set in CarrierConfigManager
1960             return true;
1961         }
1962     }
1963 
onNetworkInitiatedUssd(MmiCode mmi)1964     private void onNetworkInitiatedUssd(MmiCode mmi) {
1965         Rlog.v(LOG_TAG, "onNetworkInitiatedUssd: mmi=" + mmi);
1966         mMmiCompleteRegistrants.notifyRegistrants(
1967             new AsyncResult(null, mmi, null));
1968     }
1969 
1970     /** ussdMode is one of CommandsInterface.USSD_MODE_* */
onIncomingUSSD(int ussdMode, String ussdMessage)1971     private void onIncomingUSSD (int ussdMode, String ussdMessage) {
1972         if (!isPhoneTypeGsm()) {
1973             loge("onIncomingUSSD: not expected on GSM");
1974         }
1975         boolean isUssdError;
1976         boolean isUssdRequest;
1977         boolean isUssdRelease;
1978 
1979         isUssdRequest
1980             = (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
1981 
1982         isUssdError
1983             = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
1984                 && ussdMode != CommandsInterface.USSD_MODE_REQUEST);
1985 
1986         isUssdRelease = (ussdMode == CommandsInterface.USSD_MODE_NW_RELEASE);
1987 
1988 
1989         // See comments in GsmMmiCode.java
1990         // USSD requests aren't finished until one
1991         // of these two events happen
1992         GsmMmiCode found = null;
1993         for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
1994             if(((GsmMmiCode)mPendingMMIs.get(i)).isPendingUSSD()) {
1995                 found = (GsmMmiCode)mPendingMMIs.get(i);
1996                 break;
1997             }
1998         }
1999 
2000         if (found != null) {
2001             // Complete pending USSD
2002 
2003             if (isUssdRelease) {
2004                 found.onUssdRelease();
2005             } else if (isUssdError) {
2006                 found.onUssdFinishedError();
2007             } else {
2008                 found.onUssdFinished(ussdMessage, isUssdRequest);
2009             }
2010         } else if (!isUssdError && ussdMessage != null) {
2011             // pending USSD not found
2012             // The network may initiate its own USSD request
2013 
2014             // ignore everything that isnt a Notify or a Request
2015             // also, discard if there is no message to present
2016             GsmMmiCode mmi;
2017             mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
2018                                                    isUssdRequest,
2019                                                    GsmCdmaPhone.this,
2020                                                    mUiccApplication.get());
2021             onNetworkInitiatedUssd(mmi);
2022         }
2023     }
2024 
2025     /**
2026      * Make sure the network knows our preferred setting.
2027      */
syncClirSetting()2028     private void syncClirSetting() {
2029         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
2030         int clirSetting = sp.getInt(CLIR_KEY + getPhoneId(), -1);
2031         if (clirSetting >= 0) {
2032             mCi.setCLIR(clirSetting, null);
2033         }
2034     }
2035 
handleRadioAvailable()2036     private void handleRadioAvailable() {
2037         mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
2038 
2039         mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
2040         mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
2041         startLceAfterRadioIsAvailable();
2042     }
2043 
handleRadioOn()2044     private void handleRadioOn() {
2045         /* Proactively query voice radio technologies */
2046         mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
2047 
2048         if (!isPhoneTypeGsm()) {
2049             mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
2050         }
2051 
2052         // If this is on APM off, SIM may already be loaded. Send setPreferredNetworkType
2053         // request to RIL to preserve user setting across APM toggling
2054         setPreferredNetworkTypeIfSimLoaded();
2055     }
2056 
handleRadioOffOrNotAvailable()2057     private void handleRadioOffOrNotAvailable() {
2058         if (isPhoneTypeGsm()) {
2059             // Some MMI requests (eg USSD) are not completed
2060             // within the course of a CommandsInterface request
2061             // If the radio shuts off or resets while one of these
2062             // is pending, we need to clean up.
2063 
2064             for (int i = mPendingMMIs.size() - 1; i >= 0; i--) {
2065                 if (((GsmMmiCode) mPendingMMIs.get(i)).isPendingUSSD()) {
2066                     ((GsmMmiCode) mPendingMMIs.get(i)).onUssdFinishedError();
2067                 }
2068             }
2069         }
2070         Phone imsPhone = mImsPhone;
2071         if (imsPhone != null) {
2072             imsPhone.getServiceState().setStateOff();
2073         }
2074         mRadioOffOrNotAvailableRegistrants.notifyRegistrants();
2075     }
2076 
2077     @Override
handleMessage(Message msg)2078     public void handleMessage(Message msg) {
2079         AsyncResult ar;
2080         Message onComplete;
2081 
2082         switch (msg.what) {
2083             case EVENT_RADIO_AVAILABLE: {
2084                 handleRadioAvailable();
2085             }
2086             break;
2087 
2088             case EVENT_GET_DEVICE_IDENTITY_DONE:{
2089                 ar = (AsyncResult)msg.obj;
2090 
2091                 if (ar.exception != null) {
2092                     break;
2093                 }
2094                 String[] respId = (String[])ar.result;
2095                 mImei = respId[0];
2096                 mImeiSv = respId[1];
2097                 mEsn  =  respId[2];
2098                 mMeid =  respId[3];
2099             }
2100             break;
2101 
2102             case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
2103                 handleEnterEmergencyCallbackMode(msg);
2104             }
2105             break;
2106 
2107             case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
2108                 handleExitEmergencyCallbackMode(msg);
2109             }
2110             break;
2111 
2112             case EVENT_RUIM_RECORDS_LOADED:
2113                 logd("Event EVENT_RUIM_RECORDS_LOADED Received");
2114                 updateCurrentCarrierInProvider();
2115                 break;
2116 
2117             case EVENT_RADIO_ON:
2118                 logd("Event EVENT_RADIO_ON Received");
2119                 handleRadioOn();
2120                 break;
2121 
2122             case EVENT_RIL_CONNECTED:
2123                 ar = (AsyncResult) msg.obj;
2124                 if (ar.exception == null && ar.result != null) {
2125                     mRilVersion = (Integer) ar.result;
2126                 } else {
2127                     logd("Unexpected exception on EVENT_RIL_CONNECTED");
2128                     mRilVersion = -1;
2129                 }
2130                 break;
2131 
2132             case EVENT_VOICE_RADIO_TECH_CHANGED:
2133             case EVENT_REQUEST_VOICE_RADIO_TECH_DONE:
2134                 String what = (msg.what == EVENT_VOICE_RADIO_TECH_CHANGED) ?
2135                         "EVENT_VOICE_RADIO_TECH_CHANGED" : "EVENT_REQUEST_VOICE_RADIO_TECH_DONE";
2136                 ar = (AsyncResult) msg.obj;
2137                 if (ar.exception == null) {
2138                     if ((ar.result != null) && (((int[]) ar.result).length != 0)) {
2139                         int newVoiceTech = ((int[]) ar.result)[0];
2140                         logd(what + ": newVoiceTech=" + newVoiceTech);
2141                         phoneObjectUpdater(newVoiceTech);
2142                     } else {
2143                         loge(what + ": has no tech!");
2144                     }
2145                 } else {
2146                     loge(what + ": exception=" + ar.exception);
2147                 }
2148                 break;
2149 
2150             case EVENT_UPDATE_PHONE_OBJECT:
2151                 phoneObjectUpdater(msg.arg1);
2152                 break;
2153 
2154             case EVENT_CARRIER_CONFIG_CHANGED:
2155                 // Only check for the voice radio tech if it not going to be updated by the voice
2156                 // registration changes.
2157                 if (!mContext.getResources().getBoolean(com.android.internal.R.bool.
2158                         config_switch_phone_on_voice_reg_state_change)) {
2159                     mCi.getVoiceRadioTechnology(obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
2160                 }
2161                 // Force update IMS service
2162                 ImsManager.updateImsServiceConfig(mContext, mPhoneId, true);
2163 
2164                 // Update broadcastEmergencyCallStateChanges
2165                 CarrierConfigManager configMgr = (CarrierConfigManager)
2166                         getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
2167                 PersistableBundle b = configMgr.getConfigForSubId(getSubId());
2168                 if (b != null) {
2169                     boolean broadcastEmergencyCallStateChanges = b.getBoolean(
2170                             CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL);
2171                     logd("broadcastEmergencyCallStateChanges = " +
2172                             broadcastEmergencyCallStateChanges);
2173                     setBroadcastEmergencyCallStateChanges(broadcastEmergencyCallStateChanges);
2174                 } else {
2175                     loge("didn't get broadcastEmergencyCallStateChanges from carrier config");
2176                 }
2177 
2178                 // Changing the cdma roaming settings based carrier config.
2179                 if (b != null) {
2180                     int config_cdma_roaming_mode = b.getInt(
2181                             CarrierConfigManager.KEY_CDMA_ROAMING_MODE_INT);
2182                     int current_cdma_roaming_mode =
2183                             Settings.Global.getInt(getContext().getContentResolver(),
2184                             Settings.Global.CDMA_ROAMING_MODE,
2185                             CarrierConfigManager.CDMA_ROAMING_MODE_RADIO_DEFAULT);
2186                     switch (config_cdma_roaming_mode) {
2187                         // Carrier's cdma_roaming_mode will overwrite the user's previous settings
2188                         // Keep the user's previous setting in global variable which will be used
2189                         // when carrier's setting is turn off.
2190                         case CarrierConfigManager.CDMA_ROAMING_MODE_HOME:
2191                         case CarrierConfigManager.CDMA_ROAMING_MODE_AFFILIATED:
2192                         case CarrierConfigManager.CDMA_ROAMING_MODE_ANY:
2193                             logd("cdma_roaming_mode is going to changed to "
2194                                     + config_cdma_roaming_mode);
2195                             setCdmaRoamingPreference(config_cdma_roaming_mode,
2196                                     obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
2197                             break;
2198 
2199                         // When carrier's setting is turn off, change the cdma_roaming_mode to the
2200                         // previous user's setting
2201                         case CarrierConfigManager.CDMA_ROAMING_MODE_RADIO_DEFAULT:
2202                             if (current_cdma_roaming_mode != config_cdma_roaming_mode) {
2203                                 logd("cdma_roaming_mode is going to changed to "
2204                                         + current_cdma_roaming_mode);
2205                                 setCdmaRoamingPreference(current_cdma_roaming_mode,
2206                                         obtainMessage(EVENT_SET_ROAMING_PREFERENCE_DONE));
2207                             }
2208 
2209                         default:
2210                             loge("Invalid cdma_roaming_mode settings: "
2211                                     + config_cdma_roaming_mode);
2212                     }
2213                 } else {
2214                     loge("didn't get the cdma_roaming_mode changes from the carrier config.");
2215                 }
2216 
2217                 // Load the ERI based on carrier config. Carrier might have their specific ERI.
2218                 prepareEri();
2219                 if (!isPhoneTypeGsm()) {
2220                     mSST.pollState();
2221                 }
2222 
2223                 break;
2224 
2225             case EVENT_SET_ROAMING_PREFERENCE_DONE:
2226                 logd("cdma_roaming_mode change is done");
2227                 break;
2228 
2229             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
2230                 logd("EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED");
2231                 mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
2232                 break;
2233 
2234             case EVENT_REGISTERED_TO_NETWORK:
2235                 logd("Event EVENT_REGISTERED_TO_NETWORK Received");
2236                 if (isPhoneTypeGsm()) {
2237                     syncClirSetting();
2238                 }
2239                 break;
2240 
2241             case EVENT_SIM_RECORDS_LOADED:
2242                 if (isPhoneTypeGsm()) {
2243                     updateCurrentCarrierInProvider();
2244 
2245                     // Check if this is a different SIM than the previous one. If so unset the
2246                     // voice mail number.
2247                     String imsi = getVmSimImsi();
2248                     String imsiFromSIM = getSubscriberId();
2249                     if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
2250                         storeVoiceMailNumber(null);
2251                         setVmSimImsi(null);
2252                     }
2253                 }
2254 
2255                 mSimRecordsLoadedRegistrants.notifyRegistrants();
2256                 break;
2257 
2258             case EVENT_GET_BASEBAND_VERSION_DONE:
2259                 ar = (AsyncResult)msg.obj;
2260 
2261                 if (ar.exception != null) {
2262                     break;
2263                 }
2264 
2265                 if (DBG) logd("Baseband version: " + ar.result);
2266                 TelephonyManager.from(mContext).setBasebandVersionForPhone(getPhoneId(),
2267                         (String)ar.result);
2268             break;
2269 
2270             case EVENT_GET_IMEI_DONE:
2271                 ar = (AsyncResult)msg.obj;
2272 
2273                 if (ar.exception != null) {
2274                     break;
2275                 }
2276 
2277                 mImei = (String)ar.result;
2278             break;
2279 
2280             case EVENT_GET_IMEISV_DONE:
2281                 ar = (AsyncResult)msg.obj;
2282 
2283                 if (ar.exception != null) {
2284                     break;
2285                 }
2286 
2287                 mImeiSv = (String)ar.result;
2288             break;
2289 
2290             case EVENT_USSD:
2291                 ar = (AsyncResult)msg.obj;
2292 
2293                 String[] ussdResult = (String[]) ar.result;
2294 
2295                 if (ussdResult.length > 1) {
2296                     try {
2297                         onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
2298                     } catch (NumberFormatException e) {
2299                         Rlog.w(LOG_TAG, "error parsing USSD");
2300                     }
2301                 }
2302             break;
2303 
2304             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: {
2305                 logd("Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
2306                 handleRadioOffOrNotAvailable();
2307                 break;
2308             }
2309 
2310             case EVENT_SSN:
2311                 logd("Event EVENT_SSN Received");
2312                 if (isPhoneTypeGsm()) {
2313                     ar = (AsyncResult) msg.obj;
2314                     SuppServiceNotification not = (SuppServiceNotification) ar.result;
2315                     mSsnRegistrants.notifyRegistrants(ar);
2316                 }
2317                 break;
2318 
2319             case EVENT_SET_CALL_FORWARD_DONE:
2320                 ar = (AsyncResult)msg.obj;
2321                 IccRecords r = mIccRecords.get();
2322                 Cfu cfu = (Cfu) ar.userObj;
2323                 if (ar.exception == null && r != null) {
2324                     setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber);
2325                 }
2326                 if (cfu.mOnComplete != null) {
2327                     AsyncResult.forMessage(cfu.mOnComplete, ar.result, ar.exception);
2328                     cfu.mOnComplete.sendToTarget();
2329                 }
2330                 break;
2331 
2332             case EVENT_SET_VM_NUMBER_DONE:
2333                 ar = (AsyncResult)msg.obj;
2334                 if ((isPhoneTypeGsm() && IccVmNotSupportedException.class.isInstance(ar.exception)) ||
2335                         (!isPhoneTypeGsm() && IccException.class.isInstance(ar.exception))){
2336                     storeVoiceMailNumber(mVmNumber);
2337                     ar.exception = null;
2338                 }
2339                 onComplete = (Message) ar.userObj;
2340                 if (onComplete != null) {
2341                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2342                     onComplete.sendToTarget();
2343                 }
2344                 break;
2345 
2346 
2347             case EVENT_GET_CALL_FORWARD_DONE:
2348                 ar = (AsyncResult)msg.obj;
2349                 if (ar.exception == null) {
2350                     handleCfuQueryResult((CallForwardInfo[])ar.result);
2351                 }
2352                 onComplete = (Message) ar.userObj;
2353                 if (onComplete != null) {
2354                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2355                     onComplete.sendToTarget();
2356                 }
2357                 break;
2358 
2359             case EVENT_SET_NETWORK_AUTOMATIC:
2360                 // Automatic network selection from EF_CSP SIM record
2361                 ar = (AsyncResult) msg.obj;
2362                 if (mSST.mSS.getIsManualSelection()) {
2363                     setNetworkSelectionModeAutomatic((Message) ar.result);
2364                     logd("SET_NETWORK_SELECTION_AUTOMATIC: set to automatic");
2365                 } else {
2366                     // prevent duplicate request which will push current PLMN to low priority
2367                     logd("SET_NETWORK_SELECTION_AUTOMATIC: already automatic, ignore");
2368                 }
2369                 break;
2370 
2371             case EVENT_ICC_RECORD_EVENTS:
2372                 ar = (AsyncResult)msg.obj;
2373                 processIccRecordEvents((Integer)ar.result);
2374                 break;
2375 
2376             case EVENT_SET_CLIR_COMPLETE:
2377                 ar = (AsyncResult)msg.obj;
2378                 if (ar.exception == null) {
2379                     saveClirSetting(msg.arg1);
2380                 }
2381                 onComplete = (Message) ar.userObj;
2382                 if (onComplete != null) {
2383                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
2384                     onComplete.sendToTarget();
2385                 }
2386                 break;
2387 
2388             case EVENT_SS:
2389                 ar = (AsyncResult)msg.obj;
2390                 logd("Event EVENT_SS received");
2391                 if (isPhoneTypeGsm()) {
2392                     // SS data is already being handled through MMI codes.
2393                     // So, this result if processed as MMI response would help
2394                     // in re-using the existing functionality.
2395                     GsmMmiCode mmi = new GsmMmiCode(this, mUiccApplication.get());
2396                     mmi.processSsData(ar);
2397                 }
2398                 break;
2399 
2400             case EVENT_GET_RADIO_CAPABILITY:
2401                 ar = (AsyncResult) msg.obj;
2402                 RadioCapability rc = (RadioCapability) ar.result;
2403                 if (ar.exception != null) {
2404                     Rlog.d(LOG_TAG, "get phone radio capability fail, no need to change " +
2405                             "mRadioCapability");
2406                 } else {
2407                     radioCapabilityUpdated(rc);
2408                 }
2409                 Rlog.d(LOG_TAG, "EVENT_GET_RADIO_CAPABILITY: phone rc: " + rc);
2410                 break;
2411 
2412             default:
2413                 super.handleMessage(msg);
2414         }
2415     }
2416 
getUiccCardApplication()2417     public UiccCardApplication getUiccCardApplication() {
2418         if (isPhoneTypeGsm()) {
2419             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP);
2420         } else {
2421             return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP2);
2422         }
2423     }
2424 
2425     @Override
onUpdateIccAvailability()2426     protected void onUpdateIccAvailability() {
2427         if (mUiccController == null ) {
2428             return;
2429         }
2430 
2431         UiccCardApplication newUiccApplication = null;
2432 
2433         // Update mIsimUiccRecords
2434         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
2435             newUiccApplication =
2436                     mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS);
2437             IsimUiccRecords newIsimUiccRecords = null;
2438 
2439             if (newUiccApplication != null) {
2440                 newIsimUiccRecords = (IsimUiccRecords) newUiccApplication.getIccRecords();
2441                 if (DBG) logd("New ISIM application found");
2442             }
2443             mIsimUiccRecords = newIsimUiccRecords;
2444         }
2445 
2446         // Update mSimRecords
2447         if (mSimRecords != null) {
2448             mSimRecords.unregisterForRecordsLoaded(this);
2449         }
2450         if (isPhoneTypeCdmaLte()) {
2451             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
2452                     UiccController.APP_FAM_3GPP);
2453             SIMRecords newSimRecords = null;
2454             if (newUiccApplication != null) {
2455                 newSimRecords = (SIMRecords) newUiccApplication.getIccRecords();
2456             }
2457             mSimRecords = newSimRecords;
2458             if (mSimRecords != null) {
2459                 mSimRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
2460             }
2461         } else {
2462             mSimRecords = null;
2463         }
2464 
2465         // Update mIccRecords, mUiccApplication, mIccPhoneBookIntManager
2466         newUiccApplication = getUiccCardApplication();
2467         if (!isPhoneTypeGsm() && newUiccApplication == null) {
2468             logd("can't find 3GPP2 application; trying APP_FAM_3GPP");
2469             newUiccApplication = mUiccController.getUiccCardApplication(mPhoneId,
2470                     UiccController.APP_FAM_3GPP);
2471         }
2472 
2473         UiccCardApplication app = mUiccApplication.get();
2474         if (app != newUiccApplication) {
2475             if (app != null) {
2476                 if (DBG) logd("Removing stale icc objects.");
2477                 if (mIccRecords.get() != null) {
2478                     unregisterForIccRecordEvents();
2479                     mIccPhoneBookIntManager.updateIccRecords(null);
2480                 }
2481                 mIccRecords.set(null);
2482                 mUiccApplication.set(null);
2483             }
2484             if (newUiccApplication != null) {
2485                 if (DBG) {
2486                     logd("New Uicc application found. type = " + newUiccApplication.getType());
2487                 }
2488                 mUiccApplication.set(newUiccApplication);
2489                 mIccRecords.set(newUiccApplication.getIccRecords());
2490                 registerForIccRecordEvents();
2491                 mIccPhoneBookIntManager.updateIccRecords(mIccRecords.get());
2492             }
2493         }
2494     }
2495 
processIccRecordEvents(int eventCode)2496     private void processIccRecordEvents(int eventCode) {
2497         switch (eventCode) {
2498             case IccRecords.EVENT_CFI:
2499                 notifyCallForwardingIndicator();
2500                 break;
2501         }
2502     }
2503 
2504     /**
2505      * Sets the "current" field in the telephony provider according to the SIM's operator
2506      *
2507      * @return true for success; false otherwise.
2508      */
2509     @Override
updateCurrentCarrierInProvider()2510     public boolean updateCurrentCarrierInProvider() {
2511         if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) {
2512             long currentDds = SubscriptionManager.getDefaultDataSubscriptionId();
2513             String operatorNumeric = getOperatorNumeric();
2514 
2515             logd("updateCurrentCarrierInProvider: mSubId = " + getSubId()
2516                     + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric);
2517 
2518             if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) {
2519                 try {
2520                     Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
2521                     ContentValues map = new ContentValues();
2522                     map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
2523                     mContext.getContentResolver().insert(uri, map);
2524                     return true;
2525                 } catch (SQLException e) {
2526                     Rlog.e(LOG_TAG, "Can't store current operator", e);
2527                 }
2528             }
2529             return false;
2530         } else {
2531             return true;
2532         }
2533     }
2534 
2535     //CDMA
2536     /**
2537      * Sets the "current" field in the telephony provider according to the
2538      * build-time operator numeric property
2539      *
2540      * @return true for success; false otherwise.
2541      */
updateCurrentCarrierInProvider(String operatorNumeric)2542     private boolean updateCurrentCarrierInProvider(String operatorNumeric) {
2543         if (isPhoneTypeCdma()
2544                 || (isPhoneTypeCdmaLte() && mUiccController.getUiccCardApplication(mPhoneId,
2545                         UiccController.APP_FAM_3GPP) == null)) {
2546             logd("CDMAPhone: updateCurrentCarrierInProvider called");
2547             if (!TextUtils.isEmpty(operatorNumeric)) {
2548                 try {
2549                     Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
2550                     ContentValues map = new ContentValues();
2551                     map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
2552                     logd("updateCurrentCarrierInProvider from system: numeric=" + operatorNumeric);
2553                     getContext().getContentResolver().insert(uri, map);
2554 
2555                     // Updates MCC MNC device configuration information
2556                     logd("update mccmnc=" + operatorNumeric);
2557                     MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false);
2558 
2559                     return true;
2560                 } catch (SQLException e) {
2561                     Rlog.e(LOG_TAG, "Can't store current operator", e);
2562                 }
2563             }
2564             return false;
2565         } else { // isPhoneTypeCdmaLte()
2566             if (DBG) logd("updateCurrentCarrierInProvider not updated X retVal=" + true);
2567             return true;
2568         }
2569     }
2570 
handleCfuQueryResult(CallForwardInfo[] infos)2571     private void handleCfuQueryResult(CallForwardInfo[] infos) {
2572         IccRecords r = mIccRecords.get();
2573         if (r != null) {
2574             if (infos == null || infos.length == 0) {
2575                 // Assume the default is not active
2576                 // Set unconditional CFF in SIM to false
2577                 setVoiceCallForwardingFlag(1, false, null);
2578             } else {
2579                 for (int i = 0, s = infos.length; i < s; i++) {
2580                     if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
2581                         setVoiceCallForwardingFlag(1, (infos[i].status == 1),
2582                             infos[i].number);
2583                         // should only have the one
2584                         break;
2585                     }
2586                 }
2587             }
2588         }
2589     }
2590 
2591     /**
2592      * Retrieves the IccPhoneBookInterfaceManager of the GsmCdmaPhone
2593      */
2594     @Override
getIccPhoneBookInterfaceManager()2595     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
2596         return mIccPhoneBookIntManager;
2597     }
2598 
2599     //CDMA
registerForEriFileLoaded(Handler h, int what, Object obj)2600     public void registerForEriFileLoaded(Handler h, int what, Object obj) {
2601         Registrant r = new Registrant (h, what, obj);
2602         mEriFileLoadedRegistrants.add(r);
2603     }
2604 
2605     //CDMA
unregisterForEriFileLoaded(Handler h)2606     public void unregisterForEriFileLoaded(Handler h) {
2607         mEriFileLoadedRegistrants.remove(h);
2608     }
2609 
2610     //CDMA
prepareEri()2611     public void prepareEri() {
2612         if (mEriManager == null) {
2613             Rlog.e(LOG_TAG, "PrepareEri: Trying to access stale objects");
2614             return;
2615         }
2616         mEriManager.loadEriFile();
2617         if(mEriManager.isEriFileLoaded()) {
2618             // when the ERI file is loaded
2619             logd("ERI read, notify registrants");
2620             mEriFileLoadedRegistrants.notifyRegistrants();
2621         }
2622     }
2623 
2624     //CDMA
isEriFileLoaded()2625     public boolean isEriFileLoaded() {
2626         return mEriManager.isEriFileLoaded();
2627     }
2628 
2629 
2630     /**
2631      * Activate or deactivate cell broadcast SMS.
2632      *
2633      * @param activate 0 = activate, 1 = deactivate
2634      * @param response Callback message is empty on completion
2635      */
2636     @Override
activateCellBroadcastSms(int activate, Message response)2637     public void activateCellBroadcastSms(int activate, Message response) {
2638         loge("[GsmCdmaPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
2639         response.sendToTarget();
2640     }
2641 
2642     /**
2643      * Query the current configuration of cdma cell broadcast SMS.
2644      *
2645      * @param response Callback message is empty on completion
2646      */
2647     @Override
getCellBroadcastSmsConfig(Message response)2648     public void getCellBroadcastSmsConfig(Message response) {
2649         loge("[GsmCdmaPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
2650         response.sendToTarget();
2651     }
2652 
2653     /**
2654      * Configure cdma cell broadcast SMS.
2655      *
2656      * @param response Callback message is empty on completion
2657      */
2658     @Override
setCellBroadcastSmsConfig(int[] configValuesArray, Message response)2659     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
2660         loge("[GsmCdmaPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
2661         response.sendToTarget();
2662     }
2663 
2664     /**
2665      * Returns true if OTA Service Provisioning needs to be performed.
2666      */
2667     @Override
needsOtaServiceProvisioning()2668     public boolean needsOtaServiceProvisioning() {
2669         if (isPhoneTypeGsm()) {
2670             return false;
2671         } else {
2672             return mSST.getOtasp() != TelephonyManager.OTASP_NOT_NEEDED;
2673         }
2674     }
2675 
2676     @Override
isCspPlmnEnabled()2677     public boolean isCspPlmnEnabled() {
2678         IccRecords r = mIccRecords.get();
2679         return (r != null) ? r.isCspPlmnEnabled() : false;
2680     }
2681 
isManualNetSelAllowed()2682     public boolean isManualNetSelAllowed() {
2683 
2684         int nwMode = Phone.PREFERRED_NT_MODE;
2685         int subId = getSubId();
2686 
2687         nwMode = android.provider.Settings.Global.getInt(mContext.getContentResolver(),
2688                     android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, nwMode);
2689 
2690         logd("isManualNetSelAllowed in mode = " + nwMode);
2691         /*
2692          *  For multimode targets in global mode manual network
2693          *  selection is disallowed
2694          */
2695         if (isManualSelProhibitedInGlobalMode()
2696                 && ((nwMode == Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
2697                         || (nwMode == Phone.NT_MODE_GLOBAL)) ){
2698             logd("Manual selection not supported in mode = " + nwMode);
2699             return false;
2700         } else {
2701             logd("Manual selection is supported in mode = " + nwMode);
2702         }
2703 
2704         /*
2705          *  Single mode phone with - GSM network modes/global mode
2706          *  LTE only for 3GPP
2707          *  LTE centric + 3GPP Legacy
2708          *  Note: the actual enabling/disabling manual selection for these
2709          *  cases will be controlled by csp
2710          */
2711         return true;
2712     }
2713 
isManualSelProhibitedInGlobalMode()2714     private boolean isManualSelProhibitedInGlobalMode() {
2715         boolean isProhibited = false;
2716         final String configString = getContext().getResources().getString(com.android.internal.
2717                 R.string.prohibit_manual_network_selection_in_gobal_mode);
2718 
2719         if (!TextUtils.isEmpty(configString)) {
2720             String[] configArray = configString.split(";");
2721 
2722             if (configArray != null &&
2723                     ((configArray.length == 1 && configArray[0].equalsIgnoreCase("true")) ||
2724                         (configArray.length == 2 && !TextUtils.isEmpty(configArray[1]) &&
2725                             configArray[0].equalsIgnoreCase("true") &&
2726                             isMatchGid(configArray[1])))) {
2727                             isProhibited = true;
2728             }
2729         }
2730         logd("isManualNetSelAllowedInGlobal in current carrier is " + isProhibited);
2731         return isProhibited;
2732     }
2733 
registerForIccRecordEvents()2734     private void registerForIccRecordEvents() {
2735         IccRecords r = mIccRecords.get();
2736         if (r == null) {
2737             return;
2738         }
2739         if (isPhoneTypeGsm()) {
2740             r.registerForNetworkSelectionModeAutomatic(
2741                     this, EVENT_SET_NETWORK_AUTOMATIC, null);
2742             r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
2743             r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
2744         } else {
2745             r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
2746             if (isPhoneTypeCdmaLte()) {
2747                 // notify simRecordsLoaded registrants for cdmaLte phone
2748                 r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
2749             }
2750         }
2751     }
2752 
unregisterForIccRecordEvents()2753     private void unregisterForIccRecordEvents() {
2754         IccRecords r = mIccRecords.get();
2755         if (r == null) {
2756             return;
2757         }
2758         r.unregisterForNetworkSelectionModeAutomatic(this);
2759         r.unregisterForRecordsEvents(this);
2760         r.unregisterForRecordsLoaded(this);
2761     }
2762 
2763     @Override
exitEmergencyCallbackMode()2764     public void exitEmergencyCallbackMode() {
2765         if (isPhoneTypeGsm()) {
2766             if (mImsPhone != null) {
2767                 mImsPhone.exitEmergencyCallbackMode();
2768             }
2769         } else {
2770             if (mWakeLock.isHeld()) {
2771                 mWakeLock.release();
2772             }
2773             // Send a message which will invoke handleExitEmergencyCallbackMode
2774             mCi.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
2775         }
2776     }
2777 
2778     //CDMA
handleEnterEmergencyCallbackMode(Message msg)2779     private void handleEnterEmergencyCallbackMode(Message msg) {
2780         if (DBG) {
2781             Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
2782                     + mIsPhoneInEcmState);
2783         }
2784         // if phone is not in Ecm mode, and it's changed to Ecm mode
2785         if (!mIsPhoneInEcmState) {
2786             setIsInEcm(true);
2787 
2788             // notify change
2789             sendEmergencyCallbackModeChange();
2790 
2791             // Post this runnable so we will automatically exit
2792             // if no one invokes exitEmergencyCallbackMode() directly.
2793             long delayInMillis = SystemProperties.getLong(
2794                     TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
2795             postDelayed(mExitEcmRunnable, delayInMillis);
2796             // We don't want to go to sleep while in Ecm
2797             mWakeLock.acquire();
2798         }
2799     }
2800 
2801     //CDMA
handleExitEmergencyCallbackMode(Message msg)2802     private void handleExitEmergencyCallbackMode(Message msg) {
2803         AsyncResult ar = (AsyncResult)msg.obj;
2804         if (DBG) {
2805             Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState "
2806                     + ar.exception + mIsPhoneInEcmState);
2807         }
2808         // Remove pending exit Ecm runnable, if any
2809         removeCallbacks(mExitEcmRunnable);
2810 
2811         if (mEcmExitRespRegistrant != null) {
2812             mEcmExitRespRegistrant.notifyRegistrant(ar);
2813         }
2814         // if exiting ecm success
2815         if (ar.exception == null) {
2816             if (mIsPhoneInEcmState) {
2817                 setIsInEcm(false);
2818             }
2819 
2820             // release wakeLock
2821             if (mWakeLock.isHeld()) {
2822                 mWakeLock.release();
2823             }
2824 
2825             // send an Intent
2826             sendEmergencyCallbackModeChange();
2827             // Re-initiate data connection
2828             mDcTracker.setInternalDataEnabled(true);
2829             notifyEmergencyCallRegistrants(false);
2830         }
2831     }
2832 
2833     //CDMA
notifyEmergencyCallRegistrants(boolean started)2834     public void notifyEmergencyCallRegistrants(boolean started) {
2835         mEmergencyCallToggledRegistrants.notifyResult(started ? 1 : 0);
2836     }
2837 
2838     //CDMA
2839     /**
2840      * Handle to cancel or restart Ecm timer in emergency call back mode
2841      * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
2842      * otherwise, restart Ecm timer and notify apps the timer is restarted.
2843      */
handleTimerInEmergencyCallbackMode(int action)2844     public void handleTimerInEmergencyCallbackMode(int action) {
2845         switch(action) {
2846             case CANCEL_ECM_TIMER:
2847                 removeCallbacks(mExitEcmRunnable);
2848                 mEcmTimerResetRegistrants.notifyResult(Boolean.TRUE);
2849                 break;
2850             case RESTART_ECM_TIMER:
2851                 long delayInMillis = SystemProperties.getLong(
2852                         TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
2853                 postDelayed(mExitEcmRunnable, delayInMillis);
2854                 mEcmTimerResetRegistrants.notifyResult(Boolean.FALSE);
2855                 break;
2856             default:
2857                 Rlog.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
2858         }
2859     }
2860 
2861     //CDMA
2862     private static final String IS683A_FEATURE_CODE = "*228";
2863     private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
2864     private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
2865     private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
2866 
2867     private static final int IS683_CONST_800MHZ_A_BAND = 0;
2868     private static final int IS683_CONST_800MHZ_B_BAND = 1;
2869     private static final int IS683_CONST_1900MHZ_A_BLOCK = 2;
2870     private static final int IS683_CONST_1900MHZ_B_BLOCK = 3;
2871     private static final int IS683_CONST_1900MHZ_C_BLOCK = 4;
2872     private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
2873     private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
2874     private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
2875     private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
2876 
2877     // Define the pattern/format for carrier specified OTASP number schema.
2878     // It separates by comma and/or whitespace.
2879     private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
2880 
2881     //CDMA
isIs683OtaSpDialStr(String dialStr)2882     private static boolean isIs683OtaSpDialStr(String dialStr) {
2883         int sysSelCodeInt;
2884         boolean isOtaspDialString = false;
2885         int dialStrLen = dialStr.length();
2886 
2887         if (dialStrLen == IS683A_FEATURE_CODE_NUM_DIGITS) {
2888             if (dialStr.equals(IS683A_FEATURE_CODE)) {
2889                 isOtaspDialString = true;
2890             }
2891         } else {
2892             sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
2893             switch (sysSelCodeInt) {
2894                 case IS683_CONST_800MHZ_A_BAND:
2895                 case IS683_CONST_800MHZ_B_BAND:
2896                 case IS683_CONST_1900MHZ_A_BLOCK:
2897                 case IS683_CONST_1900MHZ_B_BLOCK:
2898                 case IS683_CONST_1900MHZ_C_BLOCK:
2899                 case IS683_CONST_1900MHZ_D_BLOCK:
2900                 case IS683_CONST_1900MHZ_E_BLOCK:
2901                 case IS683_CONST_1900MHZ_F_BLOCK:
2902                     isOtaspDialString = true;
2903                     break;
2904                 default:
2905                     break;
2906             }
2907         }
2908         return isOtaspDialString;
2909     }
2910 
2911     //CDMA
2912     /**
2913      * This function extracts the system selection code from the dial string.
2914      */
extractSelCodeFromOtaSpNum(String dialStr)2915     private static int extractSelCodeFromOtaSpNum(String dialStr) {
2916         int dialStrLen = dialStr.length();
2917         int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
2918 
2919         if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
2920                 0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
2921                 (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
2922                         IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
2923             // Since we checked the condition above, the system selection code
2924             // extracted from dialStr will not cause any exception
2925             sysSelCodeInt = Integer.parseInt (
2926                     dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
2927                             IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
2928         }
2929         if (DBG) Rlog.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
2930         return sysSelCodeInt;
2931     }
2932 
2933     //CDMA
2934     /**
2935      * This function checks if the system selection code extracted from
2936      * the dial string "sysSelCodeInt' is the system selection code specified
2937      * in the carrier ota sp number schema "sch".
2938      */
checkOtaSpNumBasedOnSysSelCode(int sysSelCodeInt, String sch[])2939     private static boolean checkOtaSpNumBasedOnSysSelCode(int sysSelCodeInt, String sch[]) {
2940         boolean isOtaSpNum = false;
2941         try {
2942             // Get how many number of system selection code ranges
2943             int selRc = Integer.parseInt(sch[1]);
2944             for (int i = 0; i < selRc; i++) {
2945                 if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
2946                     int selMin = Integer.parseInt(sch[i+2]);
2947                     int selMax = Integer.parseInt(sch[i+3]);
2948                     // Check if the selection code extracted from the dial string falls
2949                     // within any of the range pairs specified in the schema.
2950                     if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
2951                         isOtaSpNum = true;
2952                         break;
2953                     }
2954                 }
2955             }
2956         } catch (NumberFormatException ex) {
2957             // If the carrier ota sp number schema is not correct, we still allow dial
2958             // and only log the error:
2959             Rlog.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
2960         }
2961         return isOtaSpNum;
2962     }
2963 
2964     //CDMA
2965     /**
2966      * The following function checks if a dial string is a carrier specified
2967      * OTASP number or not by checking against the OTASP number schema stored
2968      * in PROPERTY_OTASP_NUM_SCHEMA.
2969      *
2970      * Currently, there are 2 schemas for carriers to specify the OTASP number:
2971      * 1) Use system selection code:
2972      *    The schema is:
2973      *    SELC,the # of code pairs,min1,max1,min2,max2,...
2974      *    e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
2975      *    selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
2976      *
2977      * 2) Use feature code:
2978      *    The schema is:
2979      *    "FC,length of feature code,feature code".
2980      *     e.g "FC,2,*2" indicates that the length of the feature code is 2,
2981      *     and the code itself is "*2".
2982      */
isCarrierOtaSpNum(String dialStr)2983     private boolean isCarrierOtaSpNum(String dialStr) {
2984         boolean isOtaSpNum = false;
2985         int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
2986         if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
2987             return isOtaSpNum;
2988         }
2989         // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
2990         if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
2991             Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
2992             if (DBG) {
2993                 Rlog.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
2994             }
2995 
2996             if (m.find()) {
2997                 String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
2998                 // If carrier uses system selection code mechanism
2999                 if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
3000                     if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
3001                         isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
3002                     } else {
3003                         if (DBG) {
3004                             Rlog.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
3005                         }
3006                     }
3007                 } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
3008                     int fcLen =  Integer.parseInt(sch[1]);
3009                     String fc = sch[2];
3010                     if (dialStr.regionMatches(0,fc,0,fcLen)) {
3011                         isOtaSpNum = true;
3012                     } else {
3013                         if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
3014                     }
3015                 } else {
3016                     if (DBG) {
3017                         Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
3018                     }
3019                 }
3020             } else {
3021                 if (DBG) {
3022                     Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
3023                             mCarrierOtaSpNumSchema);
3024                 }
3025             }
3026         } else {
3027             if (DBG) Rlog.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
3028         }
3029         return isOtaSpNum;
3030     }
3031 
3032     /**
3033      * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
3034      * OTASP dial string.
3035      *
3036      * @param dialStr the number to look up.
3037      * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
3038      */
3039     @Override
isOtaSpNumber(String dialStr)3040     public  boolean isOtaSpNumber(String dialStr) {
3041         if (isPhoneTypeGsm()) {
3042             return super.isOtaSpNumber(dialStr);
3043         } else {
3044             boolean isOtaSpNum = false;
3045             String dialableStr = PhoneNumberUtils.extractNetworkPortionAlt(dialStr);
3046             if (dialableStr != null) {
3047                 isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
3048                 if (isOtaSpNum == false) {
3049                     isOtaSpNum = isCarrierOtaSpNum(dialableStr);
3050                 }
3051             }
3052             if (DBG) Rlog.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
3053             return isOtaSpNum;
3054         }
3055     }
3056 
3057     @Override
getCdmaEriIconIndex()3058     public int getCdmaEriIconIndex() {
3059         if (isPhoneTypeGsm()) {
3060             return super.getCdmaEriIconIndex();
3061         } else {
3062             return getServiceState().getCdmaEriIconIndex();
3063         }
3064     }
3065 
3066     /**
3067      * Returns the CDMA ERI icon mode,
3068      * 0 - ON
3069      * 1 - FLASHING
3070      */
3071     @Override
getCdmaEriIconMode()3072     public int getCdmaEriIconMode() {
3073         if (isPhoneTypeGsm()) {
3074             return super.getCdmaEriIconMode();
3075         } else {
3076             return getServiceState().getCdmaEriIconMode();
3077         }
3078     }
3079 
3080     /**
3081      * Returns the CDMA ERI text,
3082      */
3083     @Override
getCdmaEriText()3084     public String getCdmaEriText() {
3085         if (isPhoneTypeGsm()) {
3086             return super.getCdmaEriText();
3087         } else {
3088             int roamInd = getServiceState().getCdmaRoamingIndicator();
3089             int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator();
3090             return mEriManager.getCdmaEriText(roamInd, defRoamInd);
3091         }
3092     }
3093 
phoneObjectUpdater(int newVoiceRadioTech)3094     private void phoneObjectUpdater(int newVoiceRadioTech) {
3095         logd("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech);
3096 
3097         // Check for a voice over lte replacement
3098         if (ServiceState.isLte(newVoiceRadioTech)
3099                 || (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) {
3100             CarrierConfigManager configMgr = (CarrierConfigManager)
3101                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
3102             PersistableBundle b = configMgr.getConfigForSubId(getSubId());
3103             if (b != null) {
3104                 int volteReplacementRat =
3105                         b.getInt(CarrierConfigManager.KEY_VOLTE_REPLACEMENT_RAT_INT);
3106                 logd("phoneObjectUpdater: volteReplacementRat=" + volteReplacementRat);
3107                 if (volteReplacementRat != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
3108                     newVoiceRadioTech = volteReplacementRat;
3109                 }
3110             } else {
3111                 loge("phoneObjectUpdater: didn't get volteReplacementRat from carrier config");
3112             }
3113         }
3114 
3115         if(mRilVersion == 6 && getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
3116             /*
3117              * On v6 RIL, when LTE_ON_CDMA is TRUE, always create CDMALTEPhone
3118              * irrespective of the voice radio tech reported.
3119              */
3120             if (getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
3121                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Use CDMA Phone" +
3122                         " newVoiceRadioTech=" + newVoiceRadioTech +
3123                         " mActivePhone=" + getPhoneName());
3124                 return;
3125             } else {
3126                 logd("phoneObjectUpdater: LTE ON CDMA property is set. Switch to CDMALTEPhone" +
3127                         " newVoiceRadioTech=" + newVoiceRadioTech +
3128                         " mActivePhone=" + getPhoneName());
3129                 newVoiceRadioTech = ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT;
3130             }
3131         } else {
3132 
3133             // If the device is shutting down, then there is no need to switch to the new phone
3134             // which might send unnecessary attach request to the modem.
3135             if (isShuttingDown()) {
3136                 logd("Device is shutting down. No need to switch phone now.");
3137                 return;
3138             }
3139 
3140             boolean matchCdma = ServiceState.isCdma(newVoiceRadioTech);
3141             boolean matchGsm = ServiceState.isGsm(newVoiceRadioTech);
3142             if ((matchCdma && getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) ||
3143                     (matchGsm && getPhoneType() == PhoneConstants.PHONE_TYPE_GSM)) {
3144                 // Nothing changed. Keep phone as it is.
3145                 logd("phoneObjectUpdater: No change ignore," +
3146                         " newVoiceRadioTech=" + newVoiceRadioTech +
3147                         " mActivePhone=" + getPhoneName());
3148                 return;
3149             }
3150             if (!matchCdma && !matchGsm) {
3151                 loge("phoneObjectUpdater: newVoiceRadioTech=" + newVoiceRadioTech +
3152                         " doesn't match either CDMA or GSM - error! No phone change");
3153                 return;
3154             }
3155         }
3156 
3157         if (newVoiceRadioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
3158             // We need some voice phone object to be active always, so never
3159             // delete the phone without anything to replace it with!
3160             logd("phoneObjectUpdater: Unknown rat ignore, "
3161                     + " newVoiceRadioTech=Unknown. mActivePhone=" + getPhoneName());
3162             return;
3163         }
3164 
3165         boolean oldPowerState = false; // old power state to off
3166         if (mResetModemOnRadioTechnologyChange) {
3167             if (mCi.getRadioState().isOn()) {
3168                 oldPowerState = true;
3169                 logd("phoneObjectUpdater: Setting Radio Power to Off");
3170                 mCi.setRadioPower(false, null);
3171             }
3172         }
3173 
3174         switchVoiceRadioTech(newVoiceRadioTech);
3175 
3176         if (mResetModemOnRadioTechnologyChange && oldPowerState) { // restore power state
3177             logd("phoneObjectUpdater: Resetting Radio");
3178             mCi.setRadioPower(oldPowerState, null);
3179         }
3180 
3181         // update voice radio tech in icc card proxy
3182         mIccCardProxy.setVoiceRadioTech(newVoiceRadioTech);
3183 
3184         // Send an Intent to the PhoneApp that we had a radio technology change
3185         Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
3186         intent.putExtra(PhoneConstants.PHONE_NAME_KEY, getPhoneName());
3187         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
3188         ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
3189     }
3190 
switchVoiceRadioTech(int newVoiceRadioTech)3191     private void switchVoiceRadioTech(int newVoiceRadioTech) {
3192 
3193         String outgoingPhoneName = getPhoneName();
3194 
3195         logd("Switching Voice Phone : " + outgoingPhoneName + " >>> "
3196                 + (ServiceState.isGsm(newVoiceRadioTech) ? "GSM" : "CDMA"));
3197 
3198         if (ServiceState.isCdma(newVoiceRadioTech)) {
3199             switchPhoneType(PhoneConstants.PHONE_TYPE_CDMA_LTE);
3200         } else if (ServiceState.isGsm(newVoiceRadioTech)) {
3201             switchPhoneType(PhoneConstants.PHONE_TYPE_GSM);
3202         } else {
3203             loge("deleteAndCreatePhone: newVoiceRadioTech=" + newVoiceRadioTech +
3204                     " is not CDMA or GSM (error) - aborting!");
3205             return;
3206         }
3207     }
3208 
3209     @Override
getIccSmsInterfaceManager()3210     public IccSmsInterfaceManager getIccSmsInterfaceManager(){
3211         return mIccSmsInterfaceManager;
3212     }
3213 
3214     @Override
updatePhoneObject(int voiceRadioTech)3215     public void updatePhoneObject(int voiceRadioTech) {
3216         logd("updatePhoneObject: radioTechnology=" + voiceRadioTech);
3217         sendMessage(obtainMessage(EVENT_UPDATE_PHONE_OBJECT, voiceRadioTech, 0, null));
3218     }
3219 
3220     @Override
setImsRegistrationState(boolean registered)3221     public void setImsRegistrationState(boolean registered) {
3222         mSST.setImsRegistrationState(registered);
3223     }
3224 
3225     @Override
getIccRecordsLoaded()3226     public boolean getIccRecordsLoaded() {
3227         return mIccCardProxy.getIccRecordsLoaded();
3228     }
3229 
3230     @Override
getIccCard()3231     public IccCard getIccCard() {
3232         return mIccCardProxy;
3233     }
3234 
3235     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)3236     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3237         pw.println("GsmCdmaPhone extends:");
3238         super.dump(fd, pw, args);
3239         pw.println(" mPrecisePhoneType=" + mPrecisePhoneType);
3240         pw.println(" mCT=" + mCT);
3241         pw.println(" mSST=" + mSST);
3242         pw.println(" mPendingMMIs=" + mPendingMMIs);
3243         pw.println(" mIccPhoneBookIntManager=" + mIccPhoneBookIntManager);
3244         if (VDBG) pw.println(" mImei=" + mImei);
3245         if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
3246         if (VDBG) pw.println(" mVmNumber=" + mVmNumber);
3247         pw.println(" mCdmaSSM=" + mCdmaSSM);
3248         pw.println(" mCdmaSubscriptionSource=" + mCdmaSubscriptionSource);
3249         pw.println(" mEriManager=" + mEriManager);
3250         pw.println(" mWakeLock=" + mWakeLock);
3251         pw.println(" mIsPhoneInEcmState=" + mIsPhoneInEcmState);
3252         if (VDBG) pw.println(" mEsn=" + mEsn);
3253         if (VDBG) pw.println(" mMeid=" + mMeid);
3254         pw.println(" mCarrierOtaSpNumSchema=" + mCarrierOtaSpNumSchema);
3255         if (!isPhoneTypeGsm()) {
3256             pw.println(" getCdmaEriIconIndex()=" + getCdmaEriIconIndex());
3257             pw.println(" getCdmaEriIconMode()=" + getCdmaEriIconMode());
3258             pw.println(" getCdmaEriText()=" + getCdmaEriText());
3259             pw.println(" isMinInfoReady()=" + isMinInfoReady());
3260         }
3261         pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled());
3262         pw.flush();
3263         pw.println("++++++++++++++++++++++++++++++++");
3264 
3265         try {
3266             mIccCardProxy.dump(fd, pw, args);
3267         } catch (Exception e) {
3268             e.printStackTrace();
3269         }
3270         pw.flush();
3271         pw.println("++++++++++++++++++++++++++++++++");
3272         pw.println("DeviceStateMonitor:");
3273         mDeviceStateMonitor.dump(fd, pw, args);
3274         pw.println("++++++++++++++++++++++++++++++++");
3275     }
3276 
3277     @Override
setOperatorBrandOverride(String brand)3278     public boolean setOperatorBrandOverride(String brand) {
3279         if (mUiccController == null) {
3280             return false;
3281         }
3282 
3283         UiccCard card = mUiccController.getUiccCard(getPhoneId());
3284         if (card == null) {
3285             return false;
3286         }
3287 
3288         boolean status = card.setOperatorBrandOverride(brand);
3289 
3290         // Refresh.
3291         if (status) {
3292             IccRecords iccRecords = mIccRecords.get();
3293             if (iccRecords != null) {
3294                 TelephonyManager.from(mContext).setSimOperatorNameForPhone(
3295                         getPhoneId(), iccRecords.getServiceProviderName());
3296             }
3297             if (mSST != null) {
3298                 mSST.pollState();
3299             }
3300         }
3301         return status;
3302     }
3303 
3304     /**
3305      * @return operator numeric.
3306      */
getOperatorNumeric()3307     private String getOperatorNumeric() {
3308         String operatorNumeric = null;
3309         if (isPhoneTypeGsm()) {
3310             IccRecords r = mIccRecords.get();
3311             if (r != null) {
3312                 operatorNumeric = r.getOperatorNumeric();
3313             }
3314         } else { //isPhoneTypeCdmaLte()
3315             IccRecords curIccRecords = null;
3316             if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_NV) {
3317                 operatorNumeric = SystemProperties.get("ro.cdma.home.operator.numeric");
3318             } else if (mCdmaSubscriptionSource == CDMA_SUBSCRIPTION_RUIM_SIM) {
3319                 curIccRecords = mSimRecords;
3320                 if (curIccRecords != null) {
3321                     operatorNumeric = curIccRecords.getOperatorNumeric();
3322                 } else {
3323                     curIccRecords = mIccRecords.get();
3324                     if (curIccRecords != null && (curIccRecords instanceof RuimRecords)) {
3325                         RuimRecords csim = (RuimRecords) curIccRecords;
3326                         operatorNumeric = csim.getRUIMOperatorNumeric();
3327                     }
3328                 }
3329             }
3330             if (operatorNumeric == null) {
3331                 loge("getOperatorNumeric: Cannot retrieve operatorNumeric:"
3332                         + " mCdmaSubscriptionSource = " + mCdmaSubscriptionSource +
3333                         " mIccRecords = " + ((curIccRecords != null) ?
3334                         curIccRecords.getRecordsLoaded() : null));
3335             }
3336 
3337             logd("getOperatorNumeric: mCdmaSubscriptionSource = " + mCdmaSubscriptionSource
3338                     + " operatorNumeric = " + operatorNumeric);
3339 
3340         }
3341         return operatorNumeric;
3342     }
3343 
3344     /**
3345      * @return The country ISO for the subscription associated with this phone.
3346      */
getCountryIso()3347     public String getCountryIso() {
3348         int subId = getSubId();
3349         SubscriptionInfo subInfo = SubscriptionManager.from(getContext())
3350                 .getActiveSubscriptionInfo(subId);
3351         if (subInfo == null) {
3352             return null;
3353         }
3354         return subInfo.getCountryIso().toUpperCase();
3355     }
3356 
notifyEcbmTimerReset(Boolean flag)3357     public void notifyEcbmTimerReset(Boolean flag) {
3358         mEcmTimerResetRegistrants.notifyResult(flag);
3359     }
3360 
3361     /**
3362      * Registration point for Ecm timer reset
3363      *
3364      * @param h handler to notify
3365      * @param what User-defined message code
3366      * @param obj placed in Message.obj
3367      */
3368     @Override
registerForEcmTimerReset(Handler h, int what, Object obj)3369     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
3370         mEcmTimerResetRegistrants.addUnique(h, what, obj);
3371     }
3372 
3373     @Override
unregisterForEcmTimerReset(Handler h)3374     public void unregisterForEcmTimerReset(Handler h) {
3375         mEcmTimerResetRegistrants.remove(h);
3376     }
3377 
3378     /**
3379      * Sets the SIM voice message waiting indicator records.
3380      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
3381      * @param countWaiting The number of messages waiting, if known. Use
3382      *                     -1 to indicate that an unknown number of
3383      *                      messages are waiting
3384      */
3385     @Override
setVoiceMessageWaiting(int line, int countWaiting)3386     public void setVoiceMessageWaiting(int line, int countWaiting) {
3387         if (isPhoneTypeGsm()) {
3388             IccRecords r = mIccRecords.get();
3389             if (r != null) {
3390                 r.setVoiceMessageWaiting(line, countWaiting);
3391             } else {
3392                 logd("SIM Records not found, MWI not updated");
3393             }
3394         } else {
3395             setVoiceMessageCount(countWaiting);
3396         }
3397     }
3398 
logd(String s)3399     private void logd(String s) {
3400         Rlog.d(LOG_TAG, "[GsmCdmaPhone] " + s);
3401     }
3402 
loge(String s)3403     private void loge(String s) {
3404         Rlog.e(LOG_TAG, "[GsmCdmaPhone] " + s);
3405     }
3406 
3407     @Override
isUtEnabled()3408     public boolean isUtEnabled() {
3409         Phone imsPhone = mImsPhone;
3410         if (imsPhone != null) {
3411             return imsPhone.isUtEnabled();
3412         } else {
3413             logd("isUtEnabled: called for GsmCdma");
3414             return false;
3415         }
3416     }
3417 
getDtmfToneDelayKey()3418     public String getDtmfToneDelayKey() {
3419         return isPhoneTypeGsm() ?
3420                 CarrierConfigManager.KEY_GSM_DTMF_TONE_DELAY_INT :
3421                 CarrierConfigManager.KEY_CDMA_DTMF_TONE_DELAY_INT;
3422     }
3423 
3424     @VisibleForTesting
getWakeLock()3425     public PowerManager.WakeLock getWakeLock() {
3426         return mWakeLock;
3427     }
3428 
3429 }
3430