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