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