1 /* 2 * Copyright (c) 2015, Motorola Mobility LLC 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * - Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * - Neither the name of Motorola Mobility nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 * DAMAGE. 27 */ 28 29 package com.android.service.ims; 30 31 import android.content.Context; 32 import android.os.PersistableBundle; 33 import android.telephony.AccessNetworkConstants; 34 import android.telephony.CarrierConfigManager; 35 import android.telephony.SubscriptionInfo; 36 import android.telephony.SubscriptionManager; 37 import android.telephony.ims.ImsException; 38 import android.telephony.ims.ImsManager; 39 import android.telephony.ims.ImsMmTelManager; 40 import android.telephony.ims.ImsRcsManager; 41 import android.telephony.ims.ProvisioningManager; 42 import android.telephony.ims.feature.MmTelFeature; 43 import android.telephony.ims.stub.ImsRegistrationImplBase; 44 45 import com.android.ims.internal.Logger; 46 import com.android.internal.telephony.flags.Flags; 47 48 import java.util.List; 49 import java.util.concurrent.LinkedBlockingQueue; 50 import java.util.concurrent.TimeUnit; 51 52 public class RcsSettingUtils { 53 static private Logger logger = Logger.getLogger("RcsSettingUtils"); 54 private static final int TIMEOUT_GET_CONFIGURATION_MS = 5000; 55 56 // Default number of entries for getMaxNumbersInRCL 57 private static final int DEFAULT_NUM_ENTRIES_IN_RCL = 100; 58 // Default for getCapabPollListSubExp in seconds. 59 private static final int DEFAULT_CAPABILITY_POLL_LIST_SUB_EXPIRATION_SEC = 30; 60 // Default for getAvailabilityCacheExpiration in seconds. 61 private static final int DEFAULT_AVAILABILITY_CACHE_EXPIRATION_SEC = 30; 62 // Default for getPublishThrottle in milliseconds 63 private static final int DEFAULT_PUBLISH_THROTTLE_MS = 60000; 64 isVoLteProvisioned(int subId)65 public static boolean isVoLteProvisioned(int subId) { 66 try { 67 boolean isProvisioned; 68 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 69 isProvisioned = manager.getProvisioningStatusForCapability( 70 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 71 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 72 logger.debug("isVoLteProvisioned=" + isProvisioned); 73 return isProvisioned; 74 } catch (Exception e) { 75 logger.debug("isVoLteProvisioned, exception = " + e.getMessage()); 76 return false; 77 } 78 } 79 isVowifiProvisioned(int subId)80 public static boolean isVowifiProvisioned(int subId) { 81 try { 82 boolean isProvisioned; 83 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 84 isProvisioned = manager.getProvisioningStatusForCapability( 85 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 86 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 87 logger.debug("isVowifiProvisioned=" + isProvisioned); 88 return isProvisioned; 89 } catch (Exception e) { 90 logger.debug("isVowifiProvisioned, exception = " + e.getMessage()); 91 return false; 92 } 93 } 94 isLvcProvisioned(int subId)95 public static boolean isLvcProvisioned(int subId) { 96 try { 97 boolean isProvisioned; 98 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 99 isProvisioned = manager.getProvisioningStatusForCapability( 100 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 101 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 102 logger.debug("isLvcProvisioned=" + isProvisioned); 103 return isProvisioned; 104 } catch (Exception e) { 105 logger.debug("isLvcProvisioned, exception = " + e.getMessage()); 106 return false; 107 } 108 } 109 isEabProvisioned(Context context, int subId)110 public static boolean isEabProvisioned(Context context, int subId) { 111 boolean isProvisioned = false; 112 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 113 logger.debug("isEabProvisioned: no valid subscriptions!"); 114 return false; 115 } 116 CarrierConfigManager configManager = (CarrierConfigManager) 117 context.getSystemService(Context.CARRIER_CONFIG_SERVICE); 118 if (configManager != null) { 119 PersistableBundle config = configManager.getConfigForSubId(subId); 120 if (config != null && !config.getBoolean( 121 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONED_BOOL)) { 122 // If we don't need provisioning, just return true. 123 return true; 124 } 125 } 126 try { 127 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 128 isProvisioned = manager.getRcsProvisioningStatusForCapability( 129 ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE, 130 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 131 } catch (Exception e) { 132 logger.debug("isEabProvisioned: exception=" + e.getMessage()); 133 } 134 logger.debug("isEabProvisioned=" + isProvisioned); 135 return isProvisioned; 136 } 137 isPublishEnabled(Context context, int subId)138 public static boolean isPublishEnabled(Context context, int subId) { 139 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 140 logger.debug("isPublishEnabled: no valid subscriptions!"); 141 return false; 142 } 143 CarrierConfigManager configManager = (CarrierConfigManager) 144 context.getSystemService(Context.CARRIER_CONFIG_SERVICE); 145 if (configManager != null) { 146 PersistableBundle config = configManager.getConfigForSubId(subId); 147 return (config != null) && config.getBoolean( 148 CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false); 149 } 150 return false; 151 } 152 hasUserEnabledContactDiscovery(Context context, int subId)153 public static boolean hasUserEnabledContactDiscovery(Context context, int subId) { 154 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 155 logger.debug("hasUserEnabledContactDiscovery: no valid subscriptions!"); 156 return false; 157 } 158 try { 159 ImsManager imsManager = context.getSystemService(ImsManager.class); 160 ImsRcsManager rcsManager = imsManager.getImsRcsManager(subId); 161 return rcsManager.getUceAdapter().isUceSettingEnabled(); 162 } catch (Exception e) { 163 logger.warn("hasUserEnabledContactDiscovery: Exception = " + e.getMessage()); 164 return false; 165 } 166 } 167 getSIPT1Timer(int subId)168 public static int getSIPT1Timer(int subId) { 169 int sipT1Timer = 0; 170 try { 171 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 172 sipT1Timer = manager.getProvisioningIntValue(ProvisioningManager.KEY_T1_TIMER_VALUE_MS); 173 } catch (Exception e) { 174 // If there is no active subscriptions, this will throw an exception. 175 logger.debug("getSIPT1Timer: exception=" + e.getMessage()); 176 } 177 logger.debug("getSIPT1Timer=" + sipT1Timer); 178 return sipT1Timer; 179 } 180 181 /** 182 * Capability discovery status of Enabled (1), or Disabled (0). 183 */ getCapabilityDiscoveryEnabled(int subId)184 public static boolean getCapabilityDiscoveryEnabled(int subId) { 185 boolean capabilityDiscoveryEnabled = false; 186 try { 187 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 188 capabilityDiscoveryEnabled = manager.getProvisioningIntValue( 189 ProvisioningManager.KEY_RCS_CAPABILITY_DISCOVERY_ENABLED) == 190 ProvisioningManager.PROVISIONING_VALUE_ENABLED; 191 } catch (Exception e) { 192 // If there is no active subscriptions, this will throw an exception. 193 logger.debug("capabilityDiscoveryEnabled: exception=" + e.getMessage()); 194 } 195 logger.debug("capabilityDiscoveryEnabled=" + capabilityDiscoveryEnabled); 196 return capabilityDiscoveryEnabled; 197 } 198 199 /** 200 * The Maximum number of MDNs contained in one Request Contained List. 201 */ getMaxNumbersInRCL(int subId)202 public static int getMaxNumbersInRCL(int subId) { 203 int maxNumbersInRCL = DEFAULT_NUM_ENTRIES_IN_RCL; 204 try { 205 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 206 maxNumbersInRCL = manager.getProvisioningIntValue( 207 ProvisioningManager.KEY_RCS_MAX_NUM_ENTRIES_IN_RCL); 208 } catch (Exception e) { 209 // If there is no active subscriptions, this will throw an exception. 210 logger.debug("getMaxNumbersInRCL: exception=" + e.getMessage()); 211 } 212 logger.debug("getMaxNumbersInRCL=" + maxNumbersInRCL); 213 return maxNumbersInRCL; 214 } 215 216 /** 217 * Expiration timer for subscription of a Request Contained List, used in capability polling. 218 */ getCapabPollListSubExp(int subId)219 public static int getCapabPollListSubExp(int subId) { 220 int capabPollListSubExp = DEFAULT_CAPABILITY_POLL_LIST_SUB_EXPIRATION_SEC; 221 try { 222 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 223 capabPollListSubExp = manager.getProvisioningIntValue( 224 ProvisioningManager.KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC); 225 } catch (Exception e) { 226 // If there is no active subscriptions, this will throw an exception. 227 logger.debug("getCapabPollListSubExp: exception=" + e.getMessage()); 228 } 229 logger.debug("getCapabPollListSubExp=" + capabPollListSubExp); 230 return capabPollListSubExp; 231 } 232 233 /** 234 * Period of time the availability information of a contact is cached on device. 235 */ getAvailabilityCacheExpiration(int subId)236 public static int getAvailabilityCacheExpiration(int subId) { 237 int availabilityCacheExpiration = DEFAULT_AVAILABILITY_CACHE_EXPIRATION_SEC; 238 try { 239 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 240 availabilityCacheExpiration = manager.getProvisioningIntValue( 241 ProvisioningManager.KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC); 242 } catch (Exception e) { 243 // If there is no active subscriptions, this will throw an exception. 244 logger.debug("getAvailabilityCacheExpiration: exception=" + e.getMessage()); 245 } 246 logger.debug("getAvailabilityCacheExpiration=" + availabilityCacheExpiration); 247 return availabilityCacheExpiration; 248 } 249 getPublishThrottle(int subId)250 public static int getPublishThrottle(int subId) { 251 // Default 252 int publishThrottle = DEFAULT_PUBLISH_THROTTLE_MS; 253 try { 254 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 255 publishThrottle = manager.getProvisioningIntValue( 256 ProvisioningManager.KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS); 257 } catch (Exception e) { 258 // If there is no active subscriptions, this will throw an exception. 259 logger.debug("publishThrottle: exception=" + e.getMessage()); 260 } 261 logger.debug("publishThrottle=" + publishThrottle); 262 return publishThrottle; 263 } 264 isVtEnabledByUser(int subId)265 public static boolean isVtEnabledByUser(int subId) { 266 try { 267 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 268 return mmTelManager.isVtSettingEnabled(); 269 } catch (Exception e) { 270 logger.warn("isVtEnabledByUser exception = " + e.getMessage()); 271 return false; 272 } 273 } 274 isWfcEnabledByUser(int subId)275 public static boolean isWfcEnabledByUser(int subId) { 276 try { 277 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 278 return mmTelManager.isVoWiFiSettingEnabled(); 279 } catch (Exception e) { 280 logger.warn("isWfcEnabledByUser exception = " + e.getMessage()); 281 return false; 282 } 283 } 284 isAdvancedCallingEnabledByUser(int subId)285 public static boolean isAdvancedCallingEnabledByUser(int subId) { 286 try { 287 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 288 return mmTelManager.isAdvancedCallingSettingEnabled(); 289 } catch (Exception e) { 290 logger.warn("isAdvancedCallingEnabledByUser exception = " + e.getMessage()); 291 return false; 292 } 293 } 294 isVoLteSupported(int subId)295 public static boolean isVoLteSupported(int subId) { 296 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 297 return false; 298 } 299 LinkedBlockingQueue<Boolean> resultQueue = new LinkedBlockingQueue<>(1); 300 try { 301 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 302 mmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 303 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, resultQueue::offer); 304 } catch (ImsException e) { 305 logger.warn("isVoLteSupported: ImsException = " + e.getMessage()); 306 return false; 307 } 308 try { 309 Boolean result = resultQueue.poll(TIMEOUT_GET_CONFIGURATION_MS, TimeUnit.MILLISECONDS); 310 return (result != null) ? result : false; 311 } catch (InterruptedException e) { 312 logger.warn("isVoLteSupported, InterruptedException=" + e.getMessage()); 313 return false; 314 } 315 } 316 isVoWiFiSupported(int subId)317 public static boolean isVoWiFiSupported(int subId) { 318 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 319 return false; 320 } 321 LinkedBlockingQueue<Boolean> resultQueue = new LinkedBlockingQueue<>(1); 322 try { 323 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 324 mmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 325 AccessNetworkConstants.TRANSPORT_TYPE_WLAN, Runnable::run, resultQueue::offer); 326 } catch (ImsException e) { 327 logger.warn("isVoWiFiSupported: ImsException = " + e.getMessage()); 328 return false; 329 } 330 try { 331 Boolean result = resultQueue.poll(TIMEOUT_GET_CONFIGURATION_MS, TimeUnit.MILLISECONDS); 332 return (result != null) ? result : false; 333 } catch (InterruptedException e) { 334 logger.warn("isVoWiFiSupported, InterruptedException=" + e.getMessage()); 335 return false; 336 } 337 } 338 isVtSupported(int subId)339 public static boolean isVtSupported(int subId) { 340 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 341 return false; 342 } 343 LinkedBlockingQueue<Boolean> resultQueue = new LinkedBlockingQueue<>(1); 344 try { 345 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 346 mmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 347 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, resultQueue::offer); 348 } catch (ImsException e) { 349 logger.warn("isVoWiFiSupported: ImsException = " + e.getMessage()); 350 return false; 351 } 352 try { 353 Boolean result = resultQueue.poll(TIMEOUT_GET_CONFIGURATION_MS, TimeUnit.MILLISECONDS); 354 return (result != null) ? result : false; 355 } catch (InterruptedException e) { 356 logger.warn("isVtSupported, InterruptedException=" + e.getMessage()); 357 return false; 358 } 359 } 360 getDefaultSubscriptionId(Context context)361 public static int getDefaultSubscriptionId(Context context) { 362 SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); 363 if (sm == null) return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 364 sm = sm.createForAllUserProfiles(); 365 366 List<SubscriptionInfo> infos = sm.getActiveSubscriptionInfoList(); 367 if (infos == null || infos.isEmpty()) { 368 // There are no active subscriptions right now. 369 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 370 } 371 // This code does not support MSIM unfortunately, so only provide presence on the default 372 // voice subscription that the user chose. 373 int defaultSub = SubscriptionManager.getDefaultVoiceSubscriptionId(); 374 if (!SubscriptionManager.isValidSubscriptionId(defaultSub)) { 375 // The voice sub may not have been specified, in this case, use the default data. 376 defaultSub = SubscriptionManager.getDefaultDataSubscriptionId(); 377 } 378 // If the user has no default set, just pick the first as backup. 379 if (!SubscriptionManager.isValidSubscriptionId(defaultSub)) { 380 for (SubscriptionInfo info : infos) { 381 if (!info.isOpportunistic()) { 382 defaultSub = info.getSubscriptionId(); 383 break; 384 } 385 } 386 } 387 return defaultSub; 388 } 389 } 390 391