Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2007 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 android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.content.SharedPreferences;
     24 import android.net.LinkProperties;
     25 import android.net.NetworkCapabilities;
     26 import android.net.wifi.WifiManager;
     27 import android.os.AsyncResult;
     28 import android.os.Build;
     29 import android.os.Bundle;
     30 import android.os.Handler;
     31 import android.os.Looper;
     32 import android.os.Message;
     33 import android.os.Registrant;
     34 import android.os.RegistrantList;
     35 import android.os.SystemProperties;
     36 import android.preference.PreferenceManager;
     37 import android.provider.Settings;
     38 import android.telecom.VideoProfile;
     39 import android.telephony.CellIdentityCdma;
     40 import android.telephony.CellInfo;
     41 import android.telephony.CellInfoCdma;
     42 import android.telephony.DataConnectionRealTimeInfo;
     43 import android.telephony.RadioAccessFamily;
     44 import android.telephony.Rlog;
     45 import android.telephony.ServiceState;
     46 import android.telephony.SignalStrength;
     47 import android.telephony.SubscriptionManager;
     48 import android.telephony.VoLteServiceState;
     49 import android.telephony.ModemActivityInfo;
     50 import android.text.TextUtils;
     51 
     52 import com.android.ims.ImsManager;
     53 import com.android.internal.R;
     54 import com.android.internal.telephony.dataconnection.DcTrackerBase;
     55 import com.android.internal.telephony.imsphone.ImsPhone;
     56 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
     57 import com.android.internal.telephony.test.SimulatedRadioControl;
     58 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
     59 import com.android.internal.telephony.uicc.IccFileHandler;
     60 import com.android.internal.telephony.uicc.IccRecords;
     61 import com.android.internal.telephony.uicc.IsimRecords;
     62 import com.android.internal.telephony.uicc.UiccCard;
     63 import com.android.internal.telephony.uicc.UiccCardApplication;
     64 import com.android.internal.telephony.uicc.UiccController;
     65 import com.android.internal.telephony.uicc.UsimServiceTable;
     66 
     67 import java.io.FileDescriptor;
     68 import java.io.PrintWriter;
     69 import java.util.ArrayList;
     70 import java.util.HashSet;
     71 import java.util.List;
     72 import java.util.Locale;
     73 import java.util.Set;
     74 import java.util.concurrent.atomic.AtomicReference;
     75 
     76 /**
     77  * (<em>Not for SDK use</em>)
     78  * A base implementation for the com.android.internal.telephony.Phone interface.
     79  *
     80  * Note that implementations of Phone.java are expected to be used
     81  * from a single application thread. This should be the same thread that
     82  * originally called PhoneFactory to obtain the interface.
     83  *
     84  *  {@hide}
     85  *
     86  */
     87 
     88 public abstract class PhoneBase extends Handler implements Phone {
     89     private static final String LOG_TAG = "PhoneBase";
     90 
     91     private boolean mImsIntentReceiverRegistered = false;
     92     private BroadcastReceiver mImsIntentReceiver = new BroadcastReceiver() {
     93         @Override
     94         public void onReceive(Context context, Intent intent) {
     95             Rlog.d(LOG_TAG, "mImsIntentReceiver: action " + intent.getAction());
     96             if (intent.hasExtra(ImsManager.EXTRA_PHONE_ID)) {
     97                 int extraPhoneId = intent.getIntExtra(ImsManager.EXTRA_PHONE_ID,
     98                         SubscriptionManager.INVALID_PHONE_INDEX);
     99                 Rlog.d(LOG_TAG, "mImsIntentReceiver: extraPhoneId = " + extraPhoneId);
    100                 if (extraPhoneId == SubscriptionManager.INVALID_PHONE_INDEX ||
    101                         extraPhoneId != getPhoneId()) {
    102                     return;
    103                 }
    104             }
    105 
    106             synchronized (PhoneProxy.lockForRadioTechnologyChange) {
    107                 if (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_UP)) {
    108                     mImsServiceReady = true;
    109                     updateImsPhone();
    110                 } else if (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_DOWN)) {
    111                     mImsServiceReady = false;
    112                     updateImsPhone();
    113                 }
    114             }
    115         }
    116     };
    117 
    118     // Key used to read and write the saved network selection numeric value
    119     public static final String NETWORK_SELECTION_KEY = "network_selection_key";
    120     // Key used to read and write the saved network selection operator name
    121     public static final String NETWORK_SELECTION_NAME_KEY = "network_selection_name_key";
    122     // Key used to read and write the saved network selection operator short name
    123     public static final String NETWORK_SELECTION_SHORT_KEY = "network_selection_short_key";
    124 
    125 
    126     // Key used to read/write "disable data connection on boot" pref (used for testing)
    127     public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key";
    128 
    129     /* Event Constants */
    130     protected static final int EVENT_RADIO_AVAILABLE             = 1;
    131     /** Supplementary Service Notification received. */
    132     protected static final int EVENT_SSN                         = 2;
    133     protected static final int EVENT_SIM_RECORDS_LOADED          = 3;
    134     protected static final int EVENT_MMI_DONE                    = 4;
    135     protected static final int EVENT_RADIO_ON                    = 5;
    136     protected static final int EVENT_GET_BASEBAND_VERSION_DONE   = 6;
    137     protected static final int EVENT_USSD                        = 7;
    138     protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE  = 8;
    139     protected static final int EVENT_GET_IMEI_DONE               = 9;
    140     protected static final int EVENT_GET_IMEISV_DONE             = 10;
    141     protected static final int EVENT_GET_SIM_STATUS_DONE         = 11;
    142     protected static final int EVENT_SET_CALL_FORWARD_DONE       = 12;
    143     protected static final int EVENT_GET_CALL_FORWARD_DONE       = 13;
    144     protected static final int EVENT_CALL_RING                   = 14;
    145     protected static final int EVENT_CALL_RING_CONTINUE          = 15;
    146 
    147     // Used to intercept the carrier selection calls so that
    148     // we can save the values.
    149     protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE    = 16;
    150     protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 17;
    151     protected static final int EVENT_SET_CLIR_COMPLETE              = 18;
    152     protected static final int EVENT_REGISTERED_TO_NETWORK          = 19;
    153     protected static final int EVENT_SET_VM_NUMBER_DONE             = 20;
    154     // Events for CDMA support
    155     protected static final int EVENT_GET_DEVICE_IDENTITY_DONE       = 21;
    156     protected static final int EVENT_RUIM_RECORDS_LOADED            = 22;
    157     protected static final int EVENT_NV_READY                       = 23;
    158     protected static final int EVENT_SET_ENHANCED_VP                = 24;
    159     protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER  = 25;
    160     protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 26;
    161     protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 27;
    162     // other
    163     protected static final int EVENT_SET_NETWORK_AUTOMATIC          = 28;
    164     protected static final int EVENT_ICC_RECORD_EVENTS              = 29;
    165     protected static final int EVENT_ICC_CHANGED                    = 30;
    166     // Single Radio Voice Call Continuity
    167     protected static final int EVENT_SRVCC_STATE_CHANGED            = 31;
    168     protected static final int EVENT_INITIATE_SILENT_REDIAL         = 32;
    169     protected static final int EVENT_RADIO_NOT_AVAILABLE            = 33;
    170     protected static final int EVENT_UNSOL_OEM_HOOK_RAW             = 34;
    171     protected static final int EVENT_GET_RADIO_CAPABILITY           = 35;
    172     protected static final int EVENT_SS                             = 36;
    173     protected static final int EVENT_CONFIG_LCE                     = 37;
    174     private static final int EVENT_CHECK_FOR_NETWORK_AUTOMATIC      = 38;
    175     protected static final int EVENT_LAST                           =
    176             EVENT_CHECK_FOR_NETWORK_AUTOMATIC;
    177 
    178     // For shared prefs.
    179     private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_";
    180     private static final String GSM_NON_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_non_roaming_list_";
    181     private static final String CDMA_ROAMING_LIST_OVERRIDE_PREFIX = "cdma_roaming_list_";
    182     private static final String CDMA_NON_ROAMING_LIST_OVERRIDE_PREFIX = "cdma_non_roaming_list_";
    183 
    184     // Key used to read/write current CLIR setting
    185     public static final String CLIR_KEY = "clir_key";
    186 
    187     // Key used for storing voice mail count
    188     public static final String VM_COUNT = "vm_count_key";
    189     // Key used to read/write the ID for storing the voice mail
    190     public static final String VM_ID = "vm_id_key";
    191 
    192     // Key used to read/write "disable DNS server check" pref (used for testing)
    193     public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key";
    194 
    195     /**
    196      * Small container class used to hold information relevant to
    197      * the carrier selection process. operatorNumeric can be ""
    198      * if we are looking for automatic selection. operatorAlphaLong is the
    199      * corresponding operator name.
    200      */
    201     protected static class NetworkSelectMessage {
    202         public Message message;
    203         public String operatorNumeric;
    204         public String operatorAlphaLong;
    205         public String operatorAlphaShort;
    206     }
    207 
    208     /* Instance Variables */
    209     public CommandsInterface mCi;
    210     private int mVmCount = 0;
    211     boolean mDnsCheckDisabled;
    212     public DcTrackerBase mDcTracker;
    213     boolean mDoesRilSendMultipleCallRing;
    214     int mCallRingContinueToken;
    215     int mCallRingDelay;
    216     public boolean mIsTheCurrentActivePhone = true;
    217     boolean mIsVoiceCapable = true;
    218 
    219     // Variable to cache the video capability. When RAT changes, we lose this info and are unable
    220     // to recover from the state. We cache it and notify listeners when they register.
    221     protected boolean mIsVideoCapable = false;
    222     protected UiccController mUiccController = null;
    223     public final AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
    224     public SmsStorageMonitor mSmsStorageMonitor;
    225     public SmsUsageMonitor mSmsUsageMonitor;
    226     protected AtomicReference<UiccCardApplication> mUiccApplication =
    227             new AtomicReference<UiccCardApplication>();
    228 
    229     private TelephonyTester mTelephonyTester;
    230     private final String mName;
    231     private final String mActionDetached;
    232     private final String mActionAttached;
    233 
    234     protected int mPhoneId;
    235 
    236     private boolean mImsServiceReady = false;
    237     protected ImsPhone mImsPhone = null;
    238 
    239     private final AtomicReference<RadioCapability> mRadioCapability =
    240             new AtomicReference<RadioCapability>();
    241 
    242     protected static final int DEFAULT_REPORT_INTERVAL_MS = 200;
    243     protected static final boolean LCE_PULL_MODE = true;
    244     protected int mReportInterval = 0;  // ms
    245     protected int mLceStatus = RILConstants.LCE_NOT_AVAILABLE;
    246 
    247     @Override
    248     public String getPhoneName() {
    249         return mName;
    250     }
    251 
    252     public String getNai(){
    253          return null;
    254     }
    255 
    256     /**
    257      * Return the ActionDetached string. When this action is received by components
    258      * they are to simulate detaching from the network.
    259      *
    260      * @return com.android.internal.telephony.{mName}.action_detached
    261      *          {mName} is GSM, CDMA ...
    262      */
    263     public String getActionDetached() {
    264         return mActionDetached;
    265     }
    266 
    267     /**
    268      * Return the ActionAttached string. When this action is received by components
    269      * they are to simulate attaching to the network.
    270      *
    271      * @return com.android.internal.telephony.{mName}.action_detached
    272      *          {mName} is GSM, CDMA ...
    273      */
    274     public String getActionAttached() {
    275         return mActionAttached;
    276     }
    277 
    278     /**
    279      * Set a system property, unless we're in unit test mode
    280      */
    281     // CAF_MSIM TODO this need to be replated with TelephonyManager API ?
    282     public void setSystemProperty(String property, String value) {
    283         if(getUnitTestMode()) {
    284             return;
    285         }
    286         SystemProperties.set(property, value);
    287     }
    288 
    289     /**
    290      * Set a system property, unless we're in unit test mode
    291      */
    292     // CAF_MSIM TODO this need to be replated with TelephonyManager API ?
    293     public String getSystemProperty(String property, String defValue) {
    294         if(getUnitTestMode()) {
    295             return null;
    296         }
    297         return SystemProperties.get(property, defValue);
    298     }
    299 
    300 
    301     protected final RegistrantList mPreciseCallStateRegistrants
    302             = new RegistrantList();
    303 
    304     protected final RegistrantList mHandoverRegistrants
    305              = new RegistrantList();
    306 
    307     protected final RegistrantList mNewRingingConnectionRegistrants
    308             = new RegistrantList();
    309 
    310     protected final RegistrantList mIncomingRingRegistrants
    311             = new RegistrantList();
    312 
    313     protected final RegistrantList mDisconnectRegistrants
    314             = new RegistrantList();
    315 
    316     protected final RegistrantList mServiceStateRegistrants
    317             = new RegistrantList();
    318 
    319     protected final RegistrantList mMmiCompleteRegistrants
    320             = new RegistrantList();
    321 
    322     protected final RegistrantList mMmiRegistrants
    323             = new RegistrantList();
    324 
    325     protected final RegistrantList mUnknownConnectionRegistrants
    326             = new RegistrantList();
    327 
    328     protected final RegistrantList mSuppServiceFailedRegistrants
    329             = new RegistrantList();
    330 
    331     protected final RegistrantList mRadioOffOrNotAvailableRegistrants
    332             = new RegistrantList();
    333 
    334     protected final RegistrantList mSimRecordsLoadedRegistrants
    335             = new RegistrantList();
    336 
    337     protected final RegistrantList mVideoCapabilityChangedRegistrants
    338             = new RegistrantList();
    339 
    340     protected final RegistrantList mEmergencyCallToggledRegistrants
    341             = new RegistrantList();
    342 
    343 
    344     protected Looper mLooper; /* to insure registrants are in correct thread*/
    345 
    346     protected final Context mContext;
    347 
    348     /**
    349      * PhoneNotifier is an abstraction for all system-wide
    350      * state change notification. DefaultPhoneNotifier is
    351      * used here unless running we're inside a unit test.
    352      */
    353     protected PhoneNotifier mNotifier;
    354 
    355     protected SimulatedRadioControl mSimulatedRadioControl;
    356 
    357     boolean mUnitTestMode;
    358 
    359     /**
    360      * Constructs a PhoneBase in normal (non-unit test) mode.
    361      *
    362      * @param notifier An instance of DefaultPhoneNotifier,
    363      * @param context Context object from hosting application
    364      * unless unit testing.
    365      * @param ci the CommandsInterface
    366      */
    367     protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci) {
    368         this(name, notifier, context, ci, false);
    369     }
    370 
    371     /**
    372      * Constructs a PhoneBase in normal (non-unit test) mode.
    373      *
    374      * @param notifier An instance of DefaultPhoneNotifier,
    375      * @param context Context object from hosting application
    376      * unless unit testing.
    377      * @param ci is CommandsInterface
    378      * @param unitTestMode when true, prevents notifications
    379      * of state change events
    380      */
    381     protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci,
    382             boolean unitTestMode) {
    383         this(name, notifier, context, ci, unitTestMode, SubscriptionManager.DEFAULT_PHONE_INDEX);
    384     }
    385 
    386     /**
    387      * Constructs a PhoneBase in normal (non-unit test) mode.
    388      *
    389      * @param notifier An instance of DefaultPhoneNotifier,
    390      * @param context Context object from hosting application
    391      * unless unit testing.
    392      * @param ci is CommandsInterface
    393      * @param unitTestMode when true, prevents notifications
    394      * of state change events
    395      * @param phoneId the phone-id of this phone.
    396      */
    397     protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci,
    398             boolean unitTestMode, int phoneId) {
    399         mPhoneId = phoneId;
    400         mName = name;
    401         mNotifier = notifier;
    402         mContext = context;
    403         mLooper = Looper.myLooper();
    404         mCi = ci;
    405         mActionDetached = this.getClass().getPackage().getName() + ".action_detached";
    406         mActionAttached = this.getClass().getPackage().getName() + ".action_attached";
    407 
    408         if (Build.IS_DEBUGGABLE) {
    409             mTelephonyTester = new TelephonyTester(this);
    410         }
    411 
    412         setUnitTestMode(unitTestMode);
    413 
    414         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
    415         mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
    416         mCi.setOnCallRing(this, EVENT_CALL_RING, null);
    417 
    418         /* "Voice capable" means that this device supports circuit-switched
    419         * (i.e. voice) phone calls over the telephony network, and is allowed
    420         * to display the in-call UI while a cellular voice call is active.
    421         * This will be false on "data only" devices which can't make voice
    422         * calls and don't support any in-call UI.
    423         */
    424         mIsVoiceCapable = mContext.getResources().getBoolean(
    425                 com.android.internal.R.bool.config_voice_capable);
    426 
    427         /**
    428          *  Some RIL's don't always send RIL_UNSOL_CALL_RING so it needs
    429          *  to be generated locally. Ideally all ring tones should be loops
    430          * and this wouldn't be necessary. But to minimize changes to upper
    431          * layers it is requested that it be generated by lower layers.
    432          *
    433          * By default old phones won't have the property set but do generate
    434          * the RIL_UNSOL_CALL_RING so the default if there is no property is
    435          * true.
    436          */
    437         mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(
    438                 TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);
    439         Rlog.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
    440 
    441         mCallRingDelay = SystemProperties.getInt(
    442                 TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);
    443         Rlog.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
    444 
    445         if (getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
    446             return;
    447         }
    448 
    449         // The locale from the "ro.carrier" system property or R.array.carrier_properties.
    450         // This will be overwritten by the Locale from the SIM language settings (EF-PL, EF-LI)
    451         // if applicable.
    452         final Locale carrierLocale = getLocaleFromCarrierProperties(mContext);
    453         if (carrierLocale != null && !TextUtils.isEmpty(carrierLocale.getCountry())) {
    454             final String country = carrierLocale.getCountry();
    455             try {
    456                 Settings.Global.getInt(mContext.getContentResolver(),
    457                         Settings.Global.WIFI_COUNTRY_CODE);
    458             } catch (Settings.SettingNotFoundException e) {
    459                 // note this is not persisting
    460                 WifiManager wM = (WifiManager)
    461                         mContext.getSystemService(Context.WIFI_SERVICE);
    462                 wM.setCountryCode(country, false);
    463             }
    464         }
    465 
    466         // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
    467         mSmsStorageMonitor = new SmsStorageMonitor(this);
    468         mSmsUsageMonitor = new SmsUsageMonitor(context);
    469         mUiccController = UiccController.getInstance();
    470         mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
    471         if (getPhoneType() != PhoneConstants.PHONE_TYPE_SIP) {
    472             mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null);
    473         }
    474         mCi.setOnUnsolOemHookRaw(this, EVENT_UNSOL_OEM_HOOK_RAW, null);
    475         mCi.startLceService(DEFAULT_REPORT_INTERVAL_MS, LCE_PULL_MODE,
    476                 obtainMessage(EVENT_CONFIG_LCE));
    477     }
    478 
    479     @Override
    480     public void startMonitoringImsService() {
    481         if (getPhoneType() == PhoneConstants.PHONE_TYPE_SIP) {
    482             return;
    483         }
    484 
    485         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
    486             IntentFilter filter = new IntentFilter();
    487             filter.addAction(ImsManager.ACTION_IMS_SERVICE_UP);
    488             filter.addAction(ImsManager.ACTION_IMS_SERVICE_DOWN);
    489             mContext.registerReceiver(mImsIntentReceiver, filter);
    490             mImsIntentReceiverRegistered = true;
    491 
    492             // Monitor IMS service - but first poll to see if already up (could miss
    493             // intent)
    494             ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
    495             if (imsManager != null && imsManager.isServiceAvailable()) {
    496                 mImsServiceReady = true;
    497                 updateImsPhone();
    498             }
    499         }
    500     }
    501 
    502     @Override
    503     public void dispose() {
    504         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
    505             if (mImsIntentReceiverRegistered) {
    506                 mContext.unregisterReceiver(mImsIntentReceiver);
    507                 mImsIntentReceiverRegistered = false;
    508             }
    509             mCi.unSetOnCallRing(this);
    510             // Must cleanup all connectionS and needs to use sendMessage!
    511             mDcTracker.cleanUpAllConnections(null);
    512             mIsTheCurrentActivePhone = false;
    513             // Dispose the SMS usage and storage monitors
    514             mSmsStorageMonitor.dispose();
    515             mSmsUsageMonitor.dispose();
    516             mUiccController.unregisterForIccChanged(this);
    517             mCi.unregisterForSrvccStateChanged(this);
    518             mCi.unSetOnUnsolOemHookRaw(this);
    519             mCi.stopLceService(obtainMessage(EVENT_CONFIG_LCE));
    520 
    521             if (mTelephonyTester != null) {
    522                 mTelephonyTester.dispose();
    523             }
    524 
    525             ImsPhone imsPhone = mImsPhone;
    526             if (imsPhone != null) {
    527                 imsPhone.unregisterForSilentRedial(this);
    528                 imsPhone.dispose();
    529             }
    530         }
    531     }
    532 
    533     @Override
    534     public void removeReferences() {
    535         mSmsStorageMonitor = null;
    536         mSmsUsageMonitor = null;
    537         mIccRecords.set(null);
    538         mUiccApplication.set(null);
    539         mDcTracker = null;
    540         mUiccController = null;
    541 
    542         ImsPhone imsPhone = mImsPhone;
    543         if (imsPhone != null) {
    544             imsPhone.removeReferences();
    545             mImsPhone = null;
    546         }
    547     }
    548 
    549     /**
    550      * When overridden the derived class needs to call
    551      * super.handleMessage(msg) so this method has a
    552      * a chance to process the message.
    553      *
    554      * @param msg
    555      */
    556     @Override
    557     public void handleMessage(Message msg) {
    558         AsyncResult ar;
    559 
    560         // messages to be handled whether or not the phone is being destroyed
    561         // should only include messages which are being re-directed and do not use
    562         // resources of the phone being destroyed
    563         // Note: make sure to add code in GSMPhone/CDMAPhone to re-direct here before
    564         // they check if phone destroyed.
    565         switch (msg.what) {
    566             // handle the select network completion callbacks.
    567             case EVENT_SET_NETWORK_MANUAL_COMPLETE:
    568             case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE:
    569                 handleSetSelectNetwork((AsyncResult) msg.obj);
    570                 return;
    571         }
    572 
    573         if (!mIsTheCurrentActivePhone) {
    574             Rlog.e(LOG_TAG, "Received message " + msg +
    575                     "[" + msg.what + "] while being destroyed. Ignoring.");
    576             return;
    577         }
    578         switch(msg.what) {
    579             case EVENT_CALL_RING:
    580                 Rlog.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState());
    581                 ar = (AsyncResult)msg.obj;
    582                 if (ar.exception == null) {
    583                     PhoneConstants.State state = getState();
    584                     if ((!mDoesRilSendMultipleCallRing)
    585                             && ((state == PhoneConstants.State.RINGING) ||
    586                                     (state == PhoneConstants.State.IDLE))) {
    587                         mCallRingContinueToken += 1;
    588                         sendIncomingCallRingNotification(mCallRingContinueToken);
    589                     } else {
    590                         notifyIncomingRing();
    591                     }
    592                 }
    593                 break;
    594 
    595             case EVENT_CALL_RING_CONTINUE:
    596                 Rlog.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received stat=" + getState());
    597                 if (getState() == PhoneConstants.State.RINGING) {
    598                     sendIncomingCallRingNotification(msg.arg1);
    599                 }
    600                 break;
    601 
    602             case EVENT_ICC_CHANGED:
    603                 onUpdateIccAvailability();
    604                 break;
    605 
    606             case EVENT_INITIATE_SILENT_REDIAL:
    607                 Rlog.d(LOG_TAG, "Event EVENT_INITIATE_SILENT_REDIAL Received");
    608                 ar = (AsyncResult) msg.obj;
    609                 if ((ar.exception == null) && (ar.result != null)) {
    610                     String dialString = (String) ar.result;
    611                     if (TextUtils.isEmpty(dialString)) return;
    612                     try {
    613                         dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, null);
    614                     } catch (CallStateException e) {
    615                         Rlog.e(LOG_TAG, "silent redial failed: " + e);
    616                     }
    617                 }
    618                 break;
    619 
    620             case EVENT_SRVCC_STATE_CHANGED:
    621                 ar = (AsyncResult)msg.obj;
    622                 if (ar.exception == null) {
    623                     handleSrvccStateChanged((int[]) ar.result);
    624                 } else {
    625                     Rlog.e(LOG_TAG, "Srvcc exception: " + ar.exception);
    626                 }
    627                 break;
    628 
    629             case EVENT_UNSOL_OEM_HOOK_RAW:
    630                 ar = (AsyncResult)msg.obj;
    631                 if (ar.exception == null) {
    632                     byte[] data = (byte[])ar.result;
    633                     Rlog.d(LOG_TAG, "EVENT_UNSOL_OEM_HOOK_RAW data="
    634                             + IccUtils.bytesToHexString(data));
    635                     mNotifier.notifyOemHookRawEventForSubscriber(getSubId(), data);
    636                 } else {
    637                     Rlog.e(LOG_TAG, "OEM hook raw exception: " + ar.exception);
    638                 }
    639                 break;
    640 
    641             case EVENT_GET_RADIO_CAPABILITY:
    642                 ar = (AsyncResult) msg.obj;
    643                 RadioCapability rc = (RadioCapability) ar.result;
    644                 if (ar.exception != null) {
    645                     Rlog.d(LOG_TAG, "get phone radio capability fail,"
    646                             + "no need to change mRadioCapability");
    647                 } else {
    648                     radioCapabilityUpdated(rc);
    649                 }
    650                 Rlog.d(LOG_TAG, "EVENT_GET_RADIO_CAPABILITY :"
    651                         + "phone rc : " + rc);
    652                 break;
    653 
    654             case EVENT_CONFIG_LCE:
    655                 ar = (AsyncResult) msg.obj;
    656                 if (ar.exception != null) {
    657                     Rlog.d(LOG_TAG, "config LCE service failed: " + ar.exception);
    658                 } else {
    659                     final ArrayList<Integer> statusInfo = (ArrayList<Integer>)ar.result;
    660                     mLceStatus = statusInfo.get(0);
    661                     mReportInterval = statusInfo.get(1);
    662                 }
    663                 break;
    664 
    665             case EVENT_CHECK_FOR_NETWORK_AUTOMATIC: {
    666                 onCheckForNetworkSelectionModeAutomatic(msg);
    667                 break;
    668             }
    669             default:
    670                 throw new RuntimeException("unexpected event not handled");
    671         }
    672     }
    673 
    674     private void handleSrvccStateChanged(int[] ret) {
    675         Rlog.d(LOG_TAG, "handleSrvccStateChanged");
    676 
    677         ArrayList<Connection> conn = null;
    678         ImsPhone imsPhone = mImsPhone;
    679         Call.SrvccState srvccState = Call.SrvccState.NONE;
    680         if (ret != null && ret.length != 0) {
    681             int state = ret[0];
    682             switch(state) {
    683                 case VoLteServiceState.HANDOVER_STARTED:
    684                     srvccState = Call.SrvccState.STARTED;
    685                     if (imsPhone != null) {
    686                         conn = imsPhone.getHandoverConnection();
    687                         migrateFrom(imsPhone);
    688                     } else {
    689                         Rlog.d(LOG_TAG, "HANDOVER_STARTED: mImsPhone null");
    690                     }
    691                     break;
    692                 case VoLteServiceState.HANDOVER_COMPLETED:
    693                     srvccState = Call.SrvccState.COMPLETED;
    694                     if (imsPhone != null) {
    695                         imsPhone.notifySrvccState(srvccState);
    696                     } else {
    697                         Rlog.d(LOG_TAG, "HANDOVER_COMPLETED: mImsPhone null");
    698                     }
    699                     break;
    700                 case VoLteServiceState.HANDOVER_FAILED:
    701                 case VoLteServiceState.HANDOVER_CANCELED:
    702                     srvccState = Call.SrvccState.FAILED;
    703                     break;
    704 
    705                 default:
    706                     //ignore invalid state
    707                     return;
    708             }
    709 
    710             getCallTracker().notifySrvccState(srvccState, conn);
    711 
    712             VoLteServiceState lteState = new VoLteServiceState(state);
    713             notifyVoLteServiceStateChanged(lteState);
    714         }
    715     }
    716 
    717     // Inherited documentation suffices.
    718     @Override
    719     public Context getContext() {
    720         return mContext;
    721     }
    722 
    723     // Will be called when icc changed
    724     protected abstract void onUpdateIccAvailability();
    725 
    726     /**
    727      * Disables the DNS check (i.e., allows "0.0.0.0").
    728      * Useful for lab testing environment.
    729      * @param b true disables the check, false enables.
    730      */
    731     @Override
    732     public void disableDnsCheck(boolean b) {
    733         mDnsCheckDisabled = b;
    734         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
    735         SharedPreferences.Editor editor = sp.edit();
    736         editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b);
    737         editor.apply();
    738     }
    739 
    740     /**
    741      * Returns true if the DNS check is currently disabled.
    742      */
    743     @Override
    744     public boolean isDnsCheckDisabled() {
    745         return mDnsCheckDisabled;
    746     }
    747 
    748     // Inherited documentation suffices.
    749     @Override
    750     public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {
    751         checkCorrectThread(h);
    752 
    753         mPreciseCallStateRegistrants.addUnique(h, what, obj);
    754     }
    755 
    756     // Inherited documentation suffices.
    757     @Override
    758     public void unregisterForPreciseCallStateChanged(Handler h) {
    759         mPreciseCallStateRegistrants.remove(h);
    760     }
    761 
    762     /**
    763      * Subclasses of Phone probably want to replace this with a
    764      * version scoped to their packages
    765      */
    766     protected void notifyPreciseCallStateChangedP() {
    767         AsyncResult ar = new AsyncResult(null, this, null);
    768         mPreciseCallStateRegistrants.notifyRegistrants(ar);
    769 
    770         mNotifier.notifyPreciseCallState(this);
    771     }
    772 
    773     @Override
    774     public void registerForHandoverStateChanged(Handler h, int what, Object obj) {
    775         checkCorrectThread(h);
    776         mHandoverRegistrants.addUnique(h, what, obj);
    777     }
    778 
    779     @Override
    780     public void unregisterForHandoverStateChanged(Handler h) {
    781         mHandoverRegistrants.remove(h);
    782     }
    783 
    784     /**
    785      * Subclasses of Phone probably want to replace this with a
    786      * version scoped to their packages
    787      */
    788     public void notifyHandoverStateChanged(Connection cn) {
    789        AsyncResult ar = new AsyncResult(null, cn, null);
    790        mHandoverRegistrants.notifyRegistrants(ar);
    791     }
    792 
    793     public void migrateFrom(PhoneBase from) {
    794         migrate(mHandoverRegistrants, from.mHandoverRegistrants);
    795         migrate(mPreciseCallStateRegistrants, from.mPreciseCallStateRegistrants);
    796         migrate(mNewRingingConnectionRegistrants, from.mNewRingingConnectionRegistrants);
    797         migrate(mIncomingRingRegistrants, from.mIncomingRingRegistrants);
    798         migrate(mDisconnectRegistrants, from.mDisconnectRegistrants);
    799         migrate(mServiceStateRegistrants, from.mServiceStateRegistrants);
    800         migrate(mMmiCompleteRegistrants, from.mMmiCompleteRegistrants);
    801         migrate(mMmiRegistrants, from.mMmiRegistrants);
    802         migrate(mUnknownConnectionRegistrants, from.mUnknownConnectionRegistrants);
    803         migrate(mSuppServiceFailedRegistrants, from.mSuppServiceFailedRegistrants);
    804     }
    805 
    806     public void migrate(RegistrantList to, RegistrantList from) {
    807         from.removeCleared();
    808         for (int i = 0, n = from.size(); i < n; i++) {
    809             to.add((Registrant) from.get(i));
    810         }
    811     }
    812 
    813     // Inherited documentation suffices.
    814     @Override
    815     public void registerForUnknownConnection(Handler h, int what, Object obj) {
    816         checkCorrectThread(h);
    817 
    818         mUnknownConnectionRegistrants.addUnique(h, what, obj);
    819     }
    820 
    821     // Inherited documentation suffices.
    822     @Override
    823     public void unregisterForUnknownConnection(Handler h) {
    824         mUnknownConnectionRegistrants.remove(h);
    825     }
    826 
    827     // Inherited documentation suffices.
    828     @Override
    829     public void registerForNewRingingConnection(
    830             Handler h, int what, Object obj) {
    831         checkCorrectThread(h);
    832 
    833         mNewRingingConnectionRegistrants.addUnique(h, what, obj);
    834     }
    835 
    836     // Inherited documentation suffices.
    837     @Override
    838     public void unregisterForNewRingingConnection(Handler h) {
    839         mNewRingingConnectionRegistrants.remove(h);
    840     }
    841 
    842     // Inherited documentation suffices.
    843     @Override
    844     public void registerForVideoCapabilityChanged(
    845             Handler h, int what, Object obj) {
    846         checkCorrectThread(h);
    847 
    848         mVideoCapabilityChangedRegistrants.addUnique(h, what, obj);
    849 
    850         // Notify any registrants of the cached video capability as soon as they register.
    851         notifyForVideoCapabilityChanged(mIsVideoCapable);
    852     }
    853 
    854     // Inherited documentation suffices.
    855     @Override
    856     public void unregisterForVideoCapabilityChanged(Handler h) {
    857         mVideoCapabilityChangedRegistrants.remove(h);
    858     }
    859 
    860     // Inherited documentation suffices.
    861     @Override
    862     public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
    863         mCi.registerForInCallVoicePrivacyOn(h, what, obj);
    864     }
    865 
    866     // Inherited documentation suffices.
    867     @Override
    868     public void unregisterForInCallVoicePrivacyOn(Handler h){
    869         mCi.unregisterForInCallVoicePrivacyOn(h);
    870     }
    871 
    872     // Inherited documentation suffices.
    873     @Override
    874     public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
    875         mCi.registerForInCallVoicePrivacyOff(h, what, obj);
    876     }
    877 
    878     // Inherited documentation suffices.
    879     @Override
    880     public void unregisterForInCallVoicePrivacyOff(Handler h){
    881         mCi.unregisterForInCallVoicePrivacyOff(h);
    882     }
    883 
    884     // Inherited documentation suffices.
    885     @Override
    886     public void registerForIncomingRing(
    887             Handler h, int what, Object obj) {
    888         checkCorrectThread(h);
    889 
    890         mIncomingRingRegistrants.addUnique(h, what, obj);
    891     }
    892 
    893     // Inherited documentation suffices.
    894     @Override
    895     public void unregisterForIncomingRing(Handler h) {
    896         mIncomingRingRegistrants.remove(h);
    897     }
    898 
    899     // Inherited documentation suffices.
    900     @Override
    901     public void registerForDisconnect(Handler h, int what, Object obj) {
    902         checkCorrectThread(h);
    903 
    904         mDisconnectRegistrants.addUnique(h, what, obj);
    905     }
    906 
    907     // Inherited documentation suffices.
    908     @Override
    909     public void unregisterForDisconnect(Handler h) {
    910         mDisconnectRegistrants.remove(h);
    911     }
    912 
    913     // Inherited documentation suffices.
    914     @Override
    915     public void registerForSuppServiceFailed(Handler h, int what, Object obj) {
    916         checkCorrectThread(h);
    917 
    918         mSuppServiceFailedRegistrants.addUnique(h, what, obj);
    919     }
    920 
    921     // Inherited documentation suffices.
    922     @Override
    923     public void unregisterForSuppServiceFailed(Handler h) {
    924         mSuppServiceFailedRegistrants.remove(h);
    925     }
    926 
    927     // Inherited documentation suffices.
    928     @Override
    929     public void registerForMmiInitiate(Handler h, int what, Object obj) {
    930         checkCorrectThread(h);
    931 
    932         mMmiRegistrants.addUnique(h, what, obj);
    933     }
    934 
    935     // Inherited documentation suffices.
    936     @Override
    937     public void unregisterForMmiInitiate(Handler h) {
    938         mMmiRegistrants.remove(h);
    939     }
    940 
    941     // Inherited documentation suffices.
    942     @Override
    943     public void registerForMmiComplete(Handler h, int what, Object obj) {
    944         checkCorrectThread(h);
    945 
    946         mMmiCompleteRegistrants.addUnique(h, what, obj);
    947     }
    948 
    949     // Inherited documentation suffices.
    950     @Override
    951     public void unregisterForMmiComplete(Handler h) {
    952         checkCorrectThread(h);
    953 
    954         mMmiCompleteRegistrants.remove(h);
    955     }
    956 
    957     public void registerForSimRecordsLoaded(Handler h, int what, Object obj) {
    958         logUnexpectedCdmaMethodCall("registerForSimRecordsLoaded");
    959     }
    960 
    961     public void unregisterForSimRecordsLoaded(Handler h) {
    962         logUnexpectedCdmaMethodCall("unregisterForSimRecordsLoaded");
    963     }
    964 
    965     @Override
    966     public void registerForTtyModeReceived(Handler h, int what, Object obj) {
    967     }
    968 
    969     @Override
    970     public void unregisterForTtyModeReceived(Handler h) {
    971     }
    972 
    973     @Override
    974     public void setNetworkSelectionModeAutomatic(Message response) {
    975         Rlog.d(LOG_TAG, "setNetworkSelectionModeAutomatic, querying current mode");
    976         // we don't want to do this unecesarily - it acutally causes
    977         // the radio to repeate network selection and is costly
    978         // first check if we're already in automatic mode
    979         Message msg = obtainMessage(EVENT_CHECK_FOR_NETWORK_AUTOMATIC);
    980         msg.obj = response;
    981         mCi.getNetworkSelectionMode(msg);
    982     }
    983 
    984     private void onCheckForNetworkSelectionModeAutomatic(Message fromRil) {
    985         AsyncResult ar = (AsyncResult)fromRil.obj;
    986         Message response = (Message)ar.userObj;
    987         boolean doAutomatic = true;
    988         if (ar.exception == null && ar.result != null) {
    989             try {
    990                 int[] modes = (int[])ar.result;
    991                 if (modes[0] == 0) {
    992                     // already confirmed to be in automatic mode - don't resend
    993                     doAutomatic = false;
    994                 }
    995             } catch (Exception e) {
    996                 // send the setting on error
    997             }
    998         }
    999         if (doAutomatic) {
   1000             // wrap the response message in our own message along with
   1001             // an empty string (to indicate automatic selection) for the
   1002             // operator's id.
   1003             NetworkSelectMessage nsm = new NetworkSelectMessage();
   1004             nsm.message = response;
   1005             nsm.operatorNumeric = "";
   1006             nsm.operatorAlphaLong = "";
   1007             nsm.operatorAlphaShort = "";
   1008 
   1009             Message msg = obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm);
   1010             mCi.setNetworkSelectionModeAutomatic(msg);
   1011 
   1012             updateSavedNetworkOperator(nsm);
   1013         } else {
   1014             Rlog.d(LOG_TAG, "setNetworkSelectionModeAutomatic - already auto, ignoring");
   1015         }
   1016     }
   1017 
   1018     @Override
   1019     public void getNetworkSelectionMode(Message message) {
   1020         mCi.getNetworkSelectionMode(message);
   1021     }
   1022 
   1023     @Override
   1024     public void selectNetworkManually(OperatorInfo network, Message response) {
   1025         // wrap the response message in our own message along with
   1026         // the operator's id.
   1027         NetworkSelectMessage nsm = new NetworkSelectMessage();
   1028         nsm.message = response;
   1029         nsm.operatorNumeric = network.getOperatorNumeric();
   1030         nsm.operatorAlphaLong = network.getOperatorAlphaLong();
   1031         nsm.operatorAlphaShort = network.getOperatorAlphaShort();
   1032 
   1033         Message msg = obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm);
   1034         mCi.setNetworkSelectionModeManual(network.getOperatorNumeric(), msg);
   1035 
   1036         updateSavedNetworkOperator(nsm);
   1037     }
   1038 
   1039     /**
   1040      * Registration point for emergency call/callback mode start. Message.obj is AsyncResult and
   1041      * Message.obj.result will be Integer indicating start of call by value 1 or end of call by
   1042      * value 0
   1043      * @param h handler to notify
   1044      * @param what what code of message when delivered
   1045      * @param obj placed in Message.obj.userObj
   1046      */
   1047     public void registerForEmergencyCallToggle(Handler h, int what, Object obj) {
   1048         Registrant r = new Registrant(h, what, obj);
   1049         mEmergencyCallToggledRegistrants.add(r);
   1050     }
   1051 
   1052     public void unregisterForEmergencyCallToggle(Handler h) {
   1053         mEmergencyCallToggledRegistrants.remove(h);
   1054     }
   1055 
   1056     private void updateSavedNetworkOperator(NetworkSelectMessage nsm) {
   1057         int subId = getSubId();
   1058         if (SubscriptionManager.isValidSubscriptionId(subId)) {
   1059             // open the shared preferences editor, and write the value.
   1060             // nsm.operatorNumeric is "" if we're in automatic.selection.
   1061             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
   1062             SharedPreferences.Editor editor = sp.edit();
   1063             editor.putString(NETWORK_SELECTION_KEY + subId, nsm.operatorNumeric);
   1064             editor.putString(NETWORK_SELECTION_NAME_KEY + subId, nsm.operatorAlphaLong);
   1065             editor.putString(NETWORK_SELECTION_SHORT_KEY + subId, nsm.operatorAlphaShort);
   1066 
   1067             // commit and log the result.
   1068             if (!editor.commit()) {
   1069                 Rlog.e(LOG_TAG, "failed to commit network selection preference");
   1070             }
   1071         } else {
   1072             Rlog.e(LOG_TAG, "Cannot update network selection preference due to invalid subId " +
   1073                     subId);
   1074         }
   1075     }
   1076 
   1077     /**
   1078      * Used to track the settings upon completion of the network change.
   1079      */
   1080     private void handleSetSelectNetwork(AsyncResult ar) {
   1081         // look for our wrapper within the asyncresult, skip the rest if it
   1082         // is null.
   1083         if (!(ar.userObj instanceof NetworkSelectMessage)) {
   1084             Rlog.e(LOG_TAG, "unexpected result from user object.");
   1085             return;
   1086         }
   1087 
   1088         NetworkSelectMessage nsm = (NetworkSelectMessage) ar.userObj;
   1089 
   1090         // found the object, now we send off the message we had originally
   1091         // attached to the request.
   1092         if (nsm.message != null) {
   1093             AsyncResult.forMessage(nsm.message, ar.result, ar.exception);
   1094             nsm.message.sendToTarget();
   1095         }
   1096     }
   1097 
   1098     /**
   1099      * Method to retrieve the saved operator from the Shared Preferences
   1100      */
   1101     private OperatorInfo getSavedNetworkSelection() {
   1102         // open the shared preferences and search with our key.
   1103         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
   1104         String numeric = sp.getString(NETWORK_SELECTION_KEY + getSubId(), "");
   1105         String name = sp.getString(NETWORK_SELECTION_NAME_KEY + getSubId(), "");
   1106         String shrt = sp.getString(NETWORK_SELECTION_SHORT_KEY + getSubId(), "");
   1107         return new OperatorInfo(numeric, name, shrt);
   1108     }
   1109 
   1110     /**
   1111      * Method to restore the previously saved operator id, or reset to
   1112      * automatic selection, all depending upon the value in the shared
   1113      * preferences.
   1114      */
   1115     public void restoreSavedNetworkSelection(Message response) {
   1116         // retrieve the operator
   1117         OperatorInfo networkSelection = getSavedNetworkSelection();
   1118 
   1119         // set to auto if the id is empty, otherwise select the network.
   1120         if (networkSelection == null || TextUtils.isEmpty(networkSelection.getOperatorNumeric())) {
   1121             setNetworkSelectionModeAutomatic(response);
   1122         } else {
   1123             selectNetworkManually(networkSelection, response);
   1124         }
   1125     }
   1126 
   1127     // Inherited documentation suffices.
   1128     @Override
   1129     public void setUnitTestMode(boolean f) {
   1130         mUnitTestMode = f;
   1131     }
   1132 
   1133     // Inherited documentation suffices.
   1134     @Override
   1135     public boolean getUnitTestMode() {
   1136         return mUnitTestMode;
   1137     }
   1138 
   1139     /**
   1140      * To be invoked when a voice call Connection disconnects.
   1141      *
   1142      * Subclasses of Phone probably want to replace this with a
   1143      * version scoped to their packages
   1144      */
   1145     protected void notifyDisconnectP(Connection cn) {
   1146         AsyncResult ar = new AsyncResult(null, cn, null);
   1147         mDisconnectRegistrants.notifyRegistrants(ar);
   1148     }
   1149 
   1150     // Inherited documentation suffices.
   1151     @Override
   1152     public void registerForServiceStateChanged(
   1153             Handler h, int what, Object obj) {
   1154         checkCorrectThread(h);
   1155 
   1156         mServiceStateRegistrants.add(h, what, obj);
   1157     }
   1158 
   1159     // Inherited documentation suffices.
   1160     @Override
   1161     public void unregisterForServiceStateChanged(Handler h) {
   1162         mServiceStateRegistrants.remove(h);
   1163     }
   1164 
   1165     // Inherited documentation suffices.
   1166     @Override
   1167     public void registerForRingbackTone(Handler h, int what, Object obj) {
   1168         mCi.registerForRingbackTone(h, what, obj);
   1169     }
   1170 
   1171     // Inherited documentation suffices.
   1172     @Override
   1173     public void unregisterForRingbackTone(Handler h) {
   1174         mCi.unregisterForRingbackTone(h);
   1175     }
   1176 
   1177     // Inherited documentation suffices.
   1178     @Override
   1179     public void registerForOnHoldTone(Handler h, int what, Object obj) {
   1180     }
   1181 
   1182     // Inherited documentation suffices.
   1183     @Override
   1184     public void unregisterForOnHoldTone(Handler h) {
   1185     }
   1186 
   1187     // Inherited documentation suffices.
   1188     @Override
   1189     public void registerForResendIncallMute(Handler h, int what, Object obj) {
   1190         mCi.registerForResendIncallMute(h, what, obj);
   1191     }
   1192 
   1193     // Inherited documentation suffices.
   1194     @Override
   1195     public void unregisterForResendIncallMute(Handler h) {
   1196         mCi.unregisterForResendIncallMute(h);
   1197     }
   1198 
   1199     @Override
   1200     public void setEchoSuppressionEnabled() {
   1201         // no need for regular phone
   1202     }
   1203 
   1204     /**
   1205      * Subclasses of Phone probably want to replace this with a
   1206      * version scoped to their packages
   1207      */
   1208     protected void notifyServiceStateChangedP(ServiceState ss) {
   1209         AsyncResult ar = new AsyncResult(null, ss, null);
   1210         mServiceStateRegistrants.notifyRegistrants(ar);
   1211 
   1212         mNotifier.notifyServiceState(this);
   1213     }
   1214 
   1215     // Inherited documentation suffices.
   1216     @Override
   1217     public SimulatedRadioControl getSimulatedRadioControl() {
   1218         return mSimulatedRadioControl;
   1219     }
   1220 
   1221     /**
   1222      * Verifies the current thread is the same as the thread originally
   1223      * used in the initialization of this instance. Throws RuntimeException
   1224      * if not.
   1225      *
   1226      * @exception RuntimeException if the current thread is not
   1227      * the thread that originally obtained this PhoneBase instance.
   1228      */
   1229     private void checkCorrectThread(Handler h) {
   1230         if (h.getLooper() != mLooper) {
   1231             throw new RuntimeException(
   1232                     "com.android.internal.telephony.Phone must be used from within one thread");
   1233         }
   1234     }
   1235 
   1236     /**
   1237      * Set the properties by matching the carrier string in
   1238      * a string-array resource
   1239      */
   1240     private static Locale getLocaleFromCarrierProperties(Context ctx) {
   1241         String carrier = SystemProperties.get("ro.carrier");
   1242 
   1243         if (null == carrier || 0 == carrier.length() || "unknown".equals(carrier)) {
   1244             return null;
   1245         }
   1246 
   1247         CharSequence[] carrierLocales = ctx.getResources().getTextArray(R.array.carrier_properties);
   1248 
   1249         for (int i = 0; i < carrierLocales.length; i+=3) {
   1250             String c = carrierLocales[i].toString();
   1251             if (carrier.equals(c)) {
   1252                 return Locale.forLanguageTag(carrierLocales[i + 1].toString().replace('_', '-'));
   1253             }
   1254         }
   1255 
   1256         return null;
   1257     }
   1258 
   1259     /**
   1260      * Get state
   1261      */
   1262     @Override
   1263     public abstract PhoneConstants.State getState();
   1264 
   1265     /**
   1266      * Retrieves the IccFileHandler of the Phone instance
   1267      */
   1268     public IccFileHandler getIccFileHandler(){
   1269         UiccCardApplication uiccApplication = mUiccApplication.get();
   1270         IccFileHandler fh;
   1271 
   1272         if (uiccApplication == null) {
   1273             Rlog.d(LOG_TAG, "getIccFileHandler: uiccApplication == null, return null");
   1274             fh = null;
   1275         } else {
   1276             fh = uiccApplication.getIccFileHandler();
   1277         }
   1278 
   1279         Rlog.d(LOG_TAG, "getIccFileHandler: fh=" + fh);
   1280         return fh;
   1281     }
   1282 
   1283     /*
   1284      * Retrieves the Handler of the Phone instance
   1285      */
   1286     public Handler getHandler() {
   1287         return this;
   1288     }
   1289 
   1290     @Override
   1291     public void updatePhoneObject(int voiceRadioTech) {
   1292         // Only the PhoneProxy can update the phone object.
   1293         PhoneFactory.getDefaultPhone().updatePhoneObject(voiceRadioTech);
   1294     }
   1295 
   1296     /**
   1297     * Retrieves the ServiceStateTracker of the phone instance.
   1298     */
   1299     public ServiceStateTracker getServiceStateTracker() {
   1300         return null;
   1301     }
   1302 
   1303     /**
   1304     * Get call tracker
   1305     */
   1306     public CallTracker getCallTracker() {
   1307         return null;
   1308     }
   1309 
   1310     public AppType getCurrentUiccAppType() {
   1311         UiccCardApplication currentApp = mUiccApplication.get();
   1312         if (currentApp != null) {
   1313             return currentApp.getType();
   1314         }
   1315         return AppType.APPTYPE_UNKNOWN;
   1316     }
   1317 
   1318     @Override
   1319     public IccCard getIccCard() {
   1320         return null;
   1321         //throw new Exception("getIccCard Shouldn't be called from PhoneBase");
   1322     }
   1323 
   1324     @Override
   1325     public String getIccSerialNumber() {
   1326         IccRecords r = mIccRecords.get();
   1327         return (r != null) ? r.getIccId() : null;
   1328     }
   1329 
   1330     @Override
   1331     public boolean getIccRecordsLoaded() {
   1332         IccRecords r = mIccRecords.get();
   1333         return (r != null) ? r.getRecordsLoaded() : false;
   1334     }
   1335 
   1336     /**
   1337      * @return all available cell information or null if none.
   1338      */
   1339     @Override
   1340     public List<CellInfo> getAllCellInfo() {
   1341         List<CellInfo> cellInfoList = getServiceStateTracker().getAllCellInfo();
   1342         return privatizeCellInfoList(cellInfoList);
   1343     }
   1344 
   1345     /**
   1346      * Clear CDMA base station lat/long values if location setting is disabled.
   1347      * @param cellInfoList the original cell info list from the RIL
   1348      * @return the original list with CDMA lat/long cleared if necessary
   1349      */
   1350     private List<CellInfo> privatizeCellInfoList(List<CellInfo> cellInfoList) {
   1351         if (cellInfoList == null) return null;
   1352         int mode = Settings.Secure.getInt(getContext().getContentResolver(),
   1353                 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
   1354         if (mode == Settings.Secure.LOCATION_MODE_OFF) {
   1355             ArrayList<CellInfo> privateCellInfoList = new ArrayList<CellInfo>(cellInfoList.size());
   1356             // clear lat/lon values for location privacy
   1357             for (CellInfo c : cellInfoList) {
   1358                 if (c instanceof CellInfoCdma) {
   1359                     CellInfoCdma cellInfoCdma = (CellInfoCdma) c;
   1360                     CellIdentityCdma cellIdentity = cellInfoCdma.getCellIdentity();
   1361                     CellIdentityCdma maskedCellIdentity = new CellIdentityCdma(
   1362                             cellIdentity.getNetworkId(),
   1363                             cellIdentity.getSystemId(),
   1364                             cellIdentity.getBasestationId(),
   1365                             Integer.MAX_VALUE, Integer.MAX_VALUE);
   1366                     CellInfoCdma privateCellInfoCdma = new CellInfoCdma(cellInfoCdma);
   1367                     privateCellInfoCdma.setCellIdentity(maskedCellIdentity);
   1368                     privateCellInfoList.add(privateCellInfoCdma);
   1369                 } else {
   1370                     privateCellInfoList.add(c);
   1371                 }
   1372             }
   1373             cellInfoList = privateCellInfoList;
   1374         }
   1375         return cellInfoList;
   1376     }
   1377 
   1378     /**
   1379      * {@inheritDoc}
   1380      */
   1381     @Override
   1382     public void setCellInfoListRate(int rateInMillis) {
   1383         mCi.setCellInfoListRate(rateInMillis, null);
   1384     }
   1385 
   1386     @Override
   1387     /** @return true if there are messages waiting, false otherwise. */
   1388     public boolean getMessageWaitingIndicator() {
   1389         return mVmCount != 0;
   1390     }
   1391 
   1392     @Override
   1393     public boolean getCallForwardingIndicator() {
   1394         IccRecords r = mIccRecords.get();
   1395         return (r != null) ? r.getVoiceCallForwardingFlag() : false;
   1396     }
   1397 
   1398     /**
   1399      *  Query the status of the CDMA roaming preference
   1400      */
   1401     @Override
   1402     public void queryCdmaRoamingPreference(Message response) {
   1403         mCi.queryCdmaRoamingPreference(response);
   1404     }
   1405 
   1406     /**
   1407      * Get the signal strength
   1408      */
   1409     @Override
   1410     public SignalStrength getSignalStrength() {
   1411         ServiceStateTracker sst = getServiceStateTracker();
   1412         if (sst == null) {
   1413             return new SignalStrength();
   1414         } else {
   1415             return sst.getSignalStrength();
   1416         }
   1417     }
   1418 
   1419     /**
   1420      *  Set the status of the CDMA roaming preference
   1421      */
   1422     @Override
   1423     public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
   1424         mCi.setCdmaRoamingPreference(cdmaRoamingType, response);
   1425     }
   1426 
   1427     /**
   1428      *  Set the status of the CDMA subscription mode
   1429      */
   1430     @Override
   1431     public void setCdmaSubscription(int cdmaSubscriptionType, Message response) {
   1432         mCi.setCdmaSubscriptionSource(cdmaSubscriptionType, response);
   1433     }
   1434 
   1435     /**
   1436      *  Set the preferred Network Type: Global, CDMA only or GSM/UMTS only
   1437      */
   1438     @Override
   1439     public void setPreferredNetworkType(int networkType, Message response) {
   1440         // Only set preferred network types to that which the modem supports
   1441         int modemRaf = getRadioAccessFamily();
   1442         int rafFromType = RadioAccessFamily.getRafFromNetworkType(networkType);
   1443 
   1444         if (modemRaf == RadioAccessFamily.RAF_UNKNOWN
   1445                 || rafFromType == RadioAccessFamily.RAF_UNKNOWN) {
   1446             Rlog.d(LOG_TAG, "setPreferredNetworkType: Abort, unknown RAF: "
   1447                     + modemRaf + " " + rafFromType);
   1448             if (response != null) {
   1449                 CommandException ex;
   1450 
   1451                 ex = new CommandException(CommandException.Error.GENERIC_FAILURE);
   1452                 AsyncResult.forMessage(response, null, ex);
   1453                 response.sendToTarget();
   1454             }
   1455             return;
   1456         }
   1457 
   1458         int filteredRaf = (rafFromType & modemRaf);
   1459         int filteredType = RadioAccessFamily.getNetworkTypeFromRaf(filteredRaf);
   1460 
   1461         Rlog.d(LOG_TAG, "setPreferredNetworkType: networkType = " + networkType
   1462                 + " modemRaf = " + modemRaf
   1463                 + " rafFromType = " + rafFromType
   1464                 + " filteredType = " + filteredType);
   1465 
   1466         mCi.setPreferredNetworkType(filteredType, response);
   1467     }
   1468 
   1469     @Override
   1470     public void getPreferredNetworkType(Message response) {
   1471         mCi.getPreferredNetworkType(response);
   1472     }
   1473 
   1474     @Override
   1475     public void getSmscAddress(Message result) {
   1476         mCi.getSmscAddress(result);
   1477     }
   1478 
   1479     @Override
   1480     public void setSmscAddress(String address, Message result) {
   1481         mCi.setSmscAddress(address, result);
   1482     }
   1483 
   1484     @Override
   1485     public void setTTYMode(int ttyMode, Message onComplete) {
   1486         mCi.setTTYMode(ttyMode, onComplete);
   1487     }
   1488 
   1489     @Override
   1490     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
   1491         Rlog.d(LOG_TAG, "unexpected setUiTTYMode method call");
   1492     }
   1493 
   1494     @Override
   1495     public void queryTTYMode(Message onComplete) {
   1496         mCi.queryTTYMode(onComplete);
   1497     }
   1498 
   1499     @Override
   1500     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
   1501         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1502         logUnexpectedCdmaMethodCall("enableEnhancedVoicePrivacy");
   1503     }
   1504 
   1505     @Override
   1506     public void getEnhancedVoicePrivacy(Message onComplete) {
   1507         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1508         logUnexpectedCdmaMethodCall("getEnhancedVoicePrivacy");
   1509     }
   1510 
   1511     @Override
   1512     public void setBandMode(int bandMode, Message response) {
   1513         mCi.setBandMode(bandMode, response);
   1514     }
   1515 
   1516     @Override
   1517     public void queryAvailableBandMode(Message response) {
   1518         mCi.queryAvailableBandMode(response);
   1519     }
   1520 
   1521     @Override
   1522     public void invokeOemRilRequestRaw(byte[] data, Message response) {
   1523         mCi.invokeOemRilRequestRaw(data, response);
   1524     }
   1525 
   1526     @Override
   1527     public void invokeOemRilRequestStrings(String[] strings, Message response) {
   1528         mCi.invokeOemRilRequestStrings(strings, response);
   1529     }
   1530 
   1531     @Override
   1532     public void nvReadItem(int itemID, Message response) {
   1533         mCi.nvReadItem(itemID, response);
   1534     }
   1535 
   1536     @Override
   1537     public void nvWriteItem(int itemID, String itemValue, Message response) {
   1538         mCi.nvWriteItem(itemID, itemValue, response);
   1539     }
   1540 
   1541     @Override
   1542     public void nvWriteCdmaPrl(byte[] preferredRoamingList, Message response) {
   1543         mCi.nvWriteCdmaPrl(preferredRoamingList, response);
   1544     }
   1545 
   1546     @Override
   1547     public void nvResetConfig(int resetType, Message response) {
   1548         mCi.nvResetConfig(resetType, response);
   1549     }
   1550 
   1551     @Override
   1552     public void notifyDataActivity() {
   1553         mNotifier.notifyDataActivity(this);
   1554     }
   1555 
   1556     public void notifyMessageWaitingIndicator() {
   1557         // Do not notify voice mail waiting if device doesn't support voice
   1558         if (!mIsVoiceCapable)
   1559             return;
   1560 
   1561         // This function is added to send the notification to DefaultPhoneNotifier.
   1562         mNotifier.notifyMessageWaitingChanged(this);
   1563     }
   1564 
   1565     public void notifyDataConnection(String reason, String apnType,
   1566             PhoneConstants.DataState state) {
   1567         mNotifier.notifyDataConnection(this, reason, apnType, state);
   1568     }
   1569 
   1570     public void notifyDataConnection(String reason, String apnType) {
   1571         mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
   1572     }
   1573 
   1574     public void notifyDataConnection(String reason) {
   1575         String types[] = getActiveApnTypes();
   1576         for (String apnType : types) {
   1577             mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
   1578         }
   1579     }
   1580 
   1581     public void notifyOtaspChanged(int otaspMode) {
   1582         mNotifier.notifyOtaspChanged(this, otaspMode);
   1583     }
   1584 
   1585     public void notifySignalStrength() {
   1586         mNotifier.notifySignalStrength(this);
   1587     }
   1588 
   1589     public void notifyCellInfo(List<CellInfo> cellInfo) {
   1590         mNotifier.notifyCellInfo(this, privatizeCellInfoList(cellInfo));
   1591     }
   1592 
   1593     public void notifyDataConnectionRealTimeInfo(DataConnectionRealTimeInfo dcRtInfo) {
   1594         mNotifier.notifyDataConnectionRealTimeInfo(this, dcRtInfo);
   1595     }
   1596 
   1597     public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) {
   1598         mNotifier.notifyVoLteServiceStateChanged(this, lteState);
   1599     }
   1600 
   1601     /**
   1602      * @return true if a mobile originating emergency call is active
   1603      */
   1604     public boolean isInEmergencyCall() {
   1605         return false;
   1606     }
   1607 
   1608     /**
   1609      * @return {@code true} if we are in emergency call back mode. This is a period where the phone
   1610      * should be using as little power as possible and be ready to receive an incoming call from the
   1611      * emergency operator.
   1612      */
   1613     public boolean isInEcm() {
   1614         return false;
   1615     }
   1616 
   1617     private static int getVideoState(Call call) {
   1618         int videoState = VideoProfile.STATE_AUDIO_ONLY;
   1619         ImsPhoneConnection conn = (ImsPhoneConnection) call.getEarliestConnection();
   1620         if (conn != null) {
   1621             videoState = conn.getVideoState();
   1622         }
   1623         return videoState;
   1624     }
   1625 
   1626     private boolean isVideoCall(Call call) {
   1627         int videoState = getVideoState(call);
   1628         return (VideoProfile.isVideo(videoState));
   1629     }
   1630 
   1631     @Override
   1632     public boolean isVideoCallPresent() {
   1633         boolean isVideoCallActive = false;
   1634         if (mImsPhone != null) {
   1635             isVideoCallActive = isVideoCall(mImsPhone.getForegroundCall()) ||
   1636                     isVideoCall(mImsPhone.getBackgroundCall()) ||
   1637                     isVideoCall(mImsPhone.getRingingCall());
   1638         }
   1639         Rlog.d(LOG_TAG, "isVideoCallActive: " + isVideoCallActive);
   1640         return isVideoCallActive;
   1641     }
   1642 
   1643     @Override
   1644     public abstract int getPhoneType();
   1645 
   1646     /** @hide */
   1647     /** @return number of voicemails */
   1648     @Override
   1649     public int getVoiceMessageCount(){
   1650         return mVmCount;
   1651     }
   1652 
   1653     /** sets the voice mail count of the phone and notifies listeners. */
   1654     public void setVoiceMessageCount(int countWaiting) {
   1655         mVmCount = countWaiting;
   1656         // notify listeners of voice mail
   1657         notifyMessageWaitingIndicator();
   1658     }
   1659 
   1660     /** gets the voice mail count from preferences */
   1661     protected int getStoredVoiceMessageCount() {
   1662         int countVoiceMessages = 0;
   1663         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
   1664         String subscriberId = sp.getString(VM_ID, null);
   1665         String currentSubscriberId = getSubscriberId();
   1666 
   1667         if ((subscriberId != null) && (currentSubscriberId != null)
   1668                 && (currentSubscriberId.equals(subscriberId))) {
   1669             // get voice mail count from preferences
   1670             countVoiceMessages = sp.getInt(VM_COUNT, 0);
   1671             Rlog.d(LOG_TAG, "Voice Mail Count from preference = " + countVoiceMessages);
   1672         } else {
   1673             Rlog.d(LOG_TAG, "Voicemail count retrieval returning 0 as count for matching " +
   1674                     "subscriberId not found");
   1675 
   1676         }
   1677         return countVoiceMessages;
   1678     }
   1679 
   1680     /**
   1681      * Returns the CDMA ERI icon index to display
   1682      */
   1683     @Override
   1684     public int getCdmaEriIconIndex() {
   1685         logUnexpectedCdmaMethodCall("getCdmaEriIconIndex");
   1686         return -1;
   1687     }
   1688 
   1689     /**
   1690      * Returns the CDMA ERI icon mode,
   1691      * 0 - ON
   1692      * 1 - FLASHING
   1693      */
   1694     @Override
   1695     public int getCdmaEriIconMode() {
   1696         logUnexpectedCdmaMethodCall("getCdmaEriIconMode");
   1697         return -1;
   1698     }
   1699 
   1700     /**
   1701      * Returns the CDMA ERI text,
   1702      */
   1703     @Override
   1704     public String getCdmaEriText() {
   1705         logUnexpectedCdmaMethodCall("getCdmaEriText");
   1706         return "GSM nw, no ERI";
   1707     }
   1708 
   1709     @Override
   1710     public String getCdmaMin() {
   1711         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1712         logUnexpectedCdmaMethodCall("getCdmaMin");
   1713         return null;
   1714     }
   1715 
   1716     @Override
   1717     public boolean isMinInfoReady() {
   1718         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1719         logUnexpectedCdmaMethodCall("isMinInfoReady");
   1720         return false;
   1721     }
   1722 
   1723     @Override
   1724     public String getCdmaPrlVersion(){
   1725         //  This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1726         logUnexpectedCdmaMethodCall("getCdmaPrlVersion");
   1727         return null;
   1728     }
   1729 
   1730     @Override
   1731     public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
   1732         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1733         logUnexpectedCdmaMethodCall("sendBurstDtmf");
   1734     }
   1735 
   1736     @Override
   1737     public void exitEmergencyCallbackMode() {
   1738         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1739         logUnexpectedCdmaMethodCall("exitEmergencyCallbackMode");
   1740     }
   1741 
   1742     @Override
   1743     public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
   1744         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1745         logUnexpectedCdmaMethodCall("registerForCdmaOtaStatusChange");
   1746     }
   1747 
   1748     @Override
   1749     public void unregisterForCdmaOtaStatusChange(Handler h) {
   1750         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1751         logUnexpectedCdmaMethodCall("unregisterForCdmaOtaStatusChange");
   1752     }
   1753 
   1754     @Override
   1755     public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
   1756         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1757         logUnexpectedCdmaMethodCall("registerForSubscriptionInfoReady");
   1758     }
   1759 
   1760     @Override
   1761     public void unregisterForSubscriptionInfoReady(Handler h) {
   1762         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1763         logUnexpectedCdmaMethodCall("unregisterForSubscriptionInfoReady");
   1764     }
   1765 
   1766     /**
   1767      * Returns true if OTA Service Provisioning needs to be performed.
   1768      * If not overridden return false.
   1769      */
   1770     @Override
   1771     public boolean needsOtaServiceProvisioning() {
   1772         return false;
   1773     }
   1774 
   1775     /**
   1776      * Return true if number is an OTASP number.
   1777      * If not overridden return false.
   1778      */
   1779     @Override
   1780     public  boolean isOtaSpNumber(String dialStr) {
   1781         return false;
   1782     }
   1783 
   1784     @Override
   1785     public void registerForCallWaiting(Handler h, int what, Object obj){
   1786         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1787         logUnexpectedCdmaMethodCall("registerForCallWaiting");
   1788     }
   1789 
   1790     @Override
   1791     public void unregisterForCallWaiting(Handler h){
   1792         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1793         logUnexpectedCdmaMethodCall("unregisterForCallWaiting");
   1794     }
   1795 
   1796     @Override
   1797     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
   1798         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1799         logUnexpectedCdmaMethodCall("registerForEcmTimerReset");
   1800     }
   1801 
   1802     @Override
   1803     public void unregisterForEcmTimerReset(Handler h) {
   1804         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1805         logUnexpectedCdmaMethodCall("unregisterForEcmTimerReset");
   1806     }
   1807 
   1808     @Override
   1809     public void registerForSignalInfo(Handler h, int what, Object obj) {
   1810         mCi.registerForSignalInfo(h, what, obj);
   1811     }
   1812 
   1813     @Override
   1814     public void unregisterForSignalInfo(Handler h) {
   1815         mCi.unregisterForSignalInfo(h);
   1816     }
   1817 
   1818     @Override
   1819     public void registerForDisplayInfo(Handler h, int what, Object obj) {
   1820         mCi.registerForDisplayInfo(h, what, obj);
   1821     }
   1822 
   1823      @Override
   1824     public void unregisterForDisplayInfo(Handler h) {
   1825          mCi.unregisterForDisplayInfo(h);
   1826      }
   1827 
   1828     @Override
   1829     public void registerForNumberInfo(Handler h, int what, Object obj) {
   1830         mCi.registerForNumberInfo(h, what, obj);
   1831     }
   1832 
   1833     @Override
   1834     public void unregisterForNumberInfo(Handler h) {
   1835         mCi.unregisterForNumberInfo(h);
   1836     }
   1837 
   1838     @Override
   1839     public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) {
   1840         mCi.registerForRedirectedNumberInfo(h, what, obj);
   1841     }
   1842 
   1843     @Override
   1844     public void unregisterForRedirectedNumberInfo(Handler h) {
   1845         mCi.unregisterForRedirectedNumberInfo(h);
   1846     }
   1847 
   1848     @Override
   1849     public void registerForLineControlInfo(Handler h, int what, Object obj) {
   1850         mCi.registerForLineControlInfo( h, what, obj);
   1851     }
   1852 
   1853     @Override
   1854     public void unregisterForLineControlInfo(Handler h) {
   1855         mCi.unregisterForLineControlInfo(h);
   1856     }
   1857 
   1858     @Override
   1859     public void registerFoT53ClirlInfo(Handler h, int what, Object obj) {
   1860         mCi.registerFoT53ClirlInfo(h, what, obj);
   1861     }
   1862 
   1863     @Override
   1864     public void unregisterForT53ClirInfo(Handler h) {
   1865         mCi.unregisterForT53ClirInfo(h);
   1866     }
   1867 
   1868     @Override
   1869     public void registerForT53AudioControlInfo(Handler h, int what, Object obj) {
   1870         mCi.registerForT53AudioControlInfo( h, what, obj);
   1871     }
   1872 
   1873     @Override
   1874     public void unregisterForT53AudioControlInfo(Handler h) {
   1875         mCi.unregisterForT53AudioControlInfo(h);
   1876     }
   1877 
   1878      @Override
   1879     public void setOnEcbModeExitResponse(Handler h, int what, Object obj){
   1880          // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1881          logUnexpectedCdmaMethodCall("setOnEcbModeExitResponse");
   1882      }
   1883 
   1884      @Override
   1885     public void unsetOnEcbModeExitResponse(Handler h){
   1886         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
   1887          logUnexpectedCdmaMethodCall("unsetOnEcbModeExitResponse");
   1888      }
   1889 
   1890     @Override
   1891     public void registerForRadioOffOrNotAvailable(Handler h, int what, Object obj) {
   1892         mRadioOffOrNotAvailableRegistrants.addUnique(h, what, obj);
   1893     }
   1894 
   1895     @Override
   1896     public void unregisterForRadioOffOrNotAvailable(Handler h) {
   1897         mRadioOffOrNotAvailableRegistrants.remove(h);
   1898     }
   1899 
   1900     @Override
   1901     public String[] getActiveApnTypes() {
   1902         return mDcTracker.getActiveApnTypes();
   1903     }
   1904 
   1905     @Override
   1906     public boolean hasMatchedTetherApnSetting() {
   1907         return mDcTracker.hasMatchedTetherApnSetting();
   1908     }
   1909 
   1910     @Override
   1911     public String getActiveApnHost(String apnType) {
   1912         return mDcTracker.getActiveApnString(apnType);
   1913     }
   1914 
   1915     @Override
   1916     public LinkProperties getLinkProperties(String apnType) {
   1917         return mDcTracker.getLinkProperties(apnType);
   1918     }
   1919 
   1920     @Override
   1921     public NetworkCapabilities getNetworkCapabilities(String apnType) {
   1922         return mDcTracker.getNetworkCapabilities(apnType);
   1923     }
   1924 
   1925     @Override
   1926     public boolean isDataConnectivityPossible() {
   1927         return isDataConnectivityPossible(PhoneConstants.APN_TYPE_DEFAULT);
   1928     }
   1929 
   1930     @Override
   1931     public boolean isDataConnectivityPossible(String apnType) {
   1932         return ((mDcTracker != null) &&
   1933                 (mDcTracker.isDataPossible(apnType)));
   1934     }
   1935 
   1936     /**
   1937      * Notify registrants of a new ringing Connection.
   1938      * Subclasses of Phone probably want to replace this with a
   1939      * version scoped to their packages
   1940      */
   1941     public void notifyNewRingingConnectionP(Connection cn) {
   1942         if (!mIsVoiceCapable)
   1943             return;
   1944         AsyncResult ar = new AsyncResult(null, cn, null);
   1945         mNewRingingConnectionRegistrants.notifyRegistrants(ar);
   1946     }
   1947 
   1948 
   1949     /**
   1950      * Notify registrants if phone is video capable.
   1951      */
   1952     public void notifyForVideoCapabilityChanged(boolean isVideoCallCapable) {
   1953         // Cache the current video capability so that we don't lose the information.
   1954         mIsVideoCapable = isVideoCallCapable;
   1955 
   1956         AsyncResult ar = new AsyncResult(null, isVideoCallCapable, null);
   1957         mVideoCapabilityChangedRegistrants.notifyRegistrants(ar);
   1958     }
   1959 
   1960     /**
   1961      * Notify registrants of a RING event.
   1962      */
   1963     private void notifyIncomingRing() {
   1964         if (!mIsVoiceCapable)
   1965             return;
   1966         AsyncResult ar = new AsyncResult(null, this, null);
   1967         mIncomingRingRegistrants.notifyRegistrants(ar);
   1968     }
   1969 
   1970     /**
   1971      * Send the incoming call Ring notification if conditions are right.
   1972      */
   1973     private void sendIncomingCallRingNotification(int token) {
   1974         if (mIsVoiceCapable && !mDoesRilSendMultipleCallRing &&
   1975                 (token == mCallRingContinueToken)) {
   1976             Rlog.d(LOG_TAG, "Sending notifyIncomingRing");
   1977             notifyIncomingRing();
   1978             sendMessageDelayed(
   1979                     obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);
   1980         } else {
   1981             Rlog.d(LOG_TAG, "Ignoring ring notification request,"
   1982                     + " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing
   1983                     + " token=" + token
   1984                     + " mCallRingContinueToken=" + mCallRingContinueToken
   1985                     + " mIsVoiceCapable=" + mIsVoiceCapable);
   1986         }
   1987     }
   1988 
   1989     @Override
   1990     public boolean isCspPlmnEnabled() {
   1991         // This function should be overridden by the class GSMPhone.
   1992         // Not implemented in CDMAPhone.
   1993         logUnexpectedGsmMethodCall("isCspPlmnEnabled");
   1994         return false;
   1995     }
   1996 
   1997     @Override
   1998     public IsimRecords getIsimRecords() {
   1999         Rlog.e(LOG_TAG, "getIsimRecords() is only supported on LTE devices");
   2000         return null;
   2001     }
   2002 
   2003     @Override
   2004     public String getMsisdn() {
   2005         logUnexpectedGsmMethodCall("getMsisdn");
   2006         return null;
   2007     }
   2008 
   2009     /**
   2010      * Common error logger method for unexpected calls to CDMA-only methods.
   2011      */
   2012     private static void logUnexpectedCdmaMethodCall(String name)
   2013     {
   2014         Rlog.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
   2015                 "called, CDMAPhone inactive.");
   2016     }
   2017 
   2018     @Override
   2019     public PhoneConstants.DataState getDataConnectionState() {
   2020         return getDataConnectionState(PhoneConstants.APN_TYPE_DEFAULT);
   2021     }
   2022 
   2023     /**
   2024      * Common error logger method for unexpected calls to GSM/WCDMA-only methods.
   2025      */
   2026     private static void logUnexpectedGsmMethodCall(String name) {
   2027         Rlog.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
   2028                 "called, GSMPhone inactive.");
   2029     }
   2030 
   2031     // Called by SimRecords which is constructed with a PhoneBase instead of a GSMPhone.
   2032     public void notifyCallForwardingIndicator() {
   2033         // This function should be overridden by the class GSMPhone. Not implemented in CDMAPhone.
   2034         Rlog.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
   2035     }
   2036 
   2037     public void notifyDataConnectionFailed(String reason, String apnType) {
   2038         mNotifier.notifyDataConnectionFailed(this, reason, apnType);
   2039     }
   2040 
   2041     public void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
   2042             String failCause) {
   2043         mNotifier.notifyPreciseDataConnectionFailed(this, reason, apnType, apn, failCause);
   2044     }
   2045 
   2046     /**
   2047      * {@inheritDoc}
   2048      */
   2049     @Override
   2050     public int getLteOnCdmaMode() {
   2051         return mCi.getLteOnCdmaMode();
   2052     }
   2053 
   2054     public void setVoiceMessageWaiting(int line, int countWaiting) {
   2055         // This function should be overridden by class GSMPhone and CDMAPhone.
   2056         Rlog.e(LOG_TAG, "Error! This function should never be executed, inactive Phone.");
   2057     }
   2058 
   2059     /**
   2060      * Gets the USIM service table from the UICC, if present and available.
   2061      * @return an interface to the UsimServiceTable record, or null if not available
   2062      */
   2063     @Override
   2064     public UsimServiceTable getUsimServiceTable() {
   2065         IccRecords r = mIccRecords.get();
   2066         return (r != null) ? r.getUsimServiceTable() : null;
   2067     }
   2068 
   2069     /**
   2070      * Gets the Uicc card corresponding to this phone.
   2071      * @return the UiccCard object corresponding to the phone ID.
   2072      */
   2073     @Override
   2074     public UiccCard getUiccCard() {
   2075         return mUiccController.getUiccCard(mPhoneId);
   2076     }
   2077 
   2078     /**
   2079      * Get P-CSCF address from PCO after data connection is established or modified.
   2080      * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
   2081      */
   2082     @Override
   2083     public String[] getPcscfAddress(String apnType) {
   2084         return mDcTracker.getPcscfAddress(apnType);
   2085     }
   2086 
   2087     /**
   2088      * Set IMS registration state
   2089      */
   2090     @Override
   2091     public void setImsRegistrationState(boolean registered) {
   2092         mDcTracker.setImsRegistrationState(registered);
   2093     }
   2094 
   2095     /**
   2096      * Return an instance of a IMS phone
   2097      */
   2098     @Override
   2099     public Phone getImsPhone() {
   2100         return mImsPhone;
   2101     }
   2102 
   2103     @Override
   2104     public ImsPhone relinquishOwnershipOfImsPhone() {
   2105         synchronized (PhoneProxy.lockForRadioTechnologyChange) {
   2106             if (mImsPhone == null)
   2107                 return null;
   2108 
   2109             if (mImsIntentReceiverRegistered) {
   2110                 mContext.unregisterReceiver(mImsIntentReceiver);
   2111                 mImsIntentReceiverRegistered = false;
   2112             }
   2113 
   2114             ImsPhone imsPhone = mImsPhone;
   2115             mImsPhone = null;
   2116 
   2117             CallManager.getInstance().unregisterPhone(imsPhone);
   2118             imsPhone.unregisterForSilentRedial(this);
   2119 
   2120             return imsPhone;
   2121         }
   2122     }
   2123 
   2124     @Override
   2125     public void acquireOwnershipOfImsPhone(ImsPhone imsPhone) {
   2126         synchronized (PhoneProxy.lockForRadioTechnologyChange) {
   2127             if (imsPhone == null)
   2128                 return;
   2129 
   2130             if (mImsPhone != null) {
   2131                 Rlog.e(LOG_TAG, "acquireOwnershipOfImsPhone: non-null mImsPhone." +
   2132                         " Shouldn't happen - but disposing");
   2133                 mImsPhone.dispose();
   2134                 // Potential GC issue if someone keeps a reference to ImsPhone.
   2135                 // However: this change will make sure that such a reference does
   2136                 // not access functions through NULL pointer.
   2137                 //mImsPhone.removeReferences();
   2138             }
   2139 
   2140             mImsPhone = imsPhone;
   2141 
   2142             mImsServiceReady = true;
   2143             mImsPhone.updateParentPhone(this);
   2144             CallManager.getInstance().registerPhone(mImsPhone);
   2145             mImsPhone.registerForSilentRedial(
   2146                     this, EVENT_INITIATE_SILENT_REDIAL, null);
   2147         }
   2148     }
   2149 
   2150     protected void updateImsPhone() {
   2151         Rlog.d(LOG_TAG, "updateImsPhone"
   2152                 + " mImsServiceReady=" + mImsServiceReady);
   2153 
   2154         if (mImsServiceReady && (mImsPhone == null)) {
   2155             mImsPhone = PhoneFactory.makeImsPhone(mNotifier, this);
   2156             CallManager.getInstance().registerPhone(mImsPhone);
   2157             mImsPhone.registerForSilentRedial(
   2158                     this, EVENT_INITIATE_SILENT_REDIAL, null);
   2159         } else if (!mImsServiceReady && (mImsPhone != null)) {
   2160             CallManager.getInstance().unregisterPhone(mImsPhone);
   2161             mImsPhone.unregisterForSilentRedial(this);
   2162 
   2163             mImsPhone.dispose();
   2164             // Potential GC issue if someone keeps a reference to ImsPhone.
   2165             // However: this change will make sure that such a reference does
   2166             // not access functions through NULL pointer.
   2167             //mImsPhone.removeReferences();
   2168             mImsPhone = null;
   2169         }
   2170     }
   2171 
   2172     /**
   2173      * Dials a number.
   2174      *
   2175      * @param dialString The number to dial.
   2176      * @param uusInfo The UUSInfo.
   2177      * @param videoState The video state for the call.
   2178      * @param intentExtras Extras from the original CALL intent.
   2179      * @return The Connection.
   2180      * @throws CallStateException
   2181      */
   2182     protected Connection dialInternal(
   2183             String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
   2184             throws CallStateException {
   2185         // dialInternal shall be overriden by GSMPhone and CDMAPhone
   2186         return null;
   2187     }
   2188 
   2189     /**
   2190      * Returns the subscription id.
   2191      */
   2192     public int getSubId() {
   2193         return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhoneId);
   2194     }
   2195 
   2196     /**
   2197      * Returns the phone id.
   2198      */
   2199     public int getPhoneId() {
   2200         return mPhoneId;
   2201     }
   2202 
   2203     /**
   2204      * Return the service state of mImsPhone if it is STATE_IN_SERVICE
   2205      * otherwise return the current voice service state
   2206      */
   2207     @Override
   2208     public int getVoicePhoneServiceState() {
   2209         ImsPhone imsPhone = mImsPhone;
   2210         if (imsPhone != null
   2211                 && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) {
   2212             return ServiceState.STATE_IN_SERVICE;
   2213         }
   2214         return getServiceState().getState();
   2215     }
   2216 
   2217     @Override
   2218     public boolean setOperatorBrandOverride(String brand) {
   2219         return false;
   2220     }
   2221 
   2222     @Override
   2223     public boolean setRoamingOverride(List<String> gsmRoamingList,
   2224             List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
   2225             List<String> cdmaNonRoamingList) {
   2226         String iccId = getIccSerialNumber();
   2227         if (TextUtils.isEmpty(iccId)) {
   2228             return false;
   2229         }
   2230 
   2231         setRoamingOverrideHelper(gsmRoamingList, GSM_ROAMING_LIST_OVERRIDE_PREFIX, iccId);
   2232         setRoamingOverrideHelper(gsmNonRoamingList, GSM_NON_ROAMING_LIST_OVERRIDE_PREFIX, iccId);
   2233         setRoamingOverrideHelper(cdmaRoamingList, CDMA_ROAMING_LIST_OVERRIDE_PREFIX, iccId);
   2234         setRoamingOverrideHelper(cdmaNonRoamingList, CDMA_NON_ROAMING_LIST_OVERRIDE_PREFIX, iccId);
   2235 
   2236         // Refresh.
   2237         ServiceStateTracker tracker = getServiceStateTracker();
   2238         if (tracker != null) {
   2239             tracker.pollState();
   2240         }
   2241         return true;
   2242     }
   2243 
   2244     private void setRoamingOverrideHelper(List<String> list, String prefix, String iccId) {
   2245         SharedPreferences.Editor spEditor =
   2246                 PreferenceManager.getDefaultSharedPreferences(mContext).edit();
   2247         String key = prefix + iccId;
   2248         if (list == null || list.isEmpty()) {
   2249             spEditor.remove(key).commit();
   2250         } else {
   2251             spEditor.putStringSet(key, new HashSet<String>(list)).commit();
   2252         }
   2253     }
   2254 
   2255     public boolean isMccMncMarkedAsRoaming(String mccMnc) {
   2256         return getRoamingOverrideHelper(GSM_ROAMING_LIST_OVERRIDE_PREFIX, mccMnc);
   2257     }
   2258 
   2259     public boolean isMccMncMarkedAsNonRoaming(String mccMnc) {
   2260         return getRoamingOverrideHelper(GSM_NON_ROAMING_LIST_OVERRIDE_PREFIX, mccMnc);
   2261     }
   2262 
   2263     public boolean isSidMarkedAsRoaming(int SID) {
   2264         return getRoamingOverrideHelper(CDMA_ROAMING_LIST_OVERRIDE_PREFIX,
   2265                 Integer.toString(SID));
   2266     }
   2267 
   2268     public boolean isSidMarkedAsNonRoaming(int SID) {
   2269         return getRoamingOverrideHelper(CDMA_NON_ROAMING_LIST_OVERRIDE_PREFIX,
   2270                 Integer.toString(SID));
   2271     }
   2272 
   2273     /**
   2274      * Get IMS Registration Status
   2275      */
   2276     @Override
   2277     public boolean isImsRegistered() {
   2278         ImsPhone imsPhone = mImsPhone;
   2279         boolean isImsRegistered = false;
   2280         if (imsPhone != null) {
   2281             isImsRegistered = imsPhone.isImsRegistered();
   2282         } else {
   2283             ServiceStateTracker sst = getServiceStateTracker();
   2284             if (sst != null) {
   2285                 isImsRegistered = sst.isImsRegistered();
   2286             }
   2287         }
   2288         Rlog.d(LOG_TAG, "isImsRegistered =" + isImsRegistered);
   2289         return isImsRegistered;
   2290     }
   2291 
   2292     /**
   2293      * Get Wifi Calling Feature Availability
   2294      */
   2295     @Override
   2296     public boolean isWifiCallingEnabled() {
   2297         ImsPhone imsPhone = mImsPhone;
   2298         boolean isWifiCallingEnabled = false;
   2299         if (imsPhone != null) {
   2300             isWifiCallingEnabled = imsPhone.isVowifiEnabled();
   2301         }
   2302         Rlog.d(LOG_TAG, "isWifiCallingEnabled =" + isWifiCallingEnabled);
   2303         return isWifiCallingEnabled;
   2304     }
   2305 
   2306     /**
   2307      * Get Volte Feature Availability
   2308      */
   2309     @Override
   2310     public boolean isVolteEnabled() {
   2311         ImsPhone imsPhone = mImsPhone;
   2312         boolean isVolteEnabled = false;
   2313         if (imsPhone != null) {
   2314             isVolteEnabled = imsPhone.isVolteEnabled();
   2315         }
   2316         Rlog.d(LOG_TAG, "isImsRegistered =" + isVolteEnabled);
   2317         return isVolteEnabled;
   2318     }
   2319 
   2320     private boolean getRoamingOverrideHelper(String prefix, String key) {
   2321         String iccId = getIccSerialNumber();
   2322         if (TextUtils.isEmpty(iccId) || TextUtils.isEmpty(key)) {
   2323             return false;
   2324         }
   2325 
   2326         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
   2327         Set<String> value = sp.getStringSet(prefix + iccId, null);
   2328         if (value == null) {
   2329             return false;
   2330         }
   2331         return value.contains(key);
   2332     }
   2333 
   2334     @Override
   2335     public boolean isRadioAvailable() {
   2336         return mCi.getRadioState().isAvailable();
   2337     }
   2338 
   2339     @Override
   2340     public boolean isRadioOn() {
   2341         return mCi.getRadioState().isOn();
   2342     }
   2343 
   2344     @Override
   2345     public void shutdownRadio() {
   2346         getServiceStateTracker().requestShutdown();
   2347     }
   2348 
   2349     @Override
   2350     public void setRadioCapability(RadioCapability rc, Message response) {
   2351         mCi.setRadioCapability(rc, response);
   2352     }
   2353 
   2354     @Override
   2355     public int getRadioAccessFamily() {
   2356         final RadioCapability rc = getRadioCapability();
   2357         return (rc == null ? RadioAccessFamily.RAF_UNKNOWN : rc.getRadioAccessFamily());
   2358     }
   2359 
   2360     @Override
   2361     public String getModemUuId() {
   2362         final RadioCapability rc = getRadioCapability();
   2363         return (rc == null ? "" : rc.getLogicalModemUuid());
   2364     }
   2365 
   2366     @Override
   2367     public RadioCapability getRadioCapability() {
   2368         return mRadioCapability.get();
   2369     }
   2370 
   2371     @Override
   2372     public void radioCapabilityUpdated(RadioCapability rc) {
   2373         // Called when radios first become available or after a capability switch
   2374         // Update the cached value
   2375         mRadioCapability.set(rc);
   2376 
   2377         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
   2378             sendSubscriptionSettings(true);
   2379         }
   2380     }
   2381 
   2382     public void sendSubscriptionSettings(boolean restoreNetworkSelection) {
   2383         // Send settings down
   2384         int type = PhoneFactory.calculatePreferredNetworkType(mContext, getSubId());
   2385         setPreferredNetworkType(type, null);
   2386 
   2387         if (restoreNetworkSelection) {
   2388             restoreSavedNetworkSelection(null);
   2389         }
   2390         mDcTracker.setDataEnabled(getDataEnabled());
   2391     }
   2392 
   2393     protected void setPreferredNetworkTypeIfSimLoaded() {
   2394         int subId = getSubId();
   2395         if (SubscriptionManager.isValidSubscriptionId(subId)) {
   2396             int type = PhoneFactory.calculatePreferredNetworkType(mContext, getSubId());
   2397             setPreferredNetworkType(type, null);
   2398         }
   2399     }
   2400 
   2401     @Override
   2402     public void registerForRadioCapabilityChanged(Handler h, int what, Object obj) {
   2403         mCi.registerForRadioCapabilityChanged(h, what, obj);
   2404     }
   2405 
   2406     @Override
   2407     public void unregisterForRadioCapabilityChanged(Handler h) {
   2408         mCi.unregisterForRadioCapabilityChanged(this);
   2409     }
   2410 
   2411     /**
   2412      * Determines if  IMS is enabled for call.
   2413      *
   2414      * @return {@code true} if IMS calling is enabled.
   2415      */
   2416     public boolean isImsUseEnabled() {
   2417         boolean imsUseEnabled =
   2418                 ((ImsManager.isVolteEnabledByPlatform(mContext) &&
   2419                 ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mContext)) ||
   2420                 (ImsManager.isWfcEnabledByPlatform(mContext) &&
   2421                 ImsManager.isWfcEnabledByUser(mContext)) &&
   2422                 ImsManager.isNonTtyOrTtyOnVolteEnabled(mContext));
   2423         return imsUseEnabled;
   2424     }
   2425 
   2426     /**
   2427      * Determines if video calling is enabled for the IMS phone.
   2428      *
   2429      * @return {@code true} if video calling is enabled.
   2430      */
   2431     @Override
   2432     public boolean isVideoEnabled() {
   2433         ImsPhone imsPhone = mImsPhone;
   2434         if ((imsPhone != null)
   2435                 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
   2436             return imsPhone.isVideoEnabled();
   2437         }
   2438         return false;
   2439     }
   2440 
   2441     @Override
   2442     public int getLceStatus() {
   2443         return mLceStatus;
   2444     }
   2445 
   2446     @Override
   2447     public void getModemActivityInfo(Message response)  {
   2448         mCi.getModemActivityInfo(response);
   2449     }
   2450 
   2451     /**
   2452      * Starts LCE service after radio becomes available.
   2453      * LCE service state may get destroyed on the modem when radio becomes unavailable.
   2454      */
   2455     public void startLceAfterRadioIsAvailable() {
   2456         if (mIsTheCurrentActivePhone) {
   2457             mCi.startLceService(DEFAULT_REPORT_INTERVAL_MS, LCE_PULL_MODE,
   2458                 obtainMessage(EVENT_CONFIG_LCE));
   2459         }
   2460     }
   2461 
   2462     @Override
   2463     public Locale getLocaleFromSimAndCarrierPrefs() {
   2464         final IccRecords records = mIccRecords.get();
   2465         if (records != null && records.getSimLanguage() != null) {
   2466             return new Locale(records.getSimLanguage());
   2467         }
   2468 
   2469         return getLocaleFromCarrierProperties(mContext);
   2470     }
   2471 
   2472     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2473         pw.println("PhoneBase: subId=" + getSubId());
   2474         pw.println(" mPhoneId=" + mPhoneId);
   2475         pw.println(" mCi=" + mCi);
   2476         pw.println(" mDnsCheckDisabled=" + mDnsCheckDisabled);
   2477         pw.println(" mDcTracker=" + mDcTracker);
   2478         pw.println(" mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
   2479         pw.println(" mCallRingContinueToken=" + mCallRingContinueToken);
   2480         pw.println(" mCallRingDelay=" + mCallRingDelay);
   2481         pw.println(" mIsTheCurrentActivePhone=" + mIsTheCurrentActivePhone);
   2482         pw.println(" mIsVoiceCapable=" + mIsVoiceCapable);
   2483         pw.println(" mIccRecords=" + mIccRecords.get());
   2484         pw.println(" mUiccApplication=" + mUiccApplication.get());
   2485         pw.println(" mSmsStorageMonitor=" + mSmsStorageMonitor);
   2486         pw.println(" mSmsUsageMonitor=" + mSmsUsageMonitor);
   2487         pw.flush();
   2488         pw.println(" mLooper=" + mLooper);
   2489         pw.println(" mContext=" + mContext);
   2490         pw.println(" mNotifier=" + mNotifier);
   2491         pw.println(" mSimulatedRadioControl=" + mSimulatedRadioControl);
   2492         pw.println(" mUnitTestMode=" + mUnitTestMode);
   2493         pw.println(" isDnsCheckDisabled()=" + isDnsCheckDisabled());
   2494         pw.println(" getUnitTestMode()=" + getUnitTestMode());
   2495         pw.println(" getState()=" + getState());
   2496         pw.println(" getIccSerialNumber()=" + getIccSerialNumber());
   2497         pw.println(" getIccRecordsLoaded()=" + getIccRecordsLoaded());
   2498         pw.println(" getMessageWaitingIndicator()=" + getMessageWaitingIndicator());
   2499         pw.println(" getCallForwardingIndicator()=" + getCallForwardingIndicator());
   2500         pw.println(" isInEmergencyCall()=" + isInEmergencyCall());
   2501         pw.flush();
   2502         pw.println(" isInEcm()=" + isInEcm());
   2503         pw.println(" getPhoneName()=" + getPhoneName());
   2504         pw.println(" getPhoneType()=" + getPhoneType());
   2505         pw.println(" getVoiceMessageCount()=" + getVoiceMessageCount());
   2506         pw.println(" getActiveApnTypes()=" + getActiveApnTypes());
   2507         pw.println(" isDataConnectivityPossible()=" + isDataConnectivityPossible());
   2508         pw.println(" needsOtaServiceProvisioning=" + needsOtaServiceProvisioning());
   2509         pw.flush();
   2510         pw.println("++++++++++++++++++++++++++++++++");
   2511 
   2512         try {
   2513             mDcTracker.dump(fd, pw, args);
   2514         } catch (Exception e) {
   2515             e.printStackTrace();
   2516         }
   2517         pw.flush();
   2518         pw.println("++++++++++++++++++++++++++++++++");
   2519 
   2520         try {
   2521             getServiceStateTracker().dump(fd, pw, args);
   2522         } catch (Exception e) {
   2523             e.printStackTrace();
   2524         }
   2525         pw.flush();
   2526         pw.println("++++++++++++++++++++++++++++++++");
   2527 
   2528         try {
   2529             getCallTracker().dump(fd, pw, args);
   2530         } catch (Exception e) {
   2531             e.printStackTrace();
   2532         }
   2533         pw.flush();
   2534         pw.println("++++++++++++++++++++++++++++++++");
   2535 
   2536         try {
   2537             ((RIL)mCi).dump(fd, pw, args);
   2538         } catch (Exception e) {
   2539             e.printStackTrace();
   2540         }
   2541         pw.flush();
   2542         pw.println("++++++++++++++++++++++++++++++++");
   2543     }
   2544 }
   2545