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