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 47 import java.util.List; 48 import java.util.concurrent.LinkedBlockingQueue; 49 import java.util.concurrent.TimeUnit; 50 51 public class RcsSettingUtils { 52 static private Logger logger = Logger.getLogger("RcsSettingUtils"); 53 private static final int TIMEOUT_GET_CONFIGURATION_MS = 5000; 54 55 // Default number of entries for getMaxNumbersInRCL 56 private static final int DEFAULT_NUM_ENTRIES_IN_RCL = 100; 57 // Default for getCapabPollListSubExp in seconds. 58 private static final int DEFAULT_CAPABILITY_POLL_LIST_SUB_EXPIRATION_SEC = 30; 59 // Default for getAvailabilityCacheExpiration in seconds. 60 private static final int DEFAULT_AVAILABILITY_CACHE_EXPIRATION_SEC = 30; 61 // Default for getPublishThrottle in milliseconds 62 private static final int DEFAULT_PUBLISH_THROTTLE_MS = 60000; 63 isVoLteProvisioned(int subId)64 public static boolean isVoLteProvisioned(int subId) { 65 try { 66 boolean isProvisioned; 67 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 68 isProvisioned = manager.getProvisioningStatusForCapability( 69 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 70 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 71 logger.debug("isVoLteProvisioned=" + isProvisioned); 72 return isProvisioned; 73 } catch (Exception e) { 74 logger.debug("isVoLteProvisioned, exception = " + e.getMessage()); 75 return false; 76 } 77 } 78 isVowifiProvisioned(int subId)79 public static boolean isVowifiProvisioned(int subId) { 80 try { 81 boolean isProvisioned; 82 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 83 isProvisioned = manager.getProvisioningStatusForCapability( 84 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 85 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 86 logger.debug("isVowifiProvisioned=" + isProvisioned); 87 return isProvisioned; 88 } catch (Exception e) { 89 logger.debug("isVowifiProvisioned, exception = " + e.getMessage()); 90 return false; 91 } 92 } 93 isLvcProvisioned(int subId)94 public static boolean isLvcProvisioned(int subId) { 95 try { 96 boolean isProvisioned; 97 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 98 isProvisioned = manager.getProvisioningStatusForCapability( 99 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 100 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 101 logger.debug("isLvcProvisioned=" + isProvisioned); 102 return isProvisioned; 103 } catch (Exception e) { 104 logger.debug("isLvcProvisioned, exception = " + e.getMessage()); 105 return false; 106 } 107 } 108 isEabProvisioned(Context context, int subId)109 public static boolean isEabProvisioned(Context context, int subId) { 110 boolean isProvisioned = false; 111 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 112 logger.debug("isEabProvisioned: no valid subscriptions!"); 113 return false; 114 } 115 CarrierConfigManager configManager = (CarrierConfigManager) 116 context.getSystemService(Context.CARRIER_CONFIG_SERVICE); 117 if (configManager != null) { 118 PersistableBundle config = configManager.getConfigForSubId(subId); 119 if (config != null && !config.getBoolean( 120 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONED_BOOL)) { 121 // If we don't need provisioning, just return true. 122 return true; 123 } 124 } 125 try { 126 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 127 isProvisioned = manager.getProvisioningIntValue( 128 ProvisioningManager.KEY_EAB_PROVISIONING_STATUS) 129 == ProvisioningManager.PROVISIONING_VALUE_ENABLED; 130 } catch (Exception e) { 131 logger.debug("isEabProvisioned: exception=" + e.getMessage()); 132 } 133 logger.debug("isEabProvisioned=" + isProvisioned); 134 return isProvisioned; 135 } 136 isPublishEnabled(Context context, int subId)137 public static boolean isPublishEnabled(Context context, int subId) { 138 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 139 logger.debug("isPublishEnabled: no valid subscriptions!"); 140 return false; 141 } 142 CarrierConfigManager configManager = (CarrierConfigManager) 143 context.getSystemService(Context.CARRIER_CONFIG_SERVICE); 144 if (configManager != null) { 145 PersistableBundle config = configManager.getConfigForSubId(subId); 146 return (config != null) && config.getBoolean( 147 CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false); 148 } 149 return false; 150 } 151 hasUserEnabledContactDiscovery(Context context, int subId)152 public static boolean hasUserEnabledContactDiscovery(Context context, int subId) { 153 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 154 logger.debug("hasUserEnabledContactDiscovery: no valid subscriptions!"); 155 return false; 156 } 157 try { 158 ImsManager imsManager = context.getSystemService(ImsManager.class); 159 ImsRcsManager rcsManager = imsManager.getImsRcsManager(subId); 160 return rcsManager.getUceAdapter().isUceSettingEnabled(); 161 } catch (Exception e) { 162 logger.warn("hasUserEnabledContactDiscovery: Exception = " + e.getMessage()); 163 return false; 164 } 165 } 166 getSIPT1Timer(int subId)167 public static int getSIPT1Timer(int subId) { 168 int sipT1Timer = 0; 169 try { 170 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 171 sipT1Timer = manager.getProvisioningIntValue(ProvisioningManager.KEY_T1_TIMER_VALUE_MS); 172 } catch (Exception e) { 173 // If there is no active subscriptions, this will throw an exception. 174 logger.debug("getSIPT1Timer: exception=" + e.getMessage()); 175 } 176 logger.debug("getSIPT1Timer=" + sipT1Timer); 177 return sipT1Timer; 178 } 179 180 /** 181 * Capability discovery status of Enabled (1), or Disabled (0). 182 */ getCapabilityDiscoveryEnabled(int subId)183 public static boolean getCapabilityDiscoveryEnabled(int subId) { 184 boolean capabilityDiscoveryEnabled = false; 185 try { 186 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 187 capabilityDiscoveryEnabled = manager.getProvisioningIntValue( 188 ProvisioningManager.KEY_RCS_CAPABILITY_DISCOVERY_ENABLED) == 189 ProvisioningManager.PROVISIONING_VALUE_ENABLED; 190 } catch (Exception e) { 191 // If there is no active subscriptions, this will throw an exception. 192 logger.debug("capabilityDiscoveryEnabled: exception=" + e.getMessage()); 193 } 194 logger.debug("capabilityDiscoveryEnabled=" + capabilityDiscoveryEnabled); 195 return capabilityDiscoveryEnabled; 196 } 197 198 /** 199 * The Maximum number of MDNs contained in one Request Contained List. 200 */ getMaxNumbersInRCL(int subId)201 public static int getMaxNumbersInRCL(int subId) { 202 int maxNumbersInRCL = DEFAULT_NUM_ENTRIES_IN_RCL; 203 try { 204 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 205 maxNumbersInRCL = manager.getProvisioningIntValue( 206 ProvisioningManager.KEY_RCS_MAX_NUM_ENTRIES_IN_RCL); 207 } catch (Exception e) { 208 // If there is no active subscriptions, this will throw an exception. 209 logger.debug("getMaxNumbersInRCL: exception=" + e.getMessage()); 210 } 211 logger.debug("getMaxNumbersInRCL=" + maxNumbersInRCL); 212 return maxNumbersInRCL; 213 } 214 215 /** 216 * Expiration timer for subscription of a Request Contained List, used in capability polling. 217 */ getCapabPollListSubExp(int subId)218 public static int getCapabPollListSubExp(int subId) { 219 int capabPollListSubExp = DEFAULT_CAPABILITY_POLL_LIST_SUB_EXPIRATION_SEC; 220 try { 221 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 222 capabPollListSubExp = manager.getProvisioningIntValue( 223 ProvisioningManager.KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC); 224 } catch (Exception e) { 225 // If there is no active subscriptions, this will throw an exception. 226 logger.debug("getCapabPollListSubExp: exception=" + e.getMessage()); 227 } 228 logger.debug("getCapabPollListSubExp=" + capabPollListSubExp); 229 return capabPollListSubExp; 230 } 231 232 /** 233 * Period of time the availability information of a contact is cached on device. 234 */ getAvailabilityCacheExpiration(int subId)235 public static int getAvailabilityCacheExpiration(int subId) { 236 int availabilityCacheExpiration = DEFAULT_AVAILABILITY_CACHE_EXPIRATION_SEC; 237 try { 238 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 239 availabilityCacheExpiration = manager.getProvisioningIntValue( 240 ProvisioningManager.KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC); 241 } catch (Exception e) { 242 // If there is no active subscriptions, this will throw an exception. 243 logger.debug("getAvailabilityCacheExpiration: exception=" + e.getMessage()); 244 } 245 logger.debug("getAvailabilityCacheExpiration=" + availabilityCacheExpiration); 246 return availabilityCacheExpiration; 247 } 248 getPublishThrottle(int subId)249 public static int getPublishThrottle(int subId) { 250 // Default 251 int publishThrottle = DEFAULT_PUBLISH_THROTTLE_MS; 252 try { 253 ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId); 254 publishThrottle = manager.getProvisioningIntValue( 255 ProvisioningManager.KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS); 256 } catch (Exception e) { 257 // If there is no active subscriptions, this will throw an exception. 258 logger.debug("publishThrottle: exception=" + e.getMessage()); 259 } 260 logger.debug("publishThrottle=" + publishThrottle); 261 return publishThrottle; 262 } 263 isVtEnabledByUser(int subId)264 public static boolean isVtEnabledByUser(int subId) { 265 try { 266 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 267 return mmTelManager.isVtSettingEnabled(); 268 } catch (Exception e) { 269 logger.warn("isVtEnabledByUser exception = " + e.getMessage()); 270 return false; 271 } 272 } 273 isWfcEnabledByUser(int subId)274 public static boolean isWfcEnabledByUser(int subId) { 275 try { 276 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 277 return mmTelManager.isVoWiFiSettingEnabled(); 278 } catch (Exception e) { 279 logger.warn("isWfcEnabledByUser exception = " + e.getMessage()); 280 return false; 281 } 282 } 283 isAdvancedCallingEnabledByUser(int subId)284 public static boolean isAdvancedCallingEnabledByUser(int subId) { 285 try { 286 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 287 return mmTelManager.isAdvancedCallingSettingEnabled(); 288 } catch (Exception e) { 289 logger.warn("isAdvancedCallingEnabledByUser exception = " + e.getMessage()); 290 return false; 291 } 292 } 293 isVoLteSupported(int subId)294 public static boolean isVoLteSupported(int subId) { 295 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 296 return false; 297 } 298 LinkedBlockingQueue<Boolean> resultQueue = new LinkedBlockingQueue<>(1); 299 try { 300 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 301 mmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 302 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, resultQueue::offer); 303 } catch (ImsException e) { 304 logger.warn("isVoLteSupported: ImsException = " + e.getMessage()); 305 return false; 306 } 307 try { 308 Boolean result = resultQueue.poll(TIMEOUT_GET_CONFIGURATION_MS, TimeUnit.MILLISECONDS); 309 return (result != null) ? result : false; 310 } catch (InterruptedException e) { 311 logger.warn("isVoLteSupported, InterruptedException=" + e.getMessage()); 312 return false; 313 } 314 } 315 isVoWiFiSupported(int subId)316 public static boolean isVoWiFiSupported(int subId) { 317 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 318 return false; 319 } 320 LinkedBlockingQueue<Boolean> resultQueue = new LinkedBlockingQueue<>(1); 321 try { 322 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 323 mmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 324 AccessNetworkConstants.TRANSPORT_TYPE_WLAN, Runnable::run, resultQueue::offer); 325 } catch (ImsException e) { 326 logger.warn("isVoWiFiSupported: ImsException = " + e.getMessage()); 327 return false; 328 } 329 try { 330 Boolean result = resultQueue.poll(TIMEOUT_GET_CONFIGURATION_MS, TimeUnit.MILLISECONDS); 331 return (result != null) ? result : false; 332 } catch (InterruptedException e) { 333 logger.warn("isVoWiFiSupported, InterruptedException=" + e.getMessage()); 334 return false; 335 } 336 } 337 isVtSupported(int subId)338 public static boolean isVtSupported(int subId) { 339 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 340 return false; 341 } 342 LinkedBlockingQueue<Boolean> resultQueue = new LinkedBlockingQueue<>(1); 343 try { 344 ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 345 mmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 346 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, resultQueue::offer); 347 } catch (ImsException e) { 348 logger.warn("isVoWiFiSupported: ImsException = " + e.getMessage()); 349 return false; 350 } 351 try { 352 Boolean result = resultQueue.poll(TIMEOUT_GET_CONFIGURATION_MS, TimeUnit.MILLISECONDS); 353 return (result != null) ? result : false; 354 } catch (InterruptedException e) { 355 logger.warn("isVtSupported, InterruptedException=" + e.getMessage()); 356 return false; 357 } 358 } 359 getDefaultSubscriptionId(Context context)360 public static int getDefaultSubscriptionId(Context context) { 361 SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); 362 if (sm == null) return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 363 List<SubscriptionInfo> infos = sm.getActiveSubscriptionInfoList(); 364 if (infos == null || infos.isEmpty()) { 365 // There are no active subscriptions right now. 366 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 367 } 368 // This code does not support MSIM unfortunately, so only provide presence on the default 369 // voice subscription that the user chose. 370 int defaultSub = SubscriptionManager.getDefaultVoiceSubscriptionId(); 371 if (!SubscriptionManager.isValidSubscriptionId(defaultSub)) { 372 // The voice sub may not have been specified, in this case, use the default data. 373 defaultSub = SubscriptionManager.getDefaultDataSubscriptionId(); 374 } 375 // If the user has no default set, just pick the first as backup. 376 if (!SubscriptionManager.isValidSubscriptionId(defaultSub)) { 377 for (SubscriptionInfo info : infos) { 378 if (!info.isOpportunistic()) { 379 defaultSub = info.getSubscriptionId(); 380 break; 381 } 382 } 383 } 384 return defaultSub; 385 } 386 } 387 388