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