Home | History | Annotate | Download | only in ims
      1 /*
      2  * Copyright (c) 2013 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.ims;
     18 
     19 import android.app.PendingIntent;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.net.Uri;
     23 import android.os.AsyncTask;
     24 import android.os.IBinder;
     25 import android.os.Message;
     26 import android.os.PersistableBundle;
     27 import android.os.RemoteException;
     28 import android.os.ServiceManager;
     29 import android.os.SystemProperties;
     30 import android.provider.Settings;
     31 import android.telecom.TelecomManager;
     32 import android.telephony.CarrierConfigManager;
     33 import android.telephony.Rlog;
     34 import android.telephony.SubscriptionManager;
     35 import android.telephony.TelephonyManager;
     36 
     37 import com.android.ims.internal.IImsCallSession;
     38 import com.android.ims.internal.IImsEcbm;
     39 import com.android.ims.internal.IImsMultiEndpoint;
     40 import com.android.ims.internal.IImsRegistrationListener;
     41 import com.android.ims.internal.IImsService;
     42 import com.android.ims.internal.IImsUt;
     43 import com.android.ims.internal.ImsCallSession;
     44 import com.android.ims.internal.IImsConfig;
     45 
     46 import java.io.FileDescriptor;
     47 import java.io.PrintWriter;
     48 import java.util.HashMap;
     49 
     50 /**
     51  * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
     52  * the operator's IMS network. This class is the starting point for any IMS actions.
     53  * You can acquire an instance of it with {@link #getInstance getInstance()}.</p>
     54  * <p>The APIs in this class allows you to:</p>
     55  *
     56  * @hide
     57  */
     58 public class ImsManager {
     59 
     60     /*
     61      * Debug flag to override configuration flag
     62      */
     63     public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr";
     64     public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0;
     65     public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr";
     66     public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0;
     67     public static final String PROPERTY_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr";
     68     public static final int PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT = 0;
     69     public static final String PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE = "persist.dbg.allow_ims_off";
     70     public static final int PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT = 0;
     71 
     72     /**
     73      * For accessing the IMS related service.
     74      * Internal use only.
     75      * @hide
     76      */
     77     private static final String IMS_SERVICE = "ims";
     78 
     79     /**
     80      * The result code to be sent back with the incoming call {@link PendingIntent}.
     81      * @see #open(PendingIntent, ImsConnectionStateListener)
     82      */
     83     public static final int INCOMING_CALL_RESULT_CODE = 101;
     84 
     85     /**
     86      * Key to retrieve the call ID from an incoming call intent.
     87      * @see #open(PendingIntent, ImsConnectionStateListener)
     88      */
     89     public static final String EXTRA_CALL_ID = "android:imsCallID";
     90 
     91     /**
     92      * Action to broadcast when ImsService is up.
     93      * Internal use only.
     94      * @hide
     95      */
     96     public static final String ACTION_IMS_SERVICE_UP =
     97             "com.android.ims.IMS_SERVICE_UP";
     98 
     99     /**
    100      * Action to broadcast when ImsService is down.
    101      * Internal use only.
    102      * @hide
    103      */
    104     public static final String ACTION_IMS_SERVICE_DOWN =
    105             "com.android.ims.IMS_SERVICE_DOWN";
    106 
    107     /**
    108      * Action to broadcast when ImsService registration fails.
    109      * Internal use only.
    110      * @hide
    111      */
    112     public static final String ACTION_IMS_REGISTRATION_ERROR =
    113             "com.android.ims.REGISTRATION_ERROR";
    114 
    115     /**
    116      * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
    117      * A long value; the phone ID corresponding to the IMS service coming up or down.
    118      * Internal use only.
    119      * @hide
    120      */
    121     public static final String EXTRA_PHONE_ID = "android:phone_id";
    122 
    123     /**
    124      * Action for the incoming call intent for the Phone app.
    125      * Internal use only.
    126      * @hide
    127      */
    128     public static final String ACTION_IMS_INCOMING_CALL =
    129             "com.android.ims.IMS_INCOMING_CALL";
    130 
    131     /**
    132      * Part of the ACTION_IMS_INCOMING_CALL intents.
    133      * An integer value; service identifier obtained from {@link ImsManager#open}.
    134      * Internal use only.
    135      * @hide
    136      */
    137     public static final String EXTRA_SERVICE_ID = "android:imsServiceId";
    138 
    139     /**
    140      * Part of the ACTION_IMS_INCOMING_CALL intents.
    141      * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD.
    142      * The value "true" indicates that the incoming call is for USSD.
    143      * Internal use only.
    144      * @hide
    145      */
    146     public static final String EXTRA_USSD = "android:ussd";
    147 
    148     /**
    149      * Part of the ACTION_IMS_INCOMING_CALL intents.
    150      * A boolean value; Flag to indicate whether the call is an unknown
    151      * dialing call. Such calls are originated by sending commands (like
    152      * AT commands) directly to modem without Android involvement.
    153      * Even though they are not incoming calls, they are propagated
    154      * to Phone app using same ACTION_IMS_INCOMING_CALL intent.
    155      * Internal use only.
    156      * @hide
    157      */
    158     public static final String EXTRA_IS_UNKNOWN_CALL = "android:isUnknown";
    159 
    160     private static final String TAG = "ImsManager";
    161     private static final boolean DBG = true;
    162 
    163     private static HashMap<Integer, ImsManager> sImsManagerInstances =
    164             new HashMap<Integer, ImsManager>();
    165 
    166     private Context mContext;
    167     private int mPhoneId;
    168     private IImsService mImsService = null;
    169     private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient();
    170     // Ut interface for the supplementary service configuration
    171     private ImsUt mUt = null;
    172     // Interface to get/set ims config items
    173     private ImsConfig mConfig = null;
    174     private boolean mConfigUpdated = false;
    175 
    176     private ImsConfigListener mImsConfigListener;
    177 
    178     // ECBM interface
    179     private ImsEcbm mEcbm = null;
    180 
    181     private ImsMultiEndpoint mMultiEndpoint = null;
    182 
    183     // SystemProperties used as cache
    184     private static final String VOLTE_PROVISIONED_PROP = "net.lte.ims.volte.provisioned";
    185     private static final String WFC_PROVISIONED_PROP = "net.lte.ims.wfc.provisioned";
    186     private static final String VT_PROVISIONED_PROP = "net.lte.ims.vt.provisioned";
    187     // Flag indicating data enabled or not. This flag should be in sync with
    188     // DcTracker.isDataEnabled(). The flag will be set later during boot up.
    189     private static final String DATA_ENABLED_PROP = "net.lte.ims.data.enabled";
    190 
    191     public static final String TRUE = "true";
    192     public static final String FALSE = "false";
    193 
    194     /**
    195      * Gets a manager instance.
    196      *
    197      * @param context application context for creating the manager object
    198      * @param phoneId the phone ID for the IMS Service
    199      * @return the manager instance corresponding to the phoneId
    200      */
    201     public static ImsManager getInstance(Context context, int phoneId) {
    202         synchronized (sImsManagerInstances) {
    203             if (sImsManagerInstances.containsKey(phoneId))
    204                 return sImsManagerInstances.get(phoneId);
    205 
    206             ImsManager mgr = new ImsManager(context, phoneId);
    207             sImsManagerInstances.put(phoneId, mgr);
    208 
    209             return mgr;
    210         }
    211     }
    212 
    213     /**
    214      * Returns the user configuration of Enhanced 4G LTE Mode setting
    215      */
    216     public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) {
    217         // If user can't edit Enhanced 4G LTE Mode, it assumes Enhanced 4G LTE Mode is always true.
    218         // If user changes SIM from editable mode to uneditable mode, need to return true.
    219         if (!getBooleanCarrierConfig(context,
    220                     CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL)) {
    221             return true;
    222         }
    223         int enabled = android.provider.Settings.Global.getInt(
    224                     context.getContentResolver(),
    225                     android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
    226         return (enabled == 1) ? true : false;
    227     }
    228 
    229     /**
    230      * Change persistent Enhanced 4G LTE Mode setting
    231      */
    232     public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {
    233         int value = enabled ? 1 : 0;
    234         android.provider.Settings.Global.putInt(
    235                 context.getContentResolver(),
    236                 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, value);
    237 
    238         if (isNonTtyOrTtyOnVolteEnabled(context)) {
    239             ImsManager imsManager = ImsManager.getInstance(context,
    240                     SubscriptionManager.getDefaultVoicePhoneId());
    241             if (imsManager != null) {
    242                 try {
    243                     imsManager.setAdvanced4GMode(enabled);
    244                 } catch (ImsException ie) {
    245                     // do nothing
    246                 }
    247             }
    248         }
    249     }
    250 
    251     /**
    252      * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is
    253      * supported.
    254      */
    255     public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) {
    256         if (getBooleanCarrierConfig(context,
    257                 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
    258             return true;
    259         }
    260 
    261         return Settings.Secure.getInt(context.getContentResolver(),
    262                 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF)
    263                 == TelecomManager.TTY_MODE_OFF;
    264     }
    265 
    266     /**
    267      * Returns a platform configuration for VoLTE which may override the user setting.
    268      */
    269     public static boolean isVolteEnabledByPlatform(Context context) {
    270         if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE,
    271                 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) {
    272             return true;
    273         }
    274 
    275         return context.getResources().getBoolean(
    276                 com.android.internal.R.bool.config_device_volte_available)
    277                 && getBooleanCarrierConfig(context,
    278                         CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL)
    279                 && isGbaValid(context);
    280     }
    281 
    282     /**
    283      * Indicates whether VoLTE is provisioned on device
    284      */
    285     public static boolean isVolteProvisionedOnDevice(Context context) {
    286         if (getBooleanCarrierConfig(context,
    287                     CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
    288             ImsManager mgr = ImsManager.getInstance(context,
    289                     SubscriptionManager.getDefaultVoicePhoneId());
    290             if (mgr != null) {
    291                 return mgr.isVolteProvisioned();
    292             }
    293         }
    294 
    295         return true;
    296     }
    297 
    298     /**
    299      * Indicates whether VoWifi is provisioned on device
    300      */
    301     public static boolean isWfcProvisionedOnDevice(Context context) {
    302         if (getBooleanCarrierConfig(context,
    303                 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
    304             ImsManager mgr = ImsManager.getInstance(context,
    305                     SubscriptionManager.getDefaultVoicePhoneId());
    306             if (mgr != null) {
    307                 return mgr.isWfcProvisioned();
    308             }
    309         }
    310 
    311         return true;
    312     }
    313 
    314     /**
    315      * Indicates whether VT is provisioned on device
    316      */
    317     public static boolean isVtProvisionedOnDevice(Context context) {
    318         if (getBooleanCarrierConfig(context,
    319                 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
    320             ImsManager mgr = ImsManager.getInstance(context,
    321                     SubscriptionManager.getDefaultVoicePhoneId());
    322             if (mgr != null) {
    323                 return mgr.isVtProvisioned();
    324             }
    325         }
    326 
    327         return true;
    328     }
    329 
    330     /**
    331      * Returns a platform configuration for VT which may override the user setting.
    332      *
    333      * Note: VT presumes that VoLTE is enabled (these are configuration settings
    334      * which must be done correctly).
    335      */
    336     public static boolean isVtEnabledByPlatform(Context context) {
    337         if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE,
    338                 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) {
    339             return true;
    340         }
    341 
    342         return
    343                 context.getResources().getBoolean(
    344                         com.android.internal.R.bool.config_device_vt_available) &&
    345                 getBooleanCarrierConfig(context,
    346                         CarrierConfigManager.KEY_CARRIER_VT_AVAILABLE_BOOL) &&
    347                 isGbaValid(context);
    348     }
    349 
    350     /**
    351      * Returns the user configuration of VT setting
    352      */
    353     public static boolean isVtEnabledByUser(Context context) {
    354         int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
    355                 android.provider.Settings.Global.VT_IMS_ENABLED,
    356                 ImsConfig.FeatureValueConstants.ON);
    357         return (enabled == 1) ? true : false;
    358     }
    359 
    360     /**
    361      * Change persistent VT enabled setting
    362      */
    363     public static void setVtSetting(Context context, boolean enabled) {
    364         int value = enabled ? 1 : 0;
    365         android.provider.Settings.Global.putInt(context.getContentResolver(),
    366                 android.provider.Settings.Global.VT_IMS_ENABLED, value);
    367 
    368         ImsManager imsManager = ImsManager.getInstance(context,
    369                 SubscriptionManager.getDefaultVoicePhoneId());
    370         if (imsManager != null) {
    371             try {
    372                 ImsConfig config = imsManager.getConfigInterface();
    373                 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
    374                         TelephonyManager.NETWORK_TYPE_LTE,
    375                         enabled ? ImsConfig.FeatureValueConstants.ON
    376                                 : ImsConfig.FeatureValueConstants.OFF,
    377                         imsManager.mImsConfigListener);
    378 
    379                 if (enabled) {
    380                     log("setVtSetting() : turnOnIms");
    381                     imsManager.turnOnIms();
    382                 } else if (isTurnOffImsAllowedByPlatform(context)
    383                         && (!isVolteEnabledByPlatform(context)
    384                         || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
    385                     log("setVtSetting() : imsServiceAllowTurnOff -> turnOffIms");
    386                     imsManager.turnOffIms();
    387                 }
    388             } catch (ImsException e) {
    389                 loge("setVtSetting(): ", e);
    390             }
    391         }
    392     }
    393 
    394     /*
    395      * Returns whether turning off ims is allowed by platform.
    396      * The platform property may override the carrier config.
    397      */
    398     private static boolean isTurnOffImsAllowedByPlatform(Context context) {
    399         if (SystemProperties.getInt(PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE,
    400                 PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT) == 1) {
    401             return true;
    402         }
    403         return getBooleanCarrierConfig(context,
    404                 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL);
    405     }
    406 
    407     /**
    408      * Returns the user configuration of WFC setting
    409      */
    410     public static boolean isWfcEnabledByUser(Context context) {
    411         int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
    412                 android.provider.Settings.Global.WFC_IMS_ENABLED,
    413                 getBooleanCarrierConfig(context,
    414                         CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL) ?
    415                         ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
    416         return (enabled == 1) ? true : false;
    417     }
    418 
    419     /**
    420      * Change persistent WFC enabled setting
    421      */
    422     public static void setWfcSetting(Context context, boolean enabled) {
    423         int value = enabled ? 1 : 0;
    424         android.provider.Settings.Global.putInt(context.getContentResolver(),
    425                 android.provider.Settings.Global.WFC_IMS_ENABLED, value);
    426 
    427         ImsManager imsManager = ImsManager.getInstance(context,
    428                 SubscriptionManager.getDefaultVoicePhoneId());
    429         if (imsManager != null) {
    430             try {
    431                 ImsConfig config = imsManager.getConfigInterface();
    432                 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
    433                         TelephonyManager.NETWORK_TYPE_IWLAN,
    434                         enabled ? ImsConfig.FeatureValueConstants.ON
    435                                 : ImsConfig.FeatureValueConstants.OFF,
    436                         imsManager.mImsConfigListener);
    437 
    438                 if (enabled) {
    439                     log("setWfcSetting() : turnOnIms");
    440                     imsManager.turnOnIms();
    441                 } else if (isTurnOffImsAllowedByPlatform(context)
    442                         && (!isVolteEnabledByPlatform(context)
    443                         || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
    444                     log("setWfcSetting() : imsServiceAllowTurnOff -> turnOffIms");
    445                     imsManager.turnOffIms();
    446                 }
    447 
    448                 // Force IMS to register over LTE when turning off WFC
    449                 setWfcModeInternal(context, enabled
    450                         ? getWfcMode(context)
    451                         : ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED);
    452             } catch (ImsException e) {
    453                 loge("setWfcSetting(): ", e);
    454             }
    455         }
    456     }
    457 
    458     /**
    459      * Returns the user configuration of WFC preference setting
    460      */
    461     public static int getWfcMode(Context context) {
    462         int setting = android.provider.Settings.Global.getInt(context.getContentResolver(),
    463                 android.provider.Settings.Global.WFC_IMS_MODE, getIntCarrierConfig(context,
    464                         CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
    465         if (DBG) log("getWfcMode - setting=" + setting);
    466         return setting;
    467     }
    468 
    469     /**
    470      * Change persistent WFC preference setting
    471      */
    472     public static void setWfcMode(Context context, int wfcMode) {
    473         if (DBG) log("setWfcMode - setting=" + wfcMode);
    474         android.provider.Settings.Global.putInt(context.getContentResolver(),
    475                 android.provider.Settings.Global.WFC_IMS_MODE, wfcMode);
    476 
    477         setWfcModeInternal(context, wfcMode);
    478     }
    479 
    480     /**
    481      * Returns the user configuration of WFC preference setting
    482      *
    483      * @param roaming {@code false} for home network setting, {@code true} for roaming  setting
    484      */
    485     public static int getWfcMode(Context context, boolean roaming) {
    486         int setting = 0;
    487         if (!roaming) {
    488             setting = android.provider.Settings.Global.getInt(context.getContentResolver(),
    489                     android.provider.Settings.Global.WFC_IMS_MODE, getIntCarrierConfig(context,
    490                             CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
    491             if (DBG) log("getWfcMode - setting=" + setting);
    492         } else {
    493             setting = android.provider.Settings.Global.getInt(context.getContentResolver(),
    494                     android.provider.Settings.Global.WFC_IMS_ROAMING_MODE,
    495                     getIntCarrierConfig(context,
    496                             CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT));
    497             if (DBG) log("getWfcMode (roaming) - setting=" + setting);
    498         }
    499         return setting;
    500     }
    501 
    502     /**
    503      * Change persistent WFC preference setting
    504      *
    505      * @param roaming {@code false} for home network setting, {@code true} for roaming setting
    506      */
    507     public static void setWfcMode(Context context, int wfcMode, boolean roaming) {
    508         if (!roaming) {
    509             if (DBG) log("setWfcMode - setting=" + wfcMode);
    510             android.provider.Settings.Global.putInt(context.getContentResolver(),
    511                     android.provider.Settings.Global.WFC_IMS_MODE, wfcMode);
    512         } else {
    513             if (DBG) log("setWfcMode (roaming) - setting=" + wfcMode);
    514             android.provider.Settings.Global.putInt(context.getContentResolver(),
    515                     android.provider.Settings.Global.WFC_IMS_ROAMING_MODE, wfcMode);
    516         }
    517 
    518         TelephonyManager tm = (TelephonyManager)
    519                 context.getSystemService(Context.TELEPHONY_SERVICE);
    520         if (roaming == tm.isNetworkRoaming()) {
    521             setWfcModeInternal(context, wfcMode);
    522         }
    523     }
    524 
    525     private static void setWfcModeInternal(Context context, int wfcMode) {
    526         final ImsManager imsManager = ImsManager.getInstance(context,
    527                 SubscriptionManager.getDefaultVoicePhoneId());
    528         if (imsManager != null) {
    529             final int value = wfcMode;
    530             Thread thread = new Thread(new Runnable() {
    531                 public void run() {
    532                     try {
    533                         imsManager.getConfigInterface().setProvisionedValue(
    534                                 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE,
    535                                 value);
    536                     } catch (ImsException e) {
    537                         // do nothing
    538                     }
    539                 }
    540             });
    541             thread.start();
    542         }
    543     }
    544 
    545     /**
    546      * Returns the user configuration of WFC roaming setting
    547      */
    548     public static boolean isWfcRoamingEnabledByUser(Context context) {
    549         int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
    550                 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
    551                 getBooleanCarrierConfig(context,
    552                         CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ?
    553                         ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
    554         return (enabled == 1) ? true : false;
    555     }
    556 
    557     /**
    558      * Change persistent WFC roaming enabled setting
    559      */
    560     public static void setWfcRoamingSetting(Context context, boolean enabled) {
    561         android.provider.Settings.Global.putInt(context.getContentResolver(),
    562                 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
    563                 enabled ? ImsConfig.FeatureValueConstants.ON
    564                         : ImsConfig.FeatureValueConstants.OFF);
    565 
    566         setWfcRoamingSettingInternal(context, enabled);
    567     }
    568 
    569     private static void setWfcRoamingSettingInternal(Context context, boolean enabled) {
    570         final ImsManager imsManager = ImsManager.getInstance(context,
    571                 SubscriptionManager.getDefaultVoicePhoneId());
    572         if (imsManager != null) {
    573             final int value = enabled
    574                     ? ImsConfig.FeatureValueConstants.ON
    575                     : ImsConfig.FeatureValueConstants.OFF;
    576             Thread thread = new Thread(new Runnable() {
    577                 public void run() {
    578                     try {
    579                         imsManager.getConfigInterface().setProvisionedValue(
    580                                 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_ROAMING,
    581                                 value);
    582                     } catch (ImsException e) {
    583                         // do nothing
    584                     }
    585                 }
    586             });
    587             thread.start();
    588         }
    589     }
    590 
    591     /**
    592      * Returns a platform configuration for WFC which may override the user
    593      * setting. Note: WFC presumes that VoLTE is enabled (these are
    594      * configuration settings which must be done correctly).
    595      */
    596     public static boolean isWfcEnabledByPlatform(Context context) {
    597         if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE,
    598                 PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT) == 1) {
    599             return true;
    600         }
    601 
    602         return
    603                context.getResources().getBoolean(
    604                        com.android.internal.R.bool.config_device_wfc_ims_available) &&
    605                getBooleanCarrierConfig(context,
    606                        CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) &&
    607                isGbaValid(context);
    608     }
    609 
    610     /**
    611      * If carrier requires that IMS is only available if GBA capable SIM is used,
    612      * then this function checks GBA bit in EF IST.
    613      *
    614      * Format of EF IST is defined in 3GPP TS 31.103 (Section 4.2.7).
    615      */
    616     private static boolean isGbaValid(Context context) {
    617         if (getBooleanCarrierConfig(context,
    618                 CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) {
    619             final TelephonyManager telephonyManager = TelephonyManager.getDefault();
    620             String efIst = telephonyManager.getIsimIst();
    621             if (efIst == null) {
    622                 loge("ISF is NULL");
    623                 return true;
    624             }
    625             boolean result = efIst != null && efIst.length() > 1 &&
    626                     (0x02 & (byte)efIst.charAt(1)) != 0;
    627             if (DBG) log("GBA capable=" + result + ", ISF=" + efIst);
    628             return result;
    629         }
    630         return true;
    631     }
    632 
    633     /**
    634      * This function should be called when ImsConfig.ACTION_IMS_CONFIG_CHANGED is received.
    635      *
    636      * We cannot register receiver in ImsManager because this would lead to resource leak.
    637      * ImsManager can be created in different processes and it is not notified when that process
    638      * is about to be terminated.
    639      *
    640      * @hide
    641      * */
    642     public static void onProvisionedValueChanged(Context context, int item, String value) {
    643         if (DBG) Rlog.d(TAG, "onProvisionedValueChanged: item=" + item + " val=" + value);
    644         ImsManager mgr = ImsManager.getInstance(context,
    645                 SubscriptionManager.getDefaultVoicePhoneId());
    646 
    647         switch (item) {
    648             case ImsConfig.ConfigConstants.VLT_SETTING_ENABLED:
    649                 mgr.setVolteProvisionedProperty(value.equals("1"));
    650                 if (DBG) Rlog.d(TAG,"isVoLteProvisioned = " + mgr.isVolteProvisioned());
    651                 break;
    652 
    653             case ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED:
    654                 mgr.setWfcProvisionedProperty(value.equals("1"));
    655                 if (DBG) Rlog.d(TAG,"isWfcProvisioned = " + mgr.isWfcProvisioned());
    656                 break;
    657 
    658             case ImsConfig.ConfigConstants.LVC_SETTING_ENABLED:
    659                 mgr.setVtProvisionedProperty(value.equals("1"));
    660                 if (DBG) Rlog.d(TAG,"isVtProvisioned = " + mgr.isVtProvisioned());
    661                 break;
    662 
    663         }
    664     }
    665 
    666     private class AsyncUpdateProvisionedValues extends AsyncTask<Void, Void, Void> {
    667         @Override
    668         protected Void doInBackground(Void... params) {
    669             // disable on any error
    670             setVolteProvisionedProperty(false);
    671             setWfcProvisionedProperty(false);
    672             setVtProvisionedProperty(false);
    673 
    674             try {
    675                 ImsConfig config = getConfigInterface();
    676                 if (config != null) {
    677                     setVolteProvisionedProperty(getProvisionedBool(config,
    678                             ImsConfig.ConfigConstants.VLT_SETTING_ENABLED));
    679                     if (DBG) Rlog.d(TAG, "isVoLteProvisioned = " + isVolteProvisioned());
    680 
    681                     setWfcProvisionedProperty(getProvisionedBool(config,
    682                             ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED));
    683                     if (DBG) Rlog.d(TAG, "isWfcProvisioned = " + isWfcProvisioned());
    684 
    685                     setVtProvisionedProperty(getProvisionedBool(config,
    686                             ImsConfig.ConfigConstants.LVC_SETTING_ENABLED));
    687                     if (DBG) Rlog.d(TAG, "isVtProvisioned = " + isVtProvisioned());
    688 
    689                 }
    690             } catch (ImsException ie) {
    691                 Rlog.e(TAG, "AsyncUpdateProvisionedValues error: ", ie);
    692             }
    693 
    694             return null;
    695         }
    696 
    697         private boolean getProvisionedBool(ImsConfig config, int item) throws ImsException {
    698             return config.getProvisionedValue(item) == ImsConfig.FeatureValueConstants.ON;
    699         }
    700     }
    701 
    702     /** Asynchronously get VoLTE, WFC, VT provisioning statuses */
    703     private void updateProvisionedValues() {
    704         if (getBooleanCarrierConfig(mContext,
    705                 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
    706 
    707             new AsyncUpdateProvisionedValues().execute();
    708         }
    709     }
    710 
    711     /**
    712      * Sync carrier config and user settings with ImsConfig.
    713      *
    714      * @param context for the manager object
    715      * @param phoneId phone id
    716      * @param force update
    717      */
    718     public static void updateImsServiceConfig(Context context, int phoneId, boolean force) {
    719         if (!force) {
    720             if (TelephonyManager.getDefault().getSimState() != TelephonyManager.SIM_STATE_READY) {
    721                 log("updateImsServiceConfig: SIM not ready");
    722                 // Don't disable IMS if SIM is not ready
    723                 return;
    724             }
    725         }
    726 
    727         final ImsManager imsManager = ImsManager.getInstance(context, phoneId);
    728         if (imsManager != null && (!imsManager.mConfigUpdated || force)) {
    729             try {
    730                 imsManager.updateProvisionedValues();
    731 
    732                 // TODO: Extend ImsConfig API and set all feature values in single function call.
    733 
    734                 // Note: currently the order of updates is set to produce different order of
    735                 // setFeatureValue() function calls from setAdvanced4GMode(). This is done to
    736                 // differentiate this code path from vendor code perspective.
    737                 boolean isImsUsed = imsManager.updateVolteFeatureValue();
    738                 isImsUsed |= imsManager.updateWfcFeatureAndProvisionedValues();
    739                 isImsUsed |= imsManager.updateVideoCallFeatureValue();
    740 
    741                 if (isImsUsed || !isTurnOffImsAllowedByPlatform(context)) {
    742                     // Turn on IMS if it is used.
    743                     // Also, if turning off is not allowed for current carrier,
    744                     // we need to turn IMS on because it might be turned off before
    745                     // phone switched to current carrier.
    746                     log("updateImsServiceConfig: turnOnIms");
    747                     imsManager.turnOnIms();
    748                 } else {
    749                     // Turn off IMS if it is not used AND turning off is allowed for carrier.
    750                     log("updateImsServiceConfig: turnOffIms");
    751                     imsManager.turnOffIms();
    752                 }
    753 
    754                 imsManager.mConfigUpdated = true;
    755             } catch (ImsException e) {
    756                 loge("updateImsServiceConfig: ", e);
    757                 imsManager.mConfigUpdated = false;
    758             }
    759         }
    760     }
    761 
    762     /**
    763      * Update VoLTE config
    764      * @return whether feature is On
    765      * @throws ImsException
    766      */
    767     private boolean updateVolteFeatureValue() throws ImsException {
    768         boolean available = isVolteEnabledByPlatform(mContext);
    769         boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext);
    770         boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
    771         boolean isFeatureOn = available && enabled && isNonTty;
    772 
    773         log("updateVolteFeatureValue: available = " + available
    774                 + ", enabled = " + enabled
    775                 + ", nonTTY = " + isNonTty);
    776 
    777         getConfigInterface().setFeatureValue(
    778                 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
    779                 TelephonyManager.NETWORK_TYPE_LTE,
    780                 isFeatureOn ?
    781                         ImsConfig.FeatureValueConstants.ON :
    782                         ImsConfig.FeatureValueConstants.OFF,
    783                 mImsConfigListener);
    784 
    785         return isFeatureOn;
    786     }
    787 
    788     /**
    789      * Update video call over LTE config
    790      * @return whether feature is On
    791      * @throws ImsException
    792      */
    793     private boolean updateVideoCallFeatureValue() throws ImsException {
    794         boolean available = isVtEnabledByPlatform(mContext);
    795         boolean enabled = isVtEnabledByUser(mContext);
    796         boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
    797         boolean isDataEnabled = isDataEnabled();
    798 
    799         boolean isFeatureOn = available && enabled && isNonTty && isDataEnabled;
    800 
    801         log("updateVideoCallFeatureValue: available = " + available
    802                 + ", enabled = " + enabled
    803                 + ", nonTTY = " + isNonTty
    804                 + ", data enabled = " + isDataEnabled);
    805 
    806         getConfigInterface().setFeatureValue(
    807                 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
    808                 TelephonyManager.NETWORK_TYPE_LTE,
    809                 isFeatureOn ?
    810                         ImsConfig.FeatureValueConstants.ON :
    811                         ImsConfig.FeatureValueConstants.OFF,
    812                 mImsConfigListener);
    813 
    814         return isFeatureOn;
    815     }
    816 
    817     /**
    818      * Update WFC config
    819      * @return whether feature is On
    820      * @throws ImsException
    821      */
    822     private boolean updateWfcFeatureAndProvisionedValues() throws ImsException {
    823         boolean isNetworkRoaming = TelephonyManager.getDefault().isNetworkRoaming();
    824         boolean available = isWfcEnabledByPlatform(mContext);
    825         boolean enabled = isWfcEnabledByUser(mContext);
    826         int mode = getWfcMode(mContext, isNetworkRoaming);
    827         boolean roaming = isWfcRoamingEnabledByUser(mContext);
    828         boolean isFeatureOn = available && enabled;
    829 
    830         log("updateWfcFeatureAndProvisionedValues: available = " + available
    831                 + ", enabled = " + enabled
    832                 + ", mode = " + mode
    833                 + ", roaming = " + roaming);
    834 
    835         getConfigInterface().setFeatureValue(
    836                 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
    837                 TelephonyManager.NETWORK_TYPE_IWLAN,
    838                 isFeatureOn ?
    839                         ImsConfig.FeatureValueConstants.ON :
    840                         ImsConfig.FeatureValueConstants.OFF,
    841                 mImsConfigListener);
    842 
    843         if (!isFeatureOn) {
    844             mode = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED;
    845             roaming = false;
    846         }
    847         setWfcModeInternal(mContext, mode);
    848         setWfcRoamingSettingInternal(mContext, roaming);
    849 
    850         return isFeatureOn;
    851     }
    852 
    853     private ImsManager(Context context, int phoneId) {
    854         mContext = context;
    855         mPhoneId = phoneId;
    856         createImsService(true);
    857     }
    858 
    859     /*
    860      * Returns a flag indicating whether the IMS service is available.
    861      */
    862     public boolean isServiceAvailable() {
    863         if (mImsService != null) {
    864             return true;
    865         }
    866 
    867         IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
    868         if (binder != null) {
    869             return true;
    870         }
    871 
    872         return false;
    873     }
    874 
    875     public void setImsConfigListener(ImsConfigListener listener) {
    876         mImsConfigListener = listener;
    877     }
    878 
    879     /**
    880      * Opens the IMS service for making calls and/or receiving generic IMS calls.
    881      * The caller may make subsquent calls through {@link #makeCall}.
    882      * The IMS service will register the device to the operator's network with the credentials
    883      * (from ISIM) periodically in order to receive calls from the operator's network.
    884      * When the IMS service receives a new call, it will send out an intent with
    885      * the provided action string.
    886      * The intent contains a call ID extra {@link getCallId} and it can be used to take a call.
    887      *
    888      * @param serviceClass a service class specified in {@link ImsServiceClass}
    889      *      For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
    890      * @param incomingCallPendingIntent When an incoming call is received,
    891      *        the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to
    892      *        send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE}
    893      *        as the result code and the intent to fill in the call ID; It cannot be null
    894      * @param listener To listen to IMS registration events; It cannot be null
    895      * @return identifier (greater than 0) for the specified service
    896      * @throws NullPointerException if {@code incomingCallPendingIntent}
    897      *      or {@code listener} is null
    898      * @throws ImsException if calling the IMS service results in an error
    899      * @see #getCallId
    900      * @see #getServiceId
    901      */
    902     public int open(int serviceClass, PendingIntent incomingCallPendingIntent,
    903             ImsConnectionStateListener listener) throws ImsException {
    904         checkAndThrowExceptionIfServiceUnavailable();
    905 
    906         if (incomingCallPendingIntent == null) {
    907             throw new NullPointerException("incomingCallPendingIntent can't be null");
    908         }
    909 
    910         if (listener == null) {
    911             throw new NullPointerException("listener can't be null");
    912         }
    913 
    914         int result = 0;
    915 
    916         try {
    917             result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent,
    918                     createRegistrationListenerProxy(serviceClass, listener));
    919         } catch (RemoteException e) {
    920             throw new ImsException("open()", e,
    921                     ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
    922         }
    923 
    924         if (result <= 0) {
    925             // If the return value is a minus value,
    926             // it means that an error occurred in the service.
    927             // So, it needs to convert to the reason code specified in ImsReasonInfo.
    928             throw new ImsException("open()", (result * (-1)));
    929         }
    930 
    931         return result;
    932     }
    933 
    934     /**
    935      * Adds registration listener to the IMS service.
    936      *
    937      * @param serviceClass a service class specified in {@link ImsServiceClass}
    938      *      For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
    939      * @param listener To listen to IMS registration events; It cannot be null
    940      * @throws NullPointerException if {@code listener} is null
    941      * @throws ImsException if calling the IMS service results in an error
    942      */
    943     public void addRegistrationListener(int serviceClass, ImsConnectionStateListener listener)
    944             throws ImsException {
    945         checkAndThrowExceptionIfServiceUnavailable();
    946 
    947         if (listener == null) {
    948             throw new NullPointerException("listener can't be null");
    949         }
    950 
    951         try {
    952             mImsService.addRegistrationListener(mPhoneId, serviceClass,
    953                     createRegistrationListenerProxy(serviceClass, listener));
    954         } catch (RemoteException e) {
    955             throw new ImsException("addRegistrationListener()", e,
    956                     ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
    957         }
    958     }
    959 
    960     /**
    961      * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls.
    962      * All the resources that were allocated to the service are also released.
    963      *
    964      * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open}
    965      * @throws ImsException if calling the IMS service results in an error
    966      */
    967     public void close(int serviceId) throws ImsException {
    968         checkAndThrowExceptionIfServiceUnavailable();
    969 
    970         try {
    971             mImsService.close(serviceId);
    972         } catch (RemoteException e) {
    973             throw new ImsException("close()", e,
    974                     ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
    975         } finally {
    976             mUt = null;
    977             mConfig = null;
    978             mEcbm = null;
    979             mMultiEndpoint = null;
    980         }
    981     }
    982 
    983     /**
    984      * Gets the configuration interface to provision / withdraw the supplementary service settings.
    985      *
    986      * @param serviceId a service id which is obtained from {@link ImsManager#open}
    987      * @return the Ut interface instance
    988      * @throws ImsException if getting the Ut interface results in an error
    989      */
    990     public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId)
    991             throws ImsException {
    992         // FIXME: manage the multiple Ut interfaces based on the service id
    993         if (mUt == null) {
    994             checkAndThrowExceptionIfServiceUnavailable();
    995 
    996             try {
    997                 IImsUt iUt = mImsService.getUtInterface(serviceId);
    998 
    999                 if (iUt == null) {
   1000                     throw new ImsException("getSupplementaryServiceConfiguration()",
   1001                             ImsReasonInfo.CODE_UT_NOT_SUPPORTED);
   1002                 }
   1003 
   1004                 mUt = new ImsUt(iUt);
   1005             } catch (RemoteException e) {
   1006                 throw new ImsException("getSupplementaryServiceConfiguration()", e,
   1007                         ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1008             }
   1009         }
   1010 
   1011         return mUt;
   1012     }
   1013 
   1014     /**
   1015      * Checks if the IMS service has successfully registered to the IMS network
   1016      * with the specified service & call type.
   1017      *
   1018      * @param serviceId a service id which is obtained from {@link ImsManager#open}
   1019      * @param serviceType a service type that is specified in {@link ImsCallProfile}
   1020      *        {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
   1021      *        {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
   1022      * @param callType a call type that is specified in {@link ImsCallProfile}
   1023      *        {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
   1024      *        {@link ImsCallProfile#CALL_TYPE_VOICE}
   1025      *        {@link ImsCallProfile#CALL_TYPE_VT}
   1026      *        {@link ImsCallProfile#CALL_TYPE_VS}
   1027      * @return true if the specified service id is connected to the IMS network;
   1028      *        false otherwise
   1029      * @throws ImsException if calling the IMS service results in an error
   1030      */
   1031     public boolean isConnected(int serviceId, int serviceType, int callType)
   1032             throws ImsException {
   1033         checkAndThrowExceptionIfServiceUnavailable();
   1034 
   1035         try {
   1036             return mImsService.isConnected(serviceId, serviceType, callType);
   1037         } catch (RemoteException e) {
   1038             throw new ImsException("isServiceConnected()", e,
   1039                     ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1040         }
   1041     }
   1042 
   1043     /**
   1044      * Checks if the specified IMS service is opend.
   1045      *
   1046      * @param serviceId a service id which is obtained from {@link ImsManager#open}
   1047      * @return true if the specified service id is opened; false otherwise
   1048      * @throws ImsException if calling the IMS service results in an error
   1049      */
   1050     public boolean isOpened(int serviceId) throws ImsException {
   1051         checkAndThrowExceptionIfServiceUnavailable();
   1052 
   1053         try {
   1054             return mImsService.isOpened(serviceId);
   1055         } catch (RemoteException e) {
   1056             throw new ImsException("isOpened()", e,
   1057                     ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1058         }
   1059     }
   1060 
   1061     /**
   1062      * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
   1063      *
   1064      * @param serviceId a service id which is obtained from {@link ImsManager#open}
   1065      * @param serviceType a service type that is specified in {@link ImsCallProfile}
   1066      *        {@link ImsCallProfile#SERVICE_TYPE_NONE}
   1067      *        {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
   1068      *        {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
   1069      * @param callType a call type that is specified in {@link ImsCallProfile}
   1070      *        {@link ImsCallProfile#CALL_TYPE_VOICE}
   1071      *        {@link ImsCallProfile#CALL_TYPE_VT}
   1072      *        {@link ImsCallProfile#CALL_TYPE_VT_TX}
   1073      *        {@link ImsCallProfile#CALL_TYPE_VT_RX}
   1074      *        {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
   1075      *        {@link ImsCallProfile#CALL_TYPE_VS}
   1076      *        {@link ImsCallProfile#CALL_TYPE_VS_TX}
   1077      *        {@link ImsCallProfile#CALL_TYPE_VS_RX}
   1078      * @return a {@link ImsCallProfile} object
   1079      * @throws ImsException if calling the IMS service results in an error
   1080      */
   1081     public ImsCallProfile createCallProfile(int serviceId,
   1082             int serviceType, int callType) throws ImsException {
   1083         checkAndThrowExceptionIfServiceUnavailable();
   1084 
   1085         try {
   1086             return mImsService.createCallProfile(serviceId, serviceType, callType);
   1087         } catch (RemoteException e) {
   1088             throw new ImsException("createCallProfile()", e,
   1089                     ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1090         }
   1091     }
   1092 
   1093     /**
   1094      * Creates a {@link ImsCall} to make a call.
   1095      *
   1096      * @param serviceId a service id which is obtained from {@link ImsManager#open}
   1097      * @param profile a call profile to make the call
   1098      *      (it contains service type, call type, media information, etc.)
   1099      * @param participants participants to invite the conference call
   1100      * @param listener listen to the call events from {@link ImsCall}
   1101      * @return a {@link ImsCall} object
   1102      * @throws ImsException if calling the IMS service results in an error
   1103      */
   1104     public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees,
   1105             ImsCall.Listener listener) throws ImsException {
   1106         if (DBG) {
   1107             log("makeCall :: serviceId=" + serviceId
   1108                     + ", profile=" + profile);
   1109         }
   1110 
   1111         checkAndThrowExceptionIfServiceUnavailable();
   1112 
   1113         ImsCall call = new ImsCall(mContext, profile);
   1114 
   1115         call.setListener(listener);
   1116         ImsCallSession session = createCallSession(serviceId, profile);
   1117 
   1118         if ((callees != null) && (callees.length == 1)) {
   1119             call.start(session, callees[0]);
   1120         } else {
   1121             call.start(session, callees);
   1122         }
   1123 
   1124         return call;
   1125     }
   1126 
   1127     /**
   1128      * Creates a {@link ImsCall} to take an incoming call.
   1129      *
   1130      * @param serviceId a service id which is obtained from {@link ImsManager#open}
   1131      * @param incomingCallIntent the incoming call broadcast intent
   1132      * @param listener to listen to the call events from {@link ImsCall}
   1133      * @return a {@link ImsCall} object
   1134      * @throws ImsException if calling the IMS service results in an error
   1135      */
   1136     public ImsCall takeCall(int serviceId, Intent incomingCallIntent,
   1137             ImsCall.Listener listener) throws ImsException {
   1138         if (DBG) {
   1139             log("takeCall :: serviceId=" + serviceId
   1140                     + ", incomingCall=" + incomingCallIntent);
   1141         }
   1142 
   1143         checkAndThrowExceptionIfServiceUnavailable();
   1144 
   1145         if (incomingCallIntent == null) {
   1146             throw new ImsException("Can't retrieve session with null intent",
   1147                     ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
   1148         }
   1149 
   1150         int incomingServiceId = getServiceId(incomingCallIntent);
   1151 
   1152         if (serviceId != incomingServiceId) {
   1153             throw new ImsException("Service id is mismatched in the incoming call intent",
   1154                     ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
   1155         }
   1156 
   1157         String callId = getCallId(incomingCallIntent);
   1158 
   1159         if (callId == null) {
   1160             throw new ImsException("Call ID missing in the incoming call intent",
   1161                     ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
   1162         }
   1163 
   1164         try {
   1165             IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId);
   1166 
   1167             if (session == null) {
   1168                 throw new ImsException("No pending session for the call",
   1169                         ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL);
   1170             }
   1171 
   1172             ImsCall call = new ImsCall(mContext, session.getCallProfile());
   1173 
   1174             call.attachSession(new ImsCallSession(session));
   1175             call.setListener(listener);
   1176 
   1177             return call;
   1178         } catch (Throwable t) {
   1179             throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED);
   1180         }
   1181     }
   1182 
   1183     /**
   1184      * Gets the config interface to get/set service/capability parameters.
   1185      *
   1186      * @return the ImsConfig instance.
   1187      * @throws ImsException if getting the setting interface results in an error.
   1188      */
   1189     public ImsConfig getConfigInterface() throws ImsException {
   1190 
   1191         if (mConfig == null) {
   1192             checkAndThrowExceptionIfServiceUnavailable();
   1193 
   1194             try {
   1195                 IImsConfig config = mImsService.getConfigInterface(mPhoneId);
   1196                 if (config == null) {
   1197                     throw new ImsException("getConfigInterface()",
   1198                             ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
   1199                 }
   1200                 mConfig = new ImsConfig(config, mContext);
   1201             } catch (RemoteException e) {
   1202                 throw new ImsException("getConfigInterface()", e,
   1203                         ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1204             }
   1205         }
   1206         if (DBG) log("getConfigInterface(), mConfig= " + mConfig);
   1207         return mConfig;
   1208     }
   1209 
   1210     public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete)
   1211             throws ImsException {
   1212 
   1213         checkAndThrowExceptionIfServiceUnavailable();
   1214 
   1215         try {
   1216             mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete);
   1217         } catch (RemoteException e) {
   1218             throw new ImsException("setTTYMode()", e,
   1219                     ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1220         }
   1221 
   1222         if (!getBooleanCarrierConfig(context,
   1223                 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
   1224             setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) &&
   1225                     isEnhanced4gLteModeSettingEnabledByUser(context));
   1226         }
   1227     }
   1228 
   1229     /**
   1230      * Get the boolean config from carrier config manager.
   1231      *
   1232      * @param context the context to get carrier service
   1233      * @param key config key defined in CarrierConfigManager
   1234      * @return boolean value of corresponding key.
   1235      */
   1236     private static boolean getBooleanCarrierConfig(Context context, String key) {
   1237         CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
   1238                 Context.CARRIER_CONFIG_SERVICE);
   1239         PersistableBundle b = null;
   1240         if (configManager != null) {
   1241             b = configManager.getConfig();
   1242         }
   1243         if (b != null) {
   1244             return b.getBoolean(key);
   1245         } else {
   1246             // Return static default defined in CarrierConfigManager.
   1247             return CarrierConfigManager.getDefaultConfig().getBoolean(key);
   1248         }
   1249     }
   1250 
   1251     /**
   1252      * Get the int config from carrier config manager.
   1253      *
   1254      * @param context the context to get carrier service
   1255      * @param key config key defined in CarrierConfigManager
   1256      * @return integer value of corresponding key.
   1257      */
   1258     private static int getIntCarrierConfig(Context context, String key) {
   1259         CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
   1260                 Context.CARRIER_CONFIG_SERVICE);
   1261         PersistableBundle b = null;
   1262         if (configManager != null) {
   1263             b = configManager.getConfig();
   1264         }
   1265         if (b != null) {
   1266             return b.getInt(key);
   1267         } else {
   1268             // Return static default defined in CarrierConfigManager.
   1269             return CarrierConfigManager.getDefaultConfig().getInt(key);
   1270         }
   1271     }
   1272 
   1273     /**
   1274      * Gets the call ID from the specified incoming call broadcast intent.
   1275      *
   1276      * @param incomingCallIntent the incoming call broadcast intent
   1277      * @return the call ID or null if the intent does not contain it
   1278      */
   1279     private static String getCallId(Intent incomingCallIntent) {
   1280         if (incomingCallIntent == null) {
   1281             return null;
   1282         }
   1283 
   1284         return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
   1285     }
   1286 
   1287     /**
   1288      * Gets the service type from the specified incoming call broadcast intent.
   1289      *
   1290      * @param incomingCallIntent the incoming call broadcast intent
   1291      * @return the service identifier or -1 if the intent does not contain it
   1292      */
   1293     private static int getServiceId(Intent incomingCallIntent) {
   1294         if (incomingCallIntent == null) {
   1295             return (-1);
   1296         }
   1297 
   1298         return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1);
   1299     }
   1300 
   1301     /**
   1302      * Binds the IMS service only if the service is not created.
   1303      */
   1304     private void checkAndThrowExceptionIfServiceUnavailable()
   1305             throws ImsException {
   1306         if (mImsService == null) {
   1307             createImsService(true);
   1308 
   1309             if (mImsService == null) {
   1310                 throw new ImsException("Service is unavailable",
   1311                         ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1312             }
   1313         }
   1314     }
   1315 
   1316     private static String getImsServiceName(int phoneId) {
   1317         // TODO: MSIM implementation needs to decide on service name as a function of phoneId
   1318         return IMS_SERVICE;
   1319     }
   1320 
   1321     /**
   1322      * Binds the IMS service to make/receive the call.
   1323      */
   1324     private void createImsService(boolean checkService) {
   1325         if (checkService) {
   1326             IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
   1327 
   1328             if (binder == null) {
   1329                 return;
   1330             }
   1331         }
   1332 
   1333         IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));
   1334 
   1335         if (b != null) {
   1336             try {
   1337                 b.linkToDeath(mDeathRecipient, 0);
   1338             } catch (RemoteException e) {
   1339             }
   1340         }
   1341 
   1342         mImsService = IImsService.Stub.asInterface(b);
   1343     }
   1344 
   1345     /**
   1346      * Creates a {@link ImsCallSession} with the specified call profile.
   1347      * Use other methods, if applicable, instead of interacting with
   1348      * {@link ImsCallSession} directly.
   1349      *
   1350      * @param serviceId a service id which is obtained from {@link ImsManager#open}
   1351      * @param profile a call profile to make the call
   1352      */
   1353     private ImsCallSession createCallSession(int serviceId,
   1354             ImsCallProfile profile) throws ImsException {
   1355         try {
   1356             return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null));
   1357         } catch (RemoteException e) {
   1358             return null;
   1359         }
   1360     }
   1361 
   1362     private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass,
   1363             ImsConnectionStateListener listener) {
   1364         ImsRegistrationListenerProxy proxy =
   1365                 new ImsRegistrationListenerProxy(serviceClass, listener);
   1366         return proxy;
   1367     }
   1368 
   1369     private static void log(String s) {
   1370         Rlog.d(TAG, s);
   1371     }
   1372 
   1373     private static void loge(String s) {
   1374         Rlog.e(TAG, s);
   1375     }
   1376 
   1377     private static void loge(String s, Throwable t) {
   1378         Rlog.e(TAG, s, t);
   1379     }
   1380 
   1381     /**
   1382      * Used for turning on IMS.if its off already
   1383      */
   1384     private void turnOnIms() throws ImsException {
   1385         checkAndThrowExceptionIfServiceUnavailable();
   1386 
   1387         try {
   1388             mImsService.turnOnIms(mPhoneId);
   1389         } catch (RemoteException e) {
   1390             throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1391         }
   1392     }
   1393 
   1394     private boolean isImsTurnOffAllowed() {
   1395         return isTurnOffImsAllowedByPlatform(mContext)
   1396                 && (!isWfcEnabledByPlatform(mContext)
   1397                 || !isWfcEnabledByUser(mContext));
   1398     }
   1399 
   1400     private void setLteFeatureValues(boolean turnOn) {
   1401         log("setLteFeatureValues: " + turnOn);
   1402         try {
   1403             ImsConfig config = getConfigInterface();
   1404             if (config != null) {
   1405                 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
   1406                         TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, mImsConfigListener);
   1407 
   1408                 if (isVtEnabledByPlatform(mContext)) {
   1409                     boolean enableViLte = turnOn && isVtEnabledByUser(mContext) &&
   1410                             isDataEnabled();
   1411                     config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
   1412                             TelephonyManager.NETWORK_TYPE_LTE,
   1413                             enableViLte ? 1 : 0,
   1414                             mImsConfigListener);
   1415                 }
   1416             }
   1417         } catch (ImsException e) {
   1418             loge("setLteFeatureValues: exception ", e);
   1419         }
   1420     }
   1421 
   1422     private void setAdvanced4GMode(boolean turnOn) throws ImsException {
   1423         checkAndThrowExceptionIfServiceUnavailable();
   1424 
   1425         // if turnOn: first set feature values then call turnOnIms()
   1426         // if turnOff: only set feature values if IMS turn off is not allowed. If turn off is
   1427         // allowed, first call turnOffIms() then set feature values
   1428         if (turnOn) {
   1429             setLteFeatureValues(turnOn);
   1430             log("setAdvanced4GMode: turnOnIms");
   1431             turnOnIms();
   1432         } else {
   1433             if (isImsTurnOffAllowed()) {
   1434                 log("setAdvanced4GMode: turnOffIms");
   1435                 turnOffIms();
   1436             }
   1437             setLteFeatureValues(turnOn);
   1438         }
   1439     }
   1440 
   1441     /**
   1442      * Used for turning off IMS completely in order to make the device CSFB'ed.
   1443      * Once turned off, all calls will be over CS.
   1444      */
   1445     private void turnOffIms() throws ImsException {
   1446         checkAndThrowExceptionIfServiceUnavailable();
   1447 
   1448         try {
   1449             mImsService.turnOffIms(mPhoneId);
   1450         } catch (RemoteException e) {
   1451             throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1452         }
   1453     }
   1454 
   1455     /**
   1456      * Death recipient class for monitoring IMS service.
   1457      */
   1458     private class ImsServiceDeathRecipient implements IBinder.DeathRecipient {
   1459         @Override
   1460         public void binderDied() {
   1461             mImsService = null;
   1462             mUt = null;
   1463             mConfig = null;
   1464             mEcbm = null;
   1465             mMultiEndpoint = null;
   1466 
   1467             if (mContext != null) {
   1468                 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN);
   1469                 intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
   1470                 mContext.sendBroadcast(new Intent(intent));
   1471             }
   1472         }
   1473     }
   1474 
   1475     /**
   1476      * Adapter class for {@link IImsRegistrationListener}.
   1477      */
   1478     private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub {
   1479         private int mServiceClass;
   1480         private ImsConnectionStateListener mListener;
   1481 
   1482         public ImsRegistrationListenerProxy(int serviceClass,
   1483                 ImsConnectionStateListener listener) {
   1484             mServiceClass = serviceClass;
   1485             mListener = listener;
   1486         }
   1487 
   1488         public boolean isSameProxy(int serviceClass) {
   1489             return (mServiceClass == serviceClass);
   1490         }
   1491 
   1492         @Deprecated
   1493         public void registrationConnected() {
   1494             if (DBG) {
   1495                 log("registrationConnected ::");
   1496             }
   1497 
   1498             if (mListener != null) {
   1499                 mListener.onImsConnected();
   1500             }
   1501         }
   1502 
   1503         @Deprecated
   1504         public void registrationProgressing() {
   1505             if (DBG) {
   1506                 log("registrationProgressing ::");
   1507             }
   1508 
   1509             if (mListener != null) {
   1510                 mListener.onImsProgressing();
   1511             }
   1512         }
   1513 
   1514         @Override
   1515         public void registrationConnectedWithRadioTech(int imsRadioTech) {
   1516             // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY
   1517             //       values in ServiceState.java.
   1518             if (DBG) {
   1519                 log("registrationConnectedWithRadioTech :: imsRadioTech=" + imsRadioTech);
   1520             }
   1521 
   1522             if (mListener != null) {
   1523                 mListener.onImsConnected();
   1524             }
   1525         }
   1526 
   1527         @Override
   1528         public void registrationProgressingWithRadioTech(int imsRadioTech) {
   1529             // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY
   1530             //       values in ServiceState.java.
   1531             if (DBG) {
   1532                 log("registrationProgressingWithRadioTech :: imsRadioTech=" + imsRadioTech);
   1533             }
   1534 
   1535             if (mListener != null) {
   1536                 mListener.onImsProgressing();
   1537             }
   1538         }
   1539 
   1540         @Override
   1541         public void registrationDisconnected(ImsReasonInfo imsReasonInfo) {
   1542             if (DBG) {
   1543                 log("registrationDisconnected :: imsReasonInfo" + imsReasonInfo);
   1544             }
   1545 
   1546             if (mListener != null) {
   1547                 mListener.onImsDisconnected(imsReasonInfo);
   1548             }
   1549         }
   1550 
   1551         @Override
   1552         public void registrationResumed() {
   1553             if (DBG) {
   1554                 log("registrationResumed ::");
   1555             }
   1556 
   1557             if (mListener != null) {
   1558                 mListener.onImsResumed();
   1559             }
   1560         }
   1561 
   1562         @Override
   1563         public void registrationSuspended() {
   1564             if (DBG) {
   1565                 log("registrationSuspended ::");
   1566             }
   1567 
   1568             if (mListener != null) {
   1569                 mListener.onImsSuspended();
   1570             }
   1571         }
   1572 
   1573         @Override
   1574         public void registrationServiceCapabilityChanged(int serviceClass, int event) {
   1575             log("registrationServiceCapabilityChanged :: serviceClass=" +
   1576                     serviceClass + ", event=" + event);
   1577 
   1578             if (mListener != null) {
   1579                 mListener.onImsConnected();
   1580             }
   1581         }
   1582 
   1583         @Override
   1584         public void registrationFeatureCapabilityChanged(int serviceClass,
   1585                 int[] enabledFeatures, int[] disabledFeatures) {
   1586             log("registrationFeatureCapabilityChanged :: serviceClass=" +
   1587                     serviceClass);
   1588             if (mListener != null) {
   1589                 mListener.onFeatureCapabilityChanged(serviceClass,
   1590                         enabledFeatures, disabledFeatures);
   1591             }
   1592         }
   1593 
   1594         @Override
   1595         public void voiceMessageCountUpdate(int count) {
   1596             log("voiceMessageCountUpdate :: count=" + count);
   1597 
   1598             if (mListener != null) {
   1599                 mListener.onVoiceMessageCountChanged(count);
   1600             }
   1601         }
   1602 
   1603         @Override
   1604         public void registrationAssociatedUriChanged(Uri[] uris) {
   1605             if (DBG) log("registrationAssociatedUriChanged ::");
   1606 
   1607             if (mListener != null) {
   1608                 mListener.registrationAssociatedUriChanged(uris);
   1609             }
   1610         }
   1611     }
   1612 
   1613     /**
   1614      * Gets the ECBM interface to request ECBM exit.
   1615      *
   1616      * @param serviceId a service id which is obtained from {@link ImsManager#open}
   1617      * @return the ECBM interface instance
   1618      * @throws ImsException if getting the ECBM interface results in an error
   1619      */
   1620     public ImsEcbm getEcbmInterface(int serviceId) throws ImsException {
   1621         if (mEcbm == null) {
   1622             checkAndThrowExceptionIfServiceUnavailable();
   1623 
   1624             try {
   1625                 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId);
   1626 
   1627                 if (iEcbm == null) {
   1628                     throw new ImsException("getEcbmInterface()",
   1629                             ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED);
   1630                 }
   1631                 mEcbm = new ImsEcbm(iEcbm);
   1632             } catch (RemoteException e) {
   1633                 throw new ImsException("getEcbmInterface()", e,
   1634                         ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1635             }
   1636         }
   1637         return mEcbm;
   1638     }
   1639 
   1640     /**
   1641      * Gets the Multi-Endpoint interface to subscribe to multi-enpoint notifications..
   1642      *
   1643      * @param serviceId a service id which is obtained from {@link ImsManager#open}
   1644      * @return the multi-endpoint interface instance
   1645      * @throws ImsException if getting the multi-endpoint interface results in an error
   1646      */
   1647     public ImsMultiEndpoint getMultiEndpointInterface(int serviceId) throws ImsException {
   1648         if (mMultiEndpoint == null) {
   1649             checkAndThrowExceptionIfServiceUnavailable();
   1650 
   1651             try {
   1652                 IImsMultiEndpoint iImsMultiEndpoint = mImsService.getMultiEndpointInterface(
   1653                         serviceId);
   1654 
   1655                 if (iImsMultiEndpoint == null) {
   1656                     throw new ImsException("getMultiEndpointInterface()",
   1657                             ImsReasonInfo.CODE_MULTIENDPOINT_NOT_SUPPORTED);
   1658                 }
   1659                 mMultiEndpoint = new ImsMultiEndpoint(iImsMultiEndpoint);
   1660             } catch (RemoteException e) {
   1661                 throw new ImsException("getMultiEndpointInterface()", e,
   1662                         ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
   1663             }
   1664         }
   1665         return mMultiEndpoint;
   1666     }
   1667 
   1668     /**
   1669      * Resets ImsManager settings back to factory defaults.
   1670      *
   1671      * @hide
   1672      */
   1673     public static void factoryReset(Context context) {
   1674         // Set VoLTE to default
   1675         android.provider.Settings.Global.putInt(context.getContentResolver(),
   1676                 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED,
   1677                 ImsConfig.FeatureValueConstants.ON);
   1678 
   1679         // Set VoWiFi to default
   1680         android.provider.Settings.Global.putInt(context.getContentResolver(),
   1681                 android.provider.Settings.Global.WFC_IMS_ENABLED,
   1682                 getBooleanCarrierConfig(context,
   1683                         CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL) ?
   1684                         ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
   1685 
   1686         // Set VoWiFi mode to default
   1687         android.provider.Settings.Global.putInt(context.getContentResolver(),
   1688                 android.provider.Settings.Global.WFC_IMS_MODE,
   1689                 getIntCarrierConfig(context,
   1690                         CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
   1691 
   1692         // Set VoWiFi roaming to default
   1693         android.provider.Settings.Global.putInt(context.getContentResolver(),
   1694                 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
   1695                 getBooleanCarrierConfig(context,
   1696                         CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ?
   1697                         ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
   1698 
   1699         // Set VT to default
   1700         android.provider.Settings.Global.putInt(context.getContentResolver(),
   1701                 android.provider.Settings.Global.VT_IMS_ENABLED,
   1702                 ImsConfig.FeatureValueConstants.ON);
   1703 
   1704         // Push settings to ImsConfig
   1705         ImsManager.updateImsServiceConfig(context,
   1706                 SubscriptionManager.getDefaultVoicePhoneId(), true);
   1707     }
   1708 
   1709     private boolean isDataEnabled() {
   1710         return SystemProperties.getBoolean(DATA_ENABLED_PROP, true);
   1711     }
   1712 
   1713     /**
   1714      * Set data enabled/disabled flag.
   1715      * @param enabled True if data is enabled, otherwise disabled.
   1716      */
   1717     public void setDataEnabled(boolean enabled) {
   1718         log("setDataEnabled: " + enabled);
   1719         SystemProperties.set(DATA_ENABLED_PROP, enabled ? TRUE : FALSE);
   1720     }
   1721 
   1722     private boolean isVolteProvisioned() {
   1723         return SystemProperties.getBoolean(VOLTE_PROVISIONED_PROP, true);
   1724     }
   1725 
   1726     private void setVolteProvisionedProperty(boolean provisioned) {
   1727         SystemProperties.set(VOLTE_PROVISIONED_PROP, provisioned ? TRUE : FALSE);
   1728     }
   1729 
   1730     private boolean isWfcProvisioned() {
   1731         return SystemProperties.getBoolean(WFC_PROVISIONED_PROP, true);
   1732     }
   1733 
   1734     private void setWfcProvisionedProperty(boolean provisioned) {
   1735         SystemProperties.set(WFC_PROVISIONED_PROP, provisioned ? TRUE : FALSE);
   1736     }
   1737 
   1738     private boolean isVtProvisioned() {
   1739         return SystemProperties.getBoolean(VT_PROVISIONED_PROP, true);
   1740     }
   1741 
   1742     private void setVtProvisionedProperty(boolean provisioned) {
   1743         SystemProperties.set(VT_PROVISIONED_PROP, provisioned ? TRUE : FALSE);
   1744     }
   1745 
   1746     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1747         pw.println("ImsManager:");
   1748         pw.println("  mPhoneId = " + mPhoneId);
   1749         pw.println("  mConfigUpdated = " + mConfigUpdated);
   1750         pw.println("  mImsService = " + mImsService);
   1751         pw.println("  mDataEnabled = " + isDataEnabled());
   1752 
   1753         pw.println("  isGbaValid = " + isGbaValid(mContext));
   1754         pw.println("  isImsTurnOffAllowed = " + isImsTurnOffAllowed());
   1755         pw.println("  isNonTtyOrTtyOnVolteEnabled = " + isNonTtyOrTtyOnVolteEnabled(mContext));
   1756 
   1757         pw.println("  isVolteEnabledByPlatform = " + isVolteEnabledByPlatform(mContext));
   1758         pw.println("  isVolteProvisionedOnDevice = " + isVolteProvisionedOnDevice(mContext));
   1759         pw.println("  isEnhanced4gLteModeSettingEnabledByUser = " +
   1760                 isEnhanced4gLteModeSettingEnabledByUser(mContext));
   1761         pw.println("  isVtEnabledByPlatform = " + isVtEnabledByPlatform(mContext));
   1762         pw.println("  isVtEnabledByUser = " + isVtEnabledByUser(mContext));
   1763 
   1764         pw.println("  isWfcEnabledByPlatform = " + isWfcEnabledByPlatform(mContext));
   1765         pw.println("  isWfcEnabledByUser = " + isWfcEnabledByUser(mContext));
   1766         pw.println("  getWfcMode = " + getWfcMode(mContext));
   1767         pw.println("  isWfcRoamingEnabledByUser = " + isWfcRoamingEnabledByUser(mContext));
   1768 
   1769         pw.println("  isVtProvisionedOnDevice = " + isVtProvisionedOnDevice(mContext));
   1770         pw.println("  isWfcProvisionedOnDevice = " + isWfcProvisionedOnDevice(mContext));
   1771         pw.flush();
   1772     }
   1773 }
   1774