1 /* 2 * Copyright (C) 2021 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.phone; 18 19 import static android.telephony.ims.ImsRcsManager.CAPABILITY_TYPE_OPTIONS_UCE; 20 import static android.telephony.ims.ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE; 21 import static android.telephony.ims.ProvisioningManager.KEY_EAB_PROVISIONING_STATUS; 22 import static android.telephony.ims.ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE; 23 import static android.telephony.ims.ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS; 24 import static android.telephony.ims.ProvisioningManager.KEY_VT_PROVISIONING_STATUS; 25 import static android.telephony.ims.ProvisioningManager.PROVISIONING_VALUE_DISABLED; 26 import static android.telephony.ims.ProvisioningManager.PROVISIONING_VALUE_ENABLED; 27 import static android.telephony.ims.feature.ImsFeature.FEATURE_MMTEL; 28 import static android.telephony.ims.feature.ImsFeature.FEATURE_RCS; 29 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER; 30 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS; 31 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT; 32 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO; 33 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE; 34 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM; 35 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; 36 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; 37 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_MAX; 38 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; 39 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR; 40 41 import android.annotation.Nullable; 42 import android.content.Context; 43 import android.os.AsyncResult; 44 import android.os.Binder; 45 import android.os.Handler; 46 import android.os.HandlerThread; 47 import android.os.Looper; 48 import android.os.Message; 49 import android.os.PersistableBundle; 50 import android.os.RemoteCallbackList; 51 import android.os.RemoteException; 52 import android.telephony.AnomalyReporter; 53 import android.telephony.CarrierConfigManager; 54 import android.telephony.CarrierConfigManager.Ims; 55 import android.telephony.SubscriptionManager; 56 import android.telephony.TelephonyManager; 57 import android.telephony.TelephonyRegistryManager; 58 import android.telephony.ims.ProvisioningManager; 59 import android.telephony.ims.aidl.IFeatureProvisioningCallback; 60 import android.telephony.ims.aidl.IImsConfig; 61 import android.telephony.ims.aidl.IImsConfigCallback; 62 import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities; 63 import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities; 64 import android.telephony.ims.stub.ImsConfigImplBase; 65 import android.telephony.ims.stub.ImsRegistrationImplBase; 66 import android.util.SparseArray; 67 68 import com.android.ims.FeatureConnector; 69 import com.android.ims.ImsConfig; 70 import com.android.ims.ImsException; 71 import com.android.ims.ImsManager; 72 import com.android.ims.RcsFeatureManager; 73 import com.android.internal.annotations.VisibleForTesting; 74 import com.android.internal.telephony.PhoneConfigurationManager; 75 import com.android.internal.telephony.flags.FeatureFlags; 76 import com.android.internal.telephony.util.HandlerExecutor; 77 import com.android.telephony.Rlog; 78 79 import java.util.Arrays; 80 import java.util.Map; 81 import java.util.UUID; 82 import java.util.concurrent.Executor; 83 84 /** 85 * Provides APIs for MMTEL and RCS provisioning status. This class handles provisioning status and 86 * notifies the status changing for each capability 87 * {{@link MmTelCapabilities.MmTelCapability} for MMTel services} 88 * {{@link RcsImsCapabilities.RcsImsCapabilityFlag} for RCS services} 89 */ 90 public class ImsProvisioningController { 91 private static final String TAG = "ImsProvisioningController"; 92 private static final int INVALID_VALUE = -1; 93 94 private static final int EVENT_SUB_CHANGED = 1; 95 private static final int EVENT_PROVISIONING_CAPABILITY_CHANGED = 2; 96 @VisibleForTesting 97 protected static final int EVENT_MULTI_SIM_CONFIGURATION_CHANGE = 3; 98 private static final int EVENT_PROVISIONING_VALUE_CHANGED = 4; 99 private static final int EVENT_NOTIFY_INIT_PROVISIONED_VALUE = 5; 100 101 // Provisioning Keys that are handled via AOSP cache and not sent to the ImsService 102 private static final int[] LOCAL_IMS_CONFIG_KEYS = { 103 KEY_VOLTE_PROVISIONING_STATUS, 104 KEY_VT_PROVISIONING_STATUS, 105 KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, 106 KEY_EAB_PROVISIONING_STATUS 107 }; 108 private static final int[] LOCAL_RADIO_TECHS = { 109 REGISTRATION_TECH_LTE, 110 REGISTRATION_TECH_IWLAN, 111 REGISTRATION_TECH_CROSS_SIM, 112 REGISTRATION_TECH_NR 113 }; 114 115 private static final int MMTEL_CAPABILITY_MIN = MmTelCapabilities.CAPABILITY_TYPE_NONE; 116 private static final int MMTEL_CAPABILITY_MAX = MmTelCapabilities.CAPABILITY_TYPE_MAX; 117 118 private static final int RCS_CAPABILITY_MIN = RcsImsCapabilities.CAPABILITY_TYPE_NONE; 119 private static final int RCS_CAPABILITY_MAX = RcsImsCapabilities.CAPABILITY_TYPE_MAX; 120 121 private static final int[] LOCAL_MMTEL_CAPABILITY = { 122 CAPABILITY_TYPE_VOICE, 123 CAPABILITY_TYPE_VIDEO, 124 CAPABILITY_TYPE_UT, 125 CAPABILITY_TYPE_SMS, 126 CAPABILITY_TYPE_CALL_COMPOSER 127 }; 128 129 private static final int[] LOCAL_RCS_CAPABILITY = { 130 CAPABILITY_TYPE_OPTIONS_UCE, 131 CAPABILITY_TYPE_PRESENCE_UCE 132 }; 133 134 /** 135 * map the MmTelCapabilities.MmTelCapability and 136 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VOICE_INT 137 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VIDEO_INT 138 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_UT_INT 139 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_SMS_INT 140 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT 141 */ 142 private static final Map<Integer, String> KEYS_MMTEL_CAPABILITY = Map.of( 143 CAPABILITY_TYPE_VOICE, Ims.KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY, 144 CAPABILITY_TYPE_VIDEO, Ims.KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY, 145 CAPABILITY_TYPE_UT, Ims.KEY_CAPABILITY_TYPE_UT_INT_ARRAY, 146 CAPABILITY_TYPE_SMS, Ims.KEY_CAPABILITY_TYPE_SMS_INT_ARRAY, 147 CAPABILITY_TYPE_CALL_COMPOSER, Ims.KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY 148 ); 149 150 /** 151 * map the RcsImsCapabilities.RcsImsCapabilityFlag and 152 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_OPTIONS_UCE 153 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE 154 */ 155 private static final Map<Integer, String> KEYS_RCS_CAPABILITY = Map.of( 156 CAPABILITY_TYPE_OPTIONS_UCE, Ims.KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY, 157 CAPABILITY_TYPE_PRESENCE_UCE, Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY 158 ); 159 160 private static final UUID VOLTE_PROVISIONING_ANOMALY = 161 UUID.fromString("f5f90e4d-3d73-4f63-a0f9-cbe1941ca57c"); 162 private static final String VOLTE_PROVISIONING_ANOMALY_DESC = "VoLTE is Not Provisioned"; 163 164 /** 165 * Create a FeatureConnector for this class to use to connect to an ImsManager. 166 */ 167 @VisibleForTesting 168 public interface MmTelFeatureConnector { 169 /** 170 * Create a FeatureConnector for this class to use to connect to an ImsManager. 171 * @param listener will receive ImsManager instance. 172 * @param executor that the Listener callbacks will be called on. 173 * @return A FeatureConnector 174 */ create(Context context, int slotId, String logPrefix, FeatureConnector.Listener<ImsManager> listener, Executor executor)175 FeatureConnector<ImsManager> create(Context context, int slotId, 176 String logPrefix, FeatureConnector.Listener<ImsManager> listener, 177 Executor executor); 178 } 179 180 /** 181 * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager. 182 */ 183 @VisibleForTesting 184 public interface RcsFeatureConnector { 185 /** 186 * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager. 187 * @param listener will receive RcsFeatureManager instance. 188 * @param executor that the Listener callbacks will be called on. 189 * @return A FeatureConnector 190 */ create(Context context, int slotId, FeatureConnector.Listener<RcsFeatureManager> listener, Executor executor, String logPrefix)191 FeatureConnector<RcsFeatureManager> create(Context context, int slotId, 192 FeatureConnector.Listener<RcsFeatureManager> listener, 193 Executor executor, String logPrefix); 194 } 195 196 private static ImsProvisioningController sInstance; 197 198 private final PhoneGlobals mApp; 199 private final Handler mHandler; 200 private final CarrierConfigManager mCarrierConfigManager; 201 private final SubscriptionManager mSubscriptionManager; 202 private final TelephonyRegistryManager mTelephonyRegistryManager; 203 private final MmTelFeatureConnector mMmTelFeatureConnector; 204 private final RcsFeatureConnector mRcsFeatureConnector; 205 206 // maps a slotId to a list of MmTelFeatureListeners 207 private final SparseArray<MmTelFeatureListener> mMmTelFeatureListenersSlotMap = 208 new SparseArray<>(); 209 // maps a slotId to a list of RcsFeatureListeners 210 private final SparseArray<RcsFeatureListener> mRcsFeatureListenersSlotMap = 211 new SparseArray<>(); 212 // map a slotId to a list of ProvisioningCallbackManager 213 private final SparseArray<ProvisioningCallbackManager> mProvisioningCallbackManagersSlotMap = 214 new SparseArray<>(); 215 private final ImsProvisioningLoader mImsProvisioningLoader; 216 private final FeatureFlags mFeatureFlags; 217 218 private int mNumSlot; 219 220 /** 221 * This class contains the provisioning status to notify changes. 222 * {{@link MmTelCapabilities.MmTelCapability} for MMTel services} 223 * {{@link android.telephony.ims.ImsRcsManager.RcsImsCapabilityFlag} for RCS services} 224 * {{@link ImsRegistrationImplBase.ImsRegistrationTech} for Registration tech} 225 */ 226 private static final class FeatureProvisioningData { 227 public final int mCapability; 228 public final int mTech; 229 public final boolean mProvisioned; 230 public final boolean mIsMmTel; 231 FeatureProvisioningData(int capability, int tech, boolean provisioned, boolean isMmTel)232 FeatureProvisioningData(int capability, int tech, boolean provisioned, boolean isMmTel) { 233 mCapability = capability; 234 mTech = tech; 235 mProvisioned = provisioned; 236 mIsMmTel = isMmTel; 237 } 238 } 239 240 private final class MessageHandler extends Handler { 241 private static final String LOG_PREFIX = "Handler"; MessageHandler(Looper looper)242 MessageHandler(Looper looper) { 243 super(looper); 244 } 245 246 @Override handleMessage(Message msg)247 public void handleMessage(Message msg) { 248 switch (msg.what) { 249 case EVENT_SUB_CHANGED: 250 onSubscriptionsChanged(); 251 break; 252 case EVENT_PROVISIONING_CAPABILITY_CHANGED: 253 try { 254 mProvisioningCallbackManagersSlotMap.get(msg.arg1) 255 .notifyProvisioningCapabilityChanged( 256 (FeatureProvisioningData) msg.obj); 257 } catch (NullPointerException e) { 258 logw(LOG_PREFIX, msg.arg1, 259 "can not find callback manager, message" + msg.what); 260 } 261 break; 262 case EVENT_MULTI_SIM_CONFIGURATION_CHANGE: 263 int activeModemCount = (int) ((AsyncResult) msg.obj).result; 264 onMultiSimConfigChanged(activeModemCount); 265 break; 266 case EVENT_PROVISIONING_VALUE_CHANGED: 267 logAttr("ImsConfig", "EVENT_PROVISIONING_VALUE_CHANGED", msg.arg1, 268 "changed provisioning value, item : " + msg.arg2 269 + " value : " + (int) msg.obj); 270 updateCapabilityTechFromKey("ImsConfig[" + msg.arg1 + "]", 271 msg.arg1, msg.arg2, (int) msg.obj); 272 break; 273 case EVENT_NOTIFY_INIT_PROVISIONED_VALUE: 274 int slotId = msg.arg1; 275 int subId = msg.arg2; 276 IFeatureProvisioningCallback callback = 277 (IFeatureProvisioningCallback) msg.obj; 278 log("slotId " + slotId + " subId " + subId 279 + " callback " + (callback != null)); 280 281 // Notify MmTel Provisioning Status 282 notifyMmTelProvisioningStatus(slotId, subId, callback); 283 notifyRcsProvisioningStatus(slotId, subId, callback); 284 break; 285 default: 286 log("unknown message " + msg); 287 break; 288 } 289 } 290 } 291 292 private final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener = 293 new SubscriptionManager.OnSubscriptionsChangedListener() { 294 @Override 295 public void onSubscriptionsChanged() { 296 if (!mHandler.hasMessages(EVENT_SUB_CHANGED)) { 297 mHandler.sendEmptyMessage(EVENT_SUB_CHANGED); 298 } 299 } 300 }; 301 302 private final class ProvisioningCallbackManager { 303 private static final String LOG_PREFIX = "ProvisioningCallbackManager"; 304 private RemoteCallbackList<IFeatureProvisioningCallback> mIFeatureProvisioningCallbackList; 305 private int mSubId; 306 private int mSlotId; 307 ProvisioningCallbackManager(int slotId)308 ProvisioningCallbackManager(int slotId) { 309 mIFeatureProvisioningCallbackList = 310 new RemoteCallbackList<IFeatureProvisioningCallback>(); 311 mSlotId = slotId; 312 mSubId = getSubId(slotId); 313 log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager create"); 314 } 315 clear()316 public void clear() { 317 log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager clear "); 318 319 mIFeatureProvisioningCallbackList.kill(); 320 321 // All registered callbacks are unregistered, and the list is disabled 322 // need to create again 323 mIFeatureProvisioningCallbackList = 324 new RemoteCallbackList<IFeatureProvisioningCallback>(); 325 } 326 registerCallback(IFeatureProvisioningCallback localCallback)327 public void registerCallback(IFeatureProvisioningCallback localCallback) { 328 if (!mIFeatureProvisioningCallbackList.register(localCallback, (Object) mSubId)) { 329 log(LOG_PREFIX, mSlotId, "registration callback fail"); 330 } 331 } 332 unregisterCallback(IFeatureProvisioningCallback localCallback)333 public void unregisterCallback(IFeatureProvisioningCallback localCallback) { 334 mIFeatureProvisioningCallbackList.unregister(localCallback); 335 } 336 setSubId(int subId)337 public void setSubId(int subId) { 338 if (mSubId == subId) { 339 log(LOG_PREFIX, mSlotId, "subId is not changed "); 340 return; 341 } 342 343 mSubId = subId; 344 mSlotId = getSlotId(subId); 345 346 // subId changed means the registered callbacks are not available. 347 clear(); 348 } 349 hasCallblacks()350 public boolean hasCallblacks() { 351 int size = mIFeatureProvisioningCallbackList.beginBroadcast(); 352 mIFeatureProvisioningCallbackList.finishBroadcast(); 353 354 return (size > 0); 355 } 356 notifyProvisioningCapabilityChanged(FeatureProvisioningData data)357 public void notifyProvisioningCapabilityChanged(FeatureProvisioningData data) { 358 int size = mIFeatureProvisioningCallbackList.beginBroadcast(); 359 for (int index = 0; index < size; index++) { 360 try { 361 IFeatureProvisioningCallback imsFeatureProvisioningCallback = 362 mIFeatureProvisioningCallbackList.getBroadcastItem(index); 363 364 // MMTEL 365 if (data.mIsMmTel 366 && Arrays.stream(LOCAL_MMTEL_CAPABILITY) 367 .anyMatch(value -> value == data.mCapability)) { 368 imsFeatureProvisioningCallback.onFeatureProvisioningChanged( 369 data.mCapability, data.mTech, data.mProvisioned); 370 logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : " 371 + "onFeatureProvisioningChanged" 372 + " capability " + data.mCapability 373 + " tech " + data.mTech 374 + " isProvisioned " + data.mProvisioned); 375 } else if (data.mCapability == CAPABILITY_TYPE_PRESENCE_UCE) { 376 imsFeatureProvisioningCallback.onRcsFeatureProvisioningChanged( 377 data.mCapability, data.mTech, data.mProvisioned); 378 logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : " 379 + "onRcsFeatureProvisioningChanged" 380 + " capability " + data.mCapability 381 + " tech " + data.mTech 382 + " isProvisioned " + data.mProvisioned); 383 } else { 384 loge(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : " 385 + "unknown capability " 386 + data.mCapability); 387 } 388 } catch (RemoteException e) { 389 loge(LOG_PREFIX, mSlotId, 390 "notifyProvisioningChanged: callback #" + index + " failed"); 391 } 392 } 393 mIFeatureProvisioningCallbackList.finishBroadcast(); 394 } 395 } 396 397 private final class MmTelFeatureListener implements FeatureConnector.Listener<ImsManager> { 398 private static final String LOG_PREFIX = "MmTelFeatureListener"; 399 private FeatureConnector<ImsManager> mConnector; 400 private ImsManager mImsManager; 401 private boolean mReady = false; 402 // stores whether the initial provisioning key value should be notified to ImsService 403 private boolean mRequiredNotify = false; 404 private int mSubId; 405 private int mSlotId; 406 private ConfigCallback mConfigCallback; 407 MmTelFeatureListener(int slotId)408 MmTelFeatureListener(int slotId) { 409 log(LOG_PREFIX, slotId, "created"); 410 411 mSlotId = slotId; 412 mSubId = getSubId(slotId); 413 mConfigCallback = new ConfigCallback(mSubId); 414 415 mConnector = mMmTelFeatureConnector.create( 416 mApp, slotId, TAG, this, new HandlerExecutor(mHandler)); 417 mConnector.connect(); 418 } 419 setSubId(int subId)420 public void setSubId(int subId) { 421 if (mRequiredNotify && mReady) { 422 mRequiredNotify = false; 423 setInitialProvisioningKeys(subId); 424 } 425 if (mSubId == subId) { 426 log(LOG_PREFIX, mSlotId, "subId is not changed"); 427 return; 428 } 429 430 mSubId = subId; 431 mConfigCallback.setSubId(subId); 432 } 433 destroy()434 public void destroy() { 435 log("destroy"); 436 if (mImsManager != null) { 437 try { 438 ImsConfig imsConfig = getImsConfig(mImsManager); 439 if (imsConfig != null) { 440 imsConfig.removeConfigCallback(mConfigCallback); 441 } 442 } catch (ImsException e) { 443 logw(LOG_PREFIX, mSlotId, "destroy : " + e.getMessage()); 444 } 445 } 446 mConfigCallback = null; 447 mConnector.disconnect(); 448 mConnector = null; 449 mReady = false; 450 mImsManager = null; 451 } 452 getImsManager()453 public @Nullable ImsManager getImsManager() { 454 return mImsManager; 455 } 456 457 @Override connectionReady(ImsManager manager, int subId)458 public void connectionReady(ImsManager manager, int subId) { 459 log(LOG_PREFIX, mSlotId, "connection ready"); 460 mReady = true; 461 mImsManager = manager; 462 463 if (mImsManager != null) { 464 try { 465 ImsConfig imsConfig = getImsConfig(mImsManager); 466 if (imsConfig != null) { 467 imsConfig.addConfigCallback(mConfigCallback); 468 } 469 } catch (ImsException e) { 470 logw(LOG_PREFIX, mSlotId, "addConfigCallback : " + e.getMessage()); 471 } 472 } 473 474 onMmTelAvailable(); 475 } 476 477 @Override connectionUnavailable(int reason)478 public void connectionUnavailable(int reason) { 479 log(LOG_PREFIX, mSlotId, "connection unavailable " + reason); 480 481 mReady = false; 482 mImsManager = null; 483 484 // keep the callback for other reason 485 if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) { 486 onMmTelUnavailable(); 487 } 488 } 489 setProvisioningValue(int key, int value)490 public int setProvisioningValue(int key, int value) { 491 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED; 492 493 if (!mReady) { 494 loge(LOG_PREFIX, mSlotId, "service is Unavailable"); 495 return retVal; 496 } 497 try { 498 // getConfigInterface() will return not null or throw the ImsException 499 // need not null checking 500 ImsConfig imsConfig = getImsConfig(mImsManager); 501 retVal = imsConfig.setConfig(key, value); 502 log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value); 503 } catch (ImsException e) { 504 logw(LOG_PREFIX, mSlotId, 505 "setConfig operation failed for key =" + key 506 + ", value =" + value + ". Exception:" + e.getMessage()); 507 } 508 return retVal; 509 } 510 getProvisioningValue(int key)511 public int getProvisioningValue(int key) { 512 if (!mReady) { 513 loge(LOG_PREFIX, mSlotId, "service is Unavailable"); 514 return INVALID_VALUE; 515 } 516 517 int retValue = INVALID_VALUE; 518 try { 519 // getConfigInterface() will return not null or throw the ImsException 520 // need not null checking 521 ImsConfig imsConfig = getImsConfig(mImsManager); 522 retValue = imsConfig.getConfigInt(key); 523 } catch (ImsException e) { 524 logw(LOG_PREFIX, mSlotId, 525 "getConfig operation failed for key =" + key 526 + ", value =" + retValue + ". Exception:" + e.getMessage()); 527 } 528 return retValue; 529 } 530 onMmTelAvailable()531 public void onMmTelAvailable() { 532 log(LOG_PREFIX, mSlotId, "onMmTelAvailable"); 533 534 if (isValidSubId(mSubId)) { 535 mRequiredNotify = false; 536 537 // notify provisioning key value to ImsService 538 setInitialProvisioningKeys(mSubId); 539 540 if (mFeatureFlags.notifyInitialImsProvisioningStatus()) { 541 // Notify MmTel provisioning value based on capability and radio tech. 542 ProvisioningCallbackManager p = 543 mProvisioningCallbackManagersSlotMap.get(mSlotId); 544 if (p != null && p.hasCallblacks()) { 545 notifyMmTelProvisioningStatus(mSlotId, mSubId, null); 546 } 547 } 548 } else { 549 // wait until subId is valid 550 mRequiredNotify = true; 551 } 552 } 553 onMmTelUnavailable()554 public void onMmTelUnavailable() { 555 log(LOG_PREFIX, mSlotId, "onMmTelUnavailable"); 556 557 try { 558 // delete all callbacks reference from ProvisioningManager 559 mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear(); 560 } catch (NullPointerException e) { 561 logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear"); 562 } 563 } 564 setInitialProvisioningKeys(int subId)565 private void setInitialProvisioningKeys(int subId) { 566 boolean required; 567 int value = ImsProvisioningLoader.STATUS_NOT_SET; 568 569 // updating KEY_VOLTE_PROVISIONING_STATUS 570 try { 571 required = isImsProvisioningRequiredForCapability(subId, CAPABILITY_TYPE_VOICE, 572 REGISTRATION_TECH_LTE); 573 } catch (IllegalArgumentException e) { 574 logw("setInitialProvisioningKeys: KEY_VOLTE_PROVISIONING_STATUS failed for" 575 + " subId=" + subId + ", exception: " + e.getMessage()); 576 return; 577 } 578 579 log(LOG_PREFIX, mSlotId, 580 "setInitialProvisioningKeys provisioning required(voice, lte) " + required); 581 if (required) { 582 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL, 583 CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE); 584 if (value != ImsProvisioningLoader.STATUS_NOT_SET) { 585 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED) 586 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED; 587 setProvisioningValue(KEY_VOLTE_PROVISIONING_STATUS, value); 588 } 589 } 590 591 // updating KEY_VT_PROVISIONING_STATUS 592 try { 593 required = isImsProvisioningRequiredForCapability(subId, CAPABILITY_TYPE_VIDEO, 594 REGISTRATION_TECH_LTE); 595 } catch (IllegalArgumentException e) { 596 logw("setInitialProvisioningKeys: KEY_VT_PROVISIONING_STATUS failed for" 597 + " subId=" + subId + ", exception: " + e.getMessage()); 598 return; 599 } 600 601 log(LOG_PREFIX, mSlotId, 602 "setInitialProvisioningKeys provisioning required(video, lte) " + required); 603 if (required) { 604 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL, 605 CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE); 606 if (value != ImsProvisioningLoader.STATUS_NOT_SET) { 607 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED) 608 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED; 609 setProvisioningValue(KEY_VT_PROVISIONING_STATUS, value); 610 } 611 } 612 613 // updating KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE 614 try { 615 required = isImsProvisioningRequiredForCapability(subId, CAPABILITY_TYPE_VOICE, 616 REGISTRATION_TECH_IWLAN); 617 } catch (IllegalArgumentException e) { 618 logw("setInitialProvisioningKeys: KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE failed" 619 + " for subId=" + subId + ", exception: " + e.getMessage()); 620 return; 621 } 622 623 log(LOG_PREFIX, mSlotId, 624 "setInitialProvisioningKeys provisioning required(voice, iwlan) " + required); 625 if (required) { 626 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL, 627 CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_IWLAN); 628 if (value != ImsProvisioningLoader.STATUS_NOT_SET) { 629 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED) 630 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED; 631 setProvisioningValue(KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, value); 632 } 633 } 634 } 635 } 636 637 private final class RcsFeatureListener implements FeatureConnector.Listener<RcsFeatureManager> { 638 private static final String LOG_PREFIX = "RcsFeatureListener"; 639 private FeatureConnector<RcsFeatureManager> mConnector; 640 private RcsFeatureManager mRcsFeatureManager; 641 private boolean mReady = false; 642 // stores whether the initial provisioning key value should be notified to ImsService 643 private boolean mRequiredNotify = false; 644 private int mSubId; 645 private int mSlotId; 646 private ConfigCallback mConfigCallback; 647 RcsFeatureListener(int slotId)648 RcsFeatureListener(int slotId) { 649 log(LOG_PREFIX, slotId, "created"); 650 651 mSlotId = slotId; 652 mSubId = getSubId(slotId); 653 mConfigCallback = new ConfigCallback(mSubId); 654 655 mConnector = mRcsFeatureConnector.create( 656 mApp, slotId, this, new HandlerExecutor(mHandler), TAG); 657 mConnector.connect(); 658 } 659 setSubId(int subId)660 public void setSubId(int subId) { 661 if (mRequiredNotify && mReady) { 662 mRequiredNotify = false; 663 setInitialProvisioningKeys(subId); 664 } 665 if (mSubId == subId) { 666 log(LOG_PREFIX, mSlotId, "subId is not changed"); 667 return; 668 } 669 670 mSubId = subId; 671 mConfigCallback.setSubId(subId); 672 } 673 destroy()674 public void destroy() { 675 log(LOG_PREFIX, mSlotId, "destroy"); 676 if (mRcsFeatureManager != null) { 677 try { 678 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig()); 679 if (imsConfig != null) { 680 imsConfig.removeConfigCallback(mConfigCallback); 681 } 682 } catch (ImsException e) { 683 logw(LOG_PREFIX, mSlotId, "destroy :" + e.getMessage()); 684 } 685 } 686 mConfigCallback = null; 687 mConnector.disconnect(); 688 mConnector = null; 689 mReady = false; 690 mRcsFeatureManager = null; 691 } 692 693 @Override connectionReady(RcsFeatureManager manager, int subId)694 public void connectionReady(RcsFeatureManager manager, int subId) { 695 log(LOG_PREFIX, mSlotId, "connection ready"); 696 mReady = true; 697 mRcsFeatureManager = manager; 698 699 if (mRcsFeatureManager != null) { 700 try { 701 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig()); 702 if (imsConfig != null) { 703 imsConfig.addConfigCallback(mConfigCallback); 704 } 705 } catch (ImsException e) { 706 logw(LOG_PREFIX, mSlotId, "addConfigCallback :" + e.getMessage()); 707 } 708 } 709 710 onRcsAvailable(); 711 } 712 713 @Override connectionUnavailable(int reason)714 public void connectionUnavailable(int reason) { 715 log(LOG_PREFIX, mSlotId, "connection unavailable"); 716 mReady = false; 717 mRcsFeatureManager = null; 718 719 // keep the callback for other reason 720 if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) { 721 onRcsUnavailable(); 722 } 723 } 724 setProvisioningValue(int key, int value)725 public int setProvisioningValue(int key, int value) { 726 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED; 727 728 if (!mReady) { 729 loge(LOG_PREFIX, mSlotId, "service is Unavailable"); 730 return retVal; 731 } 732 733 try { 734 // getConfigInterface() will return not null or throw the ImsException 735 // need not null checking 736 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig()); 737 retVal = imsConfig.setConfig(key, value); 738 log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value); 739 } catch (ImsException e) { 740 logw(LOG_PREFIX, mSlotId, 741 "setConfig operation failed for key =" + key 742 + ", value =" + value + ". Exception:" + e.getMessage()); 743 } 744 return retVal; 745 } 746 getProvisioningValue(int key)747 public int getProvisioningValue(int key) { 748 if (!mReady) { 749 loge(LOG_PREFIX, mSlotId, "service is Unavailable"); 750 return INVALID_VALUE; 751 } 752 753 int retValue = INVALID_VALUE; 754 try { 755 // getConfigInterface() will return not null or throw the ImsException 756 // need not null checking 757 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig()); 758 retValue = imsConfig.getConfigInt(key); 759 } catch (ImsException e) { 760 logw(LOG_PREFIX, mSlotId, 761 "getConfig operation failed for key =" + key 762 + ", value =" + retValue + ". Exception:" + e.getMessage()); 763 } 764 return retValue; 765 } 766 isConnectionReady()767 public boolean isConnectionReady() { 768 return mReady; 769 } 770 onRcsAvailable()771 public void onRcsAvailable() { 772 log(LOG_PREFIX, mSlotId, "onRcsAvailable"); 773 774 if (isValidSubId(mSubId)) { 775 mRequiredNotify = false; 776 777 // notify provisioning key value to ImsService 778 setInitialProvisioningKeys(mSubId); 779 780 if (mFeatureFlags.notifyInitialImsProvisioningStatus()) { 781 ProvisioningCallbackManager p = 782 mProvisioningCallbackManagersSlotMap.get(mSlotId); 783 if (p != null && p.hasCallblacks()) { 784 // Notify RCS provisioning value based on capability and radio tech. 785 notifyRcsProvisioningStatus(mSlotId, mSubId, null); 786 } 787 } 788 } else { 789 // wait until subId is valid 790 mRequiredNotify = true; 791 } 792 } 793 onRcsUnavailable()794 public void onRcsUnavailable() { 795 log(LOG_PREFIX, mSlotId, "onRcsUnavailable"); 796 797 try { 798 // delete all callbacks reference from ProvisioningManager 799 mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear(); 800 } catch (NullPointerException e) { 801 logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear"); 802 } 803 } 804 setInitialProvisioningKeys(int subId)805 private void setInitialProvisioningKeys(int subId) { 806 boolean required; 807 int value = ImsProvisioningLoader.STATUS_NOT_SET; 808 809 // KEY_EAB_PROVISIONING_STATUS 810 int capability = CAPABILITY_TYPE_PRESENCE_UCE; 811 // Assume that all radio techs have the same provisioning value 812 int tech = REGISTRATION_TECH_LTE; 813 814 try { 815 required = isRcsProvisioningRequiredForCapability(subId, capability, tech); 816 } catch (IllegalArgumentException e) { 817 logw("setInitialProvisioningKeys: KEY_EAB_PROVISIONING_STATUS failed for" 818 + " subId=" + subId + ", exception: " + e.getMessage()); 819 return; 820 } 821 822 if (required) { 823 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS, 824 capability, tech); 825 if (value != ImsProvisioningLoader.STATUS_NOT_SET) { 826 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED) 827 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED; 828 setProvisioningValue(KEY_EAB_PROVISIONING_STATUS, value); 829 } 830 } 831 } 832 } 833 834 // When vendor ImsService changed provisioning data, which should be updated in AOSP. 835 // Catch the event using IImsConfigCallback. 836 private final class ConfigCallback extends IImsConfigCallback.Stub { 837 private int mSubId; 838 ConfigCallback(int subId)839 ConfigCallback(int subId) { 840 mSubId = subId; 841 } 842 setSubId(int subId)843 public void setSubId(int subId) { 844 mSubId = subId; 845 } 846 847 @Override onIntConfigChanged(int item, int value)848 public void onIntConfigChanged(int item, int value) throws RemoteException { 849 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == item)) { 850 return; 851 } 852 853 final long callingIdentity = Binder.clearCallingIdentity(); 854 try { 855 if (mHandler != null) { 856 mHandler.sendMessage(mHandler.obtainMessage( 857 EVENT_PROVISIONING_VALUE_CHANGED, mSubId, item, (Object) value)); 858 } 859 } finally { 860 Binder.restoreCallingIdentity(callingIdentity); 861 } 862 } 863 864 @Override onStringConfigChanged(int item, String value)865 public void onStringConfigChanged(int item, String value) throws RemoteException { 866 // Ignore this callback. 867 } 868 } 869 870 /** 871 * Do NOT use this directly, instead use {@link #getInstance()}. 872 */ 873 @VisibleForTesting ImsProvisioningController(PhoneGlobals app, int numSlot, Looper looper, MmTelFeatureConnector mmTelFeatureConnector, RcsFeatureConnector rcsFeatureConnector, ImsProvisioningLoader imsProvisioningLoader, FeatureFlags featureFlags)874 public ImsProvisioningController(PhoneGlobals app, int numSlot, Looper looper, 875 MmTelFeatureConnector mmTelFeatureConnector, RcsFeatureConnector rcsFeatureConnector, 876 ImsProvisioningLoader imsProvisioningLoader, FeatureFlags featureFlags) { 877 log("ImsProvisioningController"); 878 mApp = app; 879 mNumSlot = numSlot; 880 mHandler = new MessageHandler(looper); 881 mMmTelFeatureConnector = mmTelFeatureConnector; 882 mRcsFeatureConnector = rcsFeatureConnector; 883 mCarrierConfigManager = mApp.getSystemService(CarrierConfigManager.class); 884 mSubscriptionManager = mApp.getSystemService(SubscriptionManager.class); 885 mTelephonyRegistryManager = mApp.getSystemService(TelephonyRegistryManager.class); 886 mTelephonyRegistryManager.addOnSubscriptionsChangedListener( 887 mSubChangedListener, mHandler::post); 888 mImsProvisioningLoader = imsProvisioningLoader; 889 mFeatureFlags = featureFlags; 890 891 PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler, 892 EVENT_MULTI_SIM_CONFIGURATION_CHANGE, null); 893 894 initialize(numSlot); 895 } 896 initialize(int numSlot)897 private void initialize(int numSlot) { 898 for (int i = 0; i < numSlot; i++) { 899 MmTelFeatureListener m = new MmTelFeatureListener(i); 900 mMmTelFeatureListenersSlotMap.put(i, m); 901 902 RcsFeatureListener r = new RcsFeatureListener(i); 903 mRcsFeatureListenersSlotMap.put(i, r); 904 905 ProvisioningCallbackManager p = new ProvisioningCallbackManager(i); 906 mProvisioningCallbackManagersSlotMap.put(i, p); 907 } 908 } 909 onMultiSimConfigChanged(int newNumSlot)910 private void onMultiSimConfigChanged(int newNumSlot) { 911 log("onMultiSimConfigChanged: NumSlot " + mNumSlot + " newNumSlot " + newNumSlot); 912 913 if (mNumSlot < newNumSlot) { 914 for (int i = mNumSlot; i < newNumSlot; i++) { 915 MmTelFeatureListener m = new MmTelFeatureListener(i); 916 mMmTelFeatureListenersSlotMap.put(i, m); 917 918 RcsFeatureListener r = new RcsFeatureListener(i); 919 mRcsFeatureListenersSlotMap.put(i, r); 920 921 ProvisioningCallbackManager p = new ProvisioningCallbackManager(i); 922 mProvisioningCallbackManagersSlotMap.put(i, p); 923 } 924 } else if (mNumSlot > newNumSlot) { 925 for (int i = (mNumSlot - 1); i > (newNumSlot - 1); i--) { 926 MmTelFeatureListener m = mMmTelFeatureListenersSlotMap.get(i); 927 mMmTelFeatureListenersSlotMap.remove(i); 928 m.destroy(); 929 930 RcsFeatureListener r = mRcsFeatureListenersSlotMap.get(i); 931 mRcsFeatureListenersSlotMap.remove(i); 932 r.destroy(); 933 934 ProvisioningCallbackManager p = mProvisioningCallbackManagersSlotMap.get(i); 935 mProvisioningCallbackManagersSlotMap.remove(i); 936 p.clear(); 937 } 938 } 939 940 mNumSlot = newNumSlot; 941 } 942 943 /** 944 * destroy the instance 945 */ 946 @VisibleForTesting destroy()947 public void destroy() { 948 log("destroy"); 949 950 mHandler.getLooper().quit(); 951 952 mTelephonyRegistryManager.removeOnSubscriptionsChangedListener(mSubChangedListener); 953 954 for (int i = 0; i < mMmTelFeatureListenersSlotMap.size(); i++) { 955 mMmTelFeatureListenersSlotMap.get(i).destroy(); 956 } 957 mMmTelFeatureListenersSlotMap.clear(); 958 959 for (int i = 0; i < mRcsFeatureListenersSlotMap.size(); i++) { 960 mRcsFeatureListenersSlotMap.get(i).destroy(); 961 } 962 mRcsFeatureListenersSlotMap.clear(); 963 964 for (int i = 0; i < mProvisioningCallbackManagersSlotMap.size(); i++) { 965 mProvisioningCallbackManagersSlotMap.get(i).clear(); 966 } 967 } 968 969 /** 970 * create an instance 971 */ 972 @VisibleForTesting make(PhoneGlobals app, int numSlot, FeatureFlags featureFlags)973 public static ImsProvisioningController make(PhoneGlobals app, int numSlot, 974 FeatureFlags featureFlags) { 975 synchronized (ImsProvisioningController.class) { 976 if (sInstance == null) { 977 Rlog.i(TAG, "ImsProvisioningController created"); 978 HandlerThread handlerThread = new HandlerThread(TAG); 979 handlerThread.start(); 980 sInstance = new ImsProvisioningController(app, numSlot, handlerThread.getLooper(), 981 ImsManager::getConnector, RcsFeatureManager::getConnector, 982 new ImsProvisioningLoader(app), featureFlags); 983 } 984 } 985 return sInstance; 986 } 987 988 /** 989 * Gets a ImsProvisioningController instance 990 */ 991 @VisibleForTesting getInstance()992 public static ImsProvisioningController getInstance() { 993 synchronized (ImsProvisioningController.class) { 994 return sInstance; 995 } 996 } 997 998 /** 999 * Register IFeatureProvisioningCallback from ProvisioningManager 1000 */ 1001 1002 @VisibleForTesting addFeatureProvisioningChangedCallback(int subId, IFeatureProvisioningCallback callback)1003 public void addFeatureProvisioningChangedCallback(int subId, 1004 IFeatureProvisioningCallback callback) { 1005 if (callback == null) { 1006 throw new IllegalArgumentException("provisioning callback can't be null"); 1007 } 1008 int slotId = getSlotId(subId); 1009 if (slotId < 0 || slotId >= mNumSlot) { 1010 throw new IllegalArgumentException("subscription id is not available"); 1011 } 1012 1013 try { 1014 mProvisioningCallbackManagersSlotMap.get(slotId).registerCallback(callback); 1015 log("Feature Provisioning Callback registered."); 1016 1017 if (mFeatureFlags.notifyInitialImsProvisioningStatus()) { 1018 mHandler.sendMessage(mHandler.obtainMessage(EVENT_NOTIFY_INIT_PROVISIONED_VALUE, 1019 getSlotId(subId), subId, (Object) callback)); 1020 } 1021 } catch (NullPointerException e) { 1022 logw("can not access callback manager to add callback"); 1023 } 1024 } 1025 1026 /** 1027 * Remove IFeatureProvisioningCallback 1028 */ 1029 @VisibleForTesting removeFeatureProvisioningChangedCallback(int subId, IFeatureProvisioningCallback callback)1030 public void removeFeatureProvisioningChangedCallback(int subId, 1031 IFeatureProvisioningCallback callback) { 1032 if (callback == null) { 1033 throw new IllegalArgumentException("provisioning callback can't be null"); 1034 } 1035 1036 int slotId = getSlotId(subId); 1037 if (slotId < 0 || slotId >= mNumSlot) { 1038 throw new IllegalArgumentException("subscription id is not available"); 1039 } 1040 1041 try { 1042 mProvisioningCallbackManagersSlotMap.get(slotId).unregisterCallback(callback); 1043 log("Feature Provisioning Callback removed."); 1044 } catch (NullPointerException e) { 1045 logw("can not access callback manager to remove callback"); 1046 } 1047 } 1048 1049 /** 1050 * return the boolean whether MmTel capability is required provisioning or not 1051 */ 1052 @VisibleForTesting isImsProvisioningRequiredForCapability(int subId, int capability, int tech)1053 public boolean isImsProvisioningRequiredForCapability(int subId, int capability, int tech) { 1054 // check subId 1055 int slotId = getSlotId(subId); 1056 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) { 1057 loge("Fail to retrieve slotId from subId"); 1058 throw new IllegalArgumentException("subscribe id is invalid"); 1059 } 1060 1061 // check valid capability 1062 if (!(MMTEL_CAPABILITY_MIN < capability && capability < MMTEL_CAPABILITY_MAX)) { 1063 throw new IllegalArgumentException("MmTel capability '" + capability + "' is invalid"); 1064 } 1065 1066 // check valid radio tech 1067 if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) { 1068 log("Ims not matched radio tech " + tech); 1069 throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid"); 1070 } 1071 1072 // check new carrier config first KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE 1073 boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/true); 1074 1075 // if that returns false, check deprecated carrier config 1076 // KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL 1077 if (!retVal && (capability == CAPABILITY_TYPE_VOICE 1078 || capability == CAPABILITY_TYPE_VIDEO 1079 || capability == CAPABILITY_TYPE_UT)) { 1080 String key = CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL; 1081 if (capability == CAPABILITY_TYPE_UT) { 1082 key = CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL; 1083 } 1084 1085 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); 1086 if (imsCarrierConfigs != null) { 1087 retVal = imsCarrierConfigs.getBoolean(key); 1088 } else { 1089 retVal = CarrierConfigManager.getDefaultConfig().getBoolean(key); 1090 } 1091 } 1092 1093 log("isImsProvisioningRequiredForCapability capability " + capability 1094 + " tech " + tech + " return value " + retVal); 1095 1096 return retVal; 1097 } 1098 1099 /** 1100 * return the boolean whether RCS capability is required provisioning or not 1101 */ 1102 @VisibleForTesting isRcsProvisioningRequiredForCapability(int subId, int capability, int tech)1103 public boolean isRcsProvisioningRequiredForCapability(int subId, int capability, int tech) { 1104 // check slotId and Phone object 1105 int slotId = getSlotId(subId); 1106 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) { 1107 loge("Fail to retrieve slotId from subId"); 1108 throw new IllegalArgumentException("subscribe id is invalid"); 1109 } 1110 1111 // check valid capability 1112 if (!(RCS_CAPABILITY_MIN < capability && capability < RCS_CAPABILITY_MAX)) { 1113 throw new IllegalArgumentException("Rcs capability '" + capability + "' is invalid"); 1114 } 1115 1116 // check valid radio tech 1117 if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) { 1118 log("Rcs not matched radio tech " + tech); 1119 throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid"); 1120 } 1121 1122 // check new carrier config first KEY_RCS_REQUIRES_PROVISIONING_BUNDLE 1123 boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/false); 1124 1125 // if that returns false, check deprecated carrier config 1126 // KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL 1127 if (!retVal) { 1128 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); 1129 if (imsCarrierConfigs != null) { 1130 retVal = imsCarrierConfigs.getBoolean( 1131 CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL); 1132 } else { 1133 retVal = CarrierConfigManager.getDefaultConfig().getBoolean( 1134 CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL); 1135 } 1136 } 1137 1138 log("isRcsProvisioningRequiredForCapability capability " + capability 1139 + " tech " + tech + " return value " + retVal); 1140 1141 return retVal; 1142 } 1143 1144 /** 1145 * return the provisioning status for MmTel capability in specific radio tech 1146 */ 1147 @VisibleForTesting getImsProvisioningStatusForCapability(String attributionPackage, int subId, int capability, int tech)1148 public boolean getImsProvisioningStatusForCapability(String attributionPackage, int subId, 1149 int capability, int tech) { 1150 boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech); 1151 if (!mmTelProvisioned) { // provisioning not required 1152 logAttr(attributionPackage, "getImsProvisioningStatusForCapability", subId, 1153 " not required, capability " + capability + " tech " + tech); 1154 return true; 1155 } 1156 1157 // read value from ImsProvisioningLoader 1158 int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL, 1159 capability, tech); 1160 if (result == ImsProvisioningLoader.STATUS_NOT_SET) { 1161 // not set means initial value 1162 // read data from vendor ImsService and store that in ImsProvisioningLoader 1163 result = getValueFromImsService(subId, capability, tech); 1164 mmTelProvisioned = getBoolValue(result); 1165 if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) { 1166 setAndNotifyMmTelProvisioningValue(attributionPackage, subId, capability, tech, 1167 mmTelProvisioned); 1168 } 1169 } else { 1170 mmTelProvisioned = getBoolValue(result); 1171 } 1172 1173 logAttr(attributionPackage, "getImsProvisioningStatusForCapability", subId, 1174 " capability " + capability 1175 + " tech " + tech 1176 + " result " + mmTelProvisioned); 1177 return mmTelProvisioned; 1178 } 1179 1180 /** 1181 * set MmTel provisioning status in specific tech 1182 */ 1183 @VisibleForTesting setImsProvisioningStatusForCapability(String attributionPackage, int subId, int capability, int tech, boolean isProvisioned)1184 public void setImsProvisioningStatusForCapability(String attributionPackage, int subId, 1185 int capability, int tech, boolean isProvisioned) { 1186 boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech); 1187 if (!mmTelProvisioned) { // provisioning not required 1188 logAttr(attributionPackage, "setImsProvisioningStatusForCapability", subId, 1189 "not required, capability " + capability + " tech " + tech); 1190 return; 1191 } 1192 1193 // write value to ImsProvisioningLoader 1194 boolean isChanged = setAndNotifyMmTelProvisioningValue(attributionPackage, subId, 1195 capability, tech, isProvisioned); 1196 if (!isChanged) { 1197 logAttr(attributionPackage, "setImsProvisioningStatusForCapability", subId, 1198 "status not changed, capability " + capability + " tech " + tech); 1199 return; 1200 } 1201 1202 int slotId = getSlotId(subId); 1203 // find matched key from capability and tech 1204 int value = getIntValue(isProvisioned); 1205 int key = getKeyFromCapability(capability, tech); 1206 if (key != INVALID_VALUE) { 1207 logAttr(attributionPackage, "setImsProvisioningStatusForCapability", subId, 1208 "matched key " + key); 1209 try { 1210 // set key and value to vendor ImsService for MmTel 1211 mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value); 1212 } catch (NullPointerException e) { 1213 loge("can not access MmTelFeatureListener with capability " + capability); 1214 } 1215 } 1216 } 1217 1218 /** 1219 * return the provisioning status for RCS capability in specific radio tech 1220 */ 1221 @VisibleForTesting getRcsProvisioningStatusForCapability(int subId, int capability, int tech)1222 public boolean getRcsProvisioningStatusForCapability(int subId, int capability, int tech) { 1223 boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech); 1224 if (!rcsProvisioned) { // provisioning not required 1225 log("getRcsProvisioningStatusForCapability : not required" 1226 + " capability " + capability + " tech " + tech); 1227 return true; 1228 } 1229 1230 // read data from ImsProvisioningLoader 1231 int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS, 1232 capability, tech); 1233 if (result == ImsProvisioningLoader.STATUS_NOT_SET) { 1234 // not set means initial value 1235 // read data from vendor ImsService and store that in ImsProvisioningLoader 1236 result = getRcsValueFromImsService(subId, capability); 1237 rcsProvisioned = getBoolValue(result); 1238 if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) { 1239 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, rcsProvisioned); 1240 } 1241 } else { 1242 rcsProvisioned = getBoolValue(result); 1243 } 1244 1245 log("getRcsProvisioningStatusForCapability : " 1246 + " capability " + capability 1247 + " tech " + tech 1248 + " result " + rcsProvisioned); 1249 return rcsProvisioned; 1250 } 1251 1252 /** 1253 * set RCS provisioning status in specific tech 1254 */ 1255 @VisibleForTesting setRcsProvisioningStatusForCapability(int subId, int capability, int tech, boolean isProvisioned)1256 public void setRcsProvisioningStatusForCapability(int subId, int capability, int tech, 1257 boolean isProvisioned) { 1258 boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech); 1259 if (!rcsProvisioned) { // provisioning not required 1260 log("set rcs provisioning status but not required"); 1261 return; 1262 } 1263 1264 // write status using ImsProvisioningLoader 1265 boolean isChanged = setAndNotifyRcsProvisioningValue(subId, capability, tech, 1266 isProvisioned); 1267 if (!isChanged) { 1268 log("status not changed rcs capability " + capability + " tech " + tech); 1269 return; 1270 } 1271 1272 int slotId = getSlotId(subId); 1273 int key = ProvisioningManager.KEY_EAB_PROVISIONING_STATUS; 1274 int value = getIntValue(isProvisioned); 1275 try { 1276 // On some older devices, EAB is managed on the MmTel ImsService when the RCS 1277 // ImsService is not configured. If there is no RCS ImsService defined, fallback to 1278 // MmTel. In the rare case that we hit a race condition where the RCS ImsService has 1279 // crashed or has not come up yet, the value will be synchronized via 1280 // setInitialProvisioningKeys(). 1281 if (mRcsFeatureListenersSlotMap.get(slotId).isConnectionReady()) { 1282 mRcsFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value); 1283 } 1284 1285 // EAB provisioning status should be updated to both the Rcs and MmTel ImsService, 1286 // because the provisioning callback is listening to only MmTel provisioning key 1287 // changes. 1288 mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value); 1289 } catch (NullPointerException e) { 1290 loge("can not access RcsFeatureListener with capability " + capability); 1291 } 1292 } 1293 1294 /** 1295 * set RCS provisioning status in specific key and value 1296 * @param key integer key, defined as one of 1297 * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS} 1298 * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS} 1299 * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE} 1300 * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS} 1301 * @param value in Integer format. 1302 * @return the result of setting the configuration value, defined as one of 1303 * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or 1304 * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or 1305 */ 1306 @VisibleForTesting setProvisioningValue(String attributionPackage, int subId, int key, int value)1307 public int setProvisioningValue(String attributionPackage, int subId, int key, int value) { 1308 logAttr(attributionPackage, "setProvisioningValue", subId, key + ": " + value); 1309 1310 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED; 1311 // check key value 1312 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) { 1313 logAttr(attributionPackage, "setProvisioningValue", subId, 1314 "not matched key " + key); 1315 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN; 1316 } 1317 1318 // check subId 1319 int slotId = getSlotId(subId); 1320 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) { 1321 logAttrE(attributionPackage, "setProvisioningValue", subId, 1322 "Fail to retrieve slotId from subId"); 1323 return ImsConfigImplBase.CONFIG_RESULT_FAILED; 1324 } 1325 1326 try { 1327 // set key and value to vendor ImsService for MmTel 1328 // EAB provisioning status should be updated to both the Rcs and MmTel ImsService, 1329 // because the provisioning callback is listening to only MmTel provisioning key 1330 // changes. 1331 retVal = mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value); 1332 1333 // If the Rcs ImsService is not available, the EAB provisioning status will be written 1334 // to the MmTel ImsService for backwards compatibility. In the rare case that this is 1335 // hit due to RCS ImsService temporarily unavailable, the value will be synchronized 1336 // via setInitialProvisioningKeys() when the RCS ImsService comes back up. 1337 if (key == KEY_EAB_PROVISIONING_STATUS 1338 && mRcsFeatureListenersSlotMap.get(slotId).isConnectionReady()) { 1339 // set key and value to vendor ImsService for RCS and use retVal from RCS if 1340 // related to EAB when possible. 1341 retVal = mRcsFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value); 1342 } 1343 } catch (NullPointerException e) { 1344 logAttrE(attributionPackage, "setProvisioningValue", subId, 1345 "can not access FeatureListener to set provisioning value"); 1346 return ImsConfigImplBase.CONFIG_RESULT_FAILED; 1347 } 1348 1349 // update and notify provisioning status changed capability and tech from key 1350 updateCapabilityTechFromKey(attributionPackage, subId, key, value); 1351 1352 return retVal; 1353 } 1354 1355 /** 1356 * get RCS provisioning status in specific key and value 1357 * @param key integer key, defined as one of 1358 * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS} 1359 * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS} 1360 * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE} 1361 * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS} 1362 * @return the result of setting the configuration value, defined as one of 1363 * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or 1364 * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or 1365 * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN} 1366 */ 1367 @VisibleForTesting getProvisioningValue(String attributionPackage, int subId, int key)1368 public int getProvisioningValue(String attributionPackage, int subId, int key) { 1369 // check key value 1370 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) { 1371 logAttr(attributionPackage, "getProvisioningValue", subId, 1372 "not matched key " + key); 1373 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN; 1374 } 1375 1376 // check subId 1377 int slotId = getSlotId(subId); 1378 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) { 1379 logAttrE(attributionPackage, "getProvisioningValue", subId, 1380 "Fail to retrieve slotId from subId"); 1381 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN; 1382 } 1383 1384 // check data from ImsProvisioningLoader 1385 int capability = getCapabilityFromKey(key); 1386 int tech = getTechFromKey(key); 1387 int result; 1388 if (capability != INVALID_VALUE && tech != INVALID_VALUE) { 1389 if (key == KEY_EAB_PROVISIONING_STATUS) { 1390 result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS, 1391 capability, tech); 1392 } else { 1393 result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL, 1394 capability, tech); 1395 } 1396 if (result != ImsProvisioningLoader.STATUS_NOT_SET) { 1397 logAttr(attributionPackage, "getProvisioningValue", subId, 1398 "cache hit : key=" + key + ": value=" + result); 1399 return result; 1400 } 1401 } 1402 1403 // get data from ImsService, update it in ImsProvisioningLoader 1404 if (key == KEY_EAB_PROVISIONING_STATUS) { 1405 result = getRcsValueFromImsService(subId, capability); 1406 if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) { 1407 logAttrW(attributionPackage, "getProvisioningValue", subId, 1408 "fail to get data from ImsService, capability=" + capability); 1409 return result; 1410 } 1411 logAttr(attributionPackage, "getProvisioningValue", subId, 1412 "cache miss, get from RCS - key=" + key + ": value=" + result); 1413 1414 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, getBoolValue(result)); 1415 return result; 1416 } else { 1417 result = getValueFromImsService(subId, capability, tech); 1418 if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) { 1419 logAttrW(attributionPackage, "getProvisioningValue", subId, 1420 "fail to get data from ImsService, capability=" + capability); 1421 return result; 1422 } 1423 logAttr(attributionPackage, "getProvisioningValue", subId, 1424 "cache miss, get from MMTEL - key=" + key + ": value=" + result); 1425 1426 setAndNotifyMmTelProvisioningValue(attributionPackage, subId, capability, tech, 1427 getBoolValue(result)); 1428 return result; 1429 } 1430 } 1431 1432 /** 1433 * get the handler 1434 */ 1435 @VisibleForTesting getHandler()1436 public Handler getHandler() { 1437 return mHandler; 1438 } 1439 isProvisioningRequired(int subId, int capability, int tech, boolean isMmTel)1440 private boolean isProvisioningRequired(int subId, int capability, int tech, boolean isMmTel) { 1441 int[] techArray; 1442 techArray = getTechsFromCarrierConfig(subId, capability, isMmTel); 1443 if (techArray == null) { 1444 logw("isProvisioningRequired : getTechsFromCarrierConfig failed"); 1445 // not exist in CarrierConfig that means provisioning is not required 1446 return false; 1447 } 1448 1449 // compare with carrier config 1450 if (Arrays.stream(techArray).anyMatch(keyValue -> keyValue == tech)) { 1451 // existing same tech means provisioning required 1452 return true; 1453 } 1454 1455 log("isProvisioningRequired : not matched capability " + capability + " tech " + tech); 1456 return false; 1457 } 1458 getTechsFromCarrierConfig(int subId, int capability, boolean isMmTel)1459 private int[] getTechsFromCarrierConfig(int subId, int capability, boolean isMmTel) { 1460 String featureKey; 1461 String capabilityKey; 1462 if (isMmTel) { 1463 featureKey = CarrierConfigManager.Ims.KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE; 1464 capabilityKey = KEYS_MMTEL_CAPABILITY.get(capability); 1465 } else { 1466 featureKey = CarrierConfigManager.Ims.KEY_RCS_REQUIRES_PROVISIONING_BUNDLE; 1467 capabilityKey = KEYS_RCS_CAPABILITY.get(capability); 1468 } 1469 1470 if (capabilityKey != null) { 1471 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); 1472 if (imsCarrierConfigs == null) { 1473 log("getTechsFromCarrierConfig : imsCarrierConfigs null"); 1474 return null; 1475 } 1476 1477 PersistableBundle provisioningBundle = 1478 imsCarrierConfigs.getPersistableBundle(featureKey); 1479 if (provisioningBundle == null) { 1480 log("getTechsFromCarrierConfig : provisioningBundle null"); 1481 return null; 1482 } 1483 1484 return provisioningBundle.getIntArray(capabilityKey); 1485 } 1486 1487 return null; 1488 } 1489 getValueFromImsService(int subId, int capability, int tech)1490 private int getValueFromImsService(int subId, int capability, int tech) { 1491 int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN; 1492 1493 // operation is based on capability 1494 switch (capability) { 1495 case CAPABILITY_TYPE_VOICE: 1496 int item = (tech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) 1497 ? ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE 1498 : ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS; 1499 // read data from vendor ImsService 1500 config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId)) 1501 .getProvisioningValue(item); 1502 break; 1503 case CAPABILITY_TYPE_VIDEO: 1504 // read data from vendor ImsService 1505 config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId)) 1506 .getProvisioningValue(ProvisioningManager.KEY_VT_PROVISIONING_STATUS); 1507 break; 1508 default: 1509 log("Capability " + capability + " has been provisioning"); 1510 break; 1511 } 1512 1513 return config; 1514 } 1515 getRcsValueFromImsService(int subId, int capability)1516 private int getRcsValueFromImsService(int subId, int capability) { 1517 int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN; 1518 int slotId = getSlotId(subId); 1519 1520 if (capability != CAPABILITY_TYPE_PRESENCE_UCE) { 1521 log("Capability " + capability + " has been provisioning"); 1522 return config; 1523 } 1524 try { 1525 if (mRcsFeatureListenersSlotMap.get(slotId).isConnectionReady()) { 1526 config = mRcsFeatureListenersSlotMap.get(slotId) 1527 .getProvisioningValue(ProvisioningManager.KEY_EAB_PROVISIONING_STATUS); 1528 } else { 1529 log("Rcs ImsService is not available, " 1530 + "EAB provisioning status should be read from MmTel ImsService"); 1531 config = mMmTelFeatureListenersSlotMap.get(slotId) 1532 .getProvisioningValue(ProvisioningManager.KEY_EAB_PROVISIONING_STATUS); 1533 } 1534 } catch (NullPointerException e) { 1535 logw("can not access FeatureListener : " + e.getMessage()); 1536 } 1537 1538 return config; 1539 } 1540 onSubscriptionsChanged()1541 private void onSubscriptionsChanged() { 1542 for (int index = 0; index < mMmTelFeatureListenersSlotMap.size(); index++) { 1543 MmTelFeatureListener m = mMmTelFeatureListenersSlotMap.get(index); 1544 m.setSubId(getSubId(index)); 1545 } 1546 for (int index = 0; index < mRcsFeatureListenersSlotMap.size(); index++) { 1547 RcsFeatureListener r = mRcsFeatureListenersSlotMap.get(index); 1548 r.setSubId(getSubId(index)); 1549 } 1550 for (int index = 0; index < mProvisioningCallbackManagersSlotMap.size(); index++) { 1551 ProvisioningCallbackManager m = mProvisioningCallbackManagersSlotMap.get(index); 1552 m.setSubId(getSubId(index)); 1553 } 1554 } 1555 updateCapabilityTechFromKey(String attributionPackage, int subId, int key, int value)1556 private void updateCapabilityTechFromKey(String attributionPackage, int subId, int key, 1557 int value) { 1558 boolean isProvisioned = getBoolValue(value); 1559 int capability = getCapabilityFromKey(key); 1560 int tech = getTechFromKey(key); 1561 1562 if (capability == INVALID_VALUE || tech == INVALID_VALUE) { 1563 logAttrW(attributionPackage, "updateCapabilityTechFromKey", subId, 1564 "unknown key " + key); 1565 return; 1566 } 1567 1568 if (key == KEY_VOLTE_PROVISIONING_STATUS 1569 || key == KEY_VT_PROVISIONING_STATUS 1570 || key == KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE) { 1571 setAndNotifyMmTelProvisioningValue(attributionPackage, subId, capability, tech, 1572 isProvisioned); 1573 } 1574 if (key == KEY_EAB_PROVISIONING_STATUS) { 1575 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, isProvisioned); 1576 } 1577 } 1578 getCapabilityFromKey(int key)1579 private int getCapabilityFromKey(int key) { 1580 int capability; 1581 switch (key) { 1582 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS: 1583 // intentional fallthrough 1584 case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE: 1585 capability = CAPABILITY_TYPE_VOICE; 1586 break; 1587 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS: 1588 capability = CAPABILITY_TYPE_VIDEO; 1589 break; 1590 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS: 1591 // default CAPABILITY_TYPE_PRESENCE_UCE used for KEY_EAB_PROVISIONING_STATUS 1592 capability = CAPABILITY_TYPE_PRESENCE_UCE; 1593 break; 1594 default: 1595 capability = INVALID_VALUE; 1596 break; 1597 } 1598 return capability; 1599 } 1600 getTechFromKey(int key)1601 private int getTechFromKey(int key) { 1602 int tech; 1603 switch (key) { 1604 case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE: 1605 tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; 1606 break; 1607 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS: 1608 // intentional fallthrough 1609 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS: 1610 // intentional fallthrough 1611 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS: 1612 tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE; 1613 break; 1614 default: 1615 tech = INVALID_VALUE; 1616 break; 1617 } 1618 return tech; 1619 } 1620 getKeyFromCapability(int capability, int tech)1621 private int getKeyFromCapability(int capability, int tech) { 1622 int key = INVALID_VALUE; 1623 if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_IWLAN) { 1624 key = ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE; 1625 } else if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_LTE) { 1626 key = ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS; 1627 } else if (capability == CAPABILITY_TYPE_VIDEO && tech == REGISTRATION_TECH_LTE) { 1628 key = ProvisioningManager.KEY_VT_PROVISIONING_STATUS; 1629 } 1630 1631 return key; 1632 } 1633 getSubId(int slotId)1634 protected int getSubId(int slotId) { 1635 return SubscriptionManager.getSubscriptionId(slotId); 1636 } 1637 getSlotId(int subId)1638 protected int getSlotId(int subId) { 1639 return mSubscriptionManager.getPhoneId(subId); 1640 } 1641 getImsConfig(ImsManager imsManager)1642 protected ImsConfig getImsConfig(ImsManager imsManager) throws ImsException { 1643 return imsManager.getConfigInterface(); 1644 } 1645 getImsConfig(IImsConfig iImsConfig)1646 protected ImsConfig getImsConfig(IImsConfig iImsConfig) { 1647 return new ImsConfig(iImsConfig); 1648 } 1649 getIntValue(boolean isProvisioned)1650 private int getIntValue(boolean isProvisioned) { 1651 return isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED 1652 : ProvisioningManager.PROVISIONING_VALUE_DISABLED; 1653 } 1654 getBoolValue(int value)1655 private boolean getBoolValue(int value) { 1656 return value == ProvisioningManager.PROVISIONING_VALUE_ENABLED ? true : false; 1657 } 1658 1659 // If VoLTE is not provisioned, generate an anomaly report as this is not expected. checkProvisioningValueForAnomaly(String attributionPackage, int subId, int capability, int tech, boolean isProvisioned)1660 private void checkProvisioningValueForAnomaly(String attributionPackage, int subId, 1661 int capability, int tech, boolean isProvisioned) { 1662 if (isProvisioned) return; 1663 boolean isVolte = capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_LTE; 1664 if (!isVolte) return; 1665 // We have hit the condition where VoLTE has been de-provisioned 1666 int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 1667 TelephonyManager manager = mApp.getSystemService(TelephonyManager.class); 1668 if (manager != null) { 1669 carrierId = manager.createForSubscriptionId(subId).getSimCarrierId(); 1670 } 1671 logAttrW(attributionPackage, "checkProvisioningValueForAnomaly", subId, 1672 "VoLTE provisioning disabled"); 1673 AnomalyReporter.reportAnomaly(VOLTE_PROVISIONING_ANOMALY, 1674 VOLTE_PROVISIONING_ANOMALY_DESC, carrierId); 1675 } 1676 setAndNotifyMmTelProvisioningValue(String attributionPackage, int subId, int capability, int tech, boolean isProvisioned)1677 private boolean setAndNotifyMmTelProvisioningValue(String attributionPackage, int subId, 1678 int capability, int tech, 1679 boolean isProvisioned) { 1680 boolean changed = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_MMTEL, 1681 capability, tech, isProvisioned); 1682 // notify MmTel capability changed 1683 if (changed) { 1684 checkProvisioningValueForAnomaly(attributionPackage, subId, capability, tech, 1685 isProvisioned); 1686 mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED, 1687 getSlotId(subId), 0, (Object) new FeatureProvisioningData( 1688 capability, tech, isProvisioned, /*isMmTel*/true))); 1689 } 1690 1691 return changed; 1692 } 1693 setAndNotifyRcsProvisioningValue(int subId, int capability, int tech, boolean isProvisioned)1694 private boolean setAndNotifyRcsProvisioningValue(int subId, int capability, int tech, 1695 boolean isProvisioned) { 1696 boolean isChanged = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_RCS, 1697 capability, tech, isProvisioned); 1698 1699 if (isChanged) { 1700 int slotId = getSlotId(subId); 1701 1702 // notify RCS capability changed 1703 mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED, 1704 slotId, 0, (Object) new FeatureProvisioningData( 1705 capability, tech, isProvisioned, /*isMmtel*/false))); 1706 } 1707 1708 return isChanged; 1709 } 1710 setAndNotifyRcsProvisioningValueForAllTech(int subId, int capability, boolean isProvisioned)1711 private boolean setAndNotifyRcsProvisioningValueForAllTech(int subId, int capability, 1712 boolean isProvisioned) { 1713 boolean isChanged = false; 1714 1715 for (int tech : LOCAL_RADIO_TECHS) { 1716 isChanged |= setAndNotifyRcsProvisioningValue(subId, capability, tech, isProvisioned); 1717 } 1718 1719 return isChanged; 1720 } 1721 isValidSubId(int subId)1722 protected boolean isValidSubId(int subId) { 1723 int slotId = getSlotId(subId); 1724 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) { 1725 return false; 1726 } 1727 1728 return true; 1729 } 1730 notifyMmTelProvisioningStatus(int slotId, int subId, @Nullable IFeatureProvisioningCallback callback)1731 private void notifyMmTelProvisioningStatus(int slotId, int subId, 1732 @Nullable IFeatureProvisioningCallback callback) { 1733 int value = ImsProvisioningLoader.STATUS_NOT_SET; 1734 int[] techArray; 1735 for (int capability : LOCAL_MMTEL_CAPABILITY) { 1736 techArray = getTechsFromCarrierConfig(subId, capability, /*isMmTle*/true); 1737 if (techArray == null) { 1738 continue; 1739 } 1740 1741 for (int radioTech : techArray) { 1742 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL, 1743 capability, radioTech); 1744 if (value == ImsProvisioningLoader.STATUS_NOT_SET) { 1745 // Not yet provisioned 1746 continue; 1747 } 1748 1749 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED) 1750 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED; 1751 1752 // Notify all registered callbacks 1753 if (callback == null) { 1754 mProvisioningCallbackManagersSlotMap.get(slotId) 1755 .notifyProvisioningCapabilityChanged( 1756 new FeatureProvisioningData( 1757 capability, 1758 radioTech, 1759 getBoolValue(value), 1760 /*isMmTle*/true)); 1761 } else { 1762 try { 1763 callback.onFeatureProvisioningChanged(capability, radioTech, 1764 getBoolValue(value)); 1765 } catch (RemoteException e) { 1766 logw("notifyMmTelProvisioningStatus callback is not available"); 1767 } 1768 } 1769 } 1770 } 1771 } 1772 notifyRcsProvisioningStatus(int slotId, int subId, @Nullable IFeatureProvisioningCallback callback)1773 private void notifyRcsProvisioningStatus(int slotId, int subId, 1774 @Nullable IFeatureProvisioningCallback callback) { 1775 int value = ImsProvisioningLoader.STATUS_NOT_SET; 1776 int[] techArray; 1777 for (int capability : LOCAL_RCS_CAPABILITY) { 1778 techArray = getTechsFromCarrierConfig(subId, capability, /*isMmTle*/false); 1779 if (techArray == null) { 1780 continue; 1781 } 1782 1783 for (int radioTech : techArray) { 1784 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS, 1785 capability, radioTech); 1786 if (value == ImsProvisioningLoader.STATUS_NOT_SET) { 1787 // Not yet provisioned 1788 continue; 1789 } 1790 1791 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED) 1792 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED; 1793 1794 // Notify all registered callbacks 1795 if (callback == null) { 1796 mProvisioningCallbackManagersSlotMap.get(slotId) 1797 .notifyProvisioningCapabilityChanged( 1798 new FeatureProvisioningData( 1799 capability, 1800 radioTech, 1801 getBoolValue(value), 1802 /*isMmTle*/false)); 1803 } else { 1804 try { 1805 callback.onRcsFeatureProvisioningChanged(capability, radioTech, 1806 getBoolValue(value)); 1807 } catch (RemoteException e) { 1808 logw("notifyRcsProvisioningStatus callback is not available"); 1809 } 1810 } 1811 } 1812 } 1813 } 1814 logAttr(String attr, String prefix, int subId, String log)1815 private void logAttr(String attr, String prefix, int subId, String log) { 1816 Rlog.d(TAG, prefix + "[" + subId + "]: " + log + ", attr = [" + attr + "]"); 1817 } 1818 logAttrW(String attr, String prefix, int subId, String log)1819 private void logAttrW(String attr, String prefix, int subId, String log) { 1820 Rlog.w(TAG, prefix + "[" + subId + "]: " + log + ", attr = [" + attr + "]"); 1821 } 1822 logAttrE(String attr, String prefix, int subId, String log)1823 private void logAttrE(String attr, String prefix, int subId, String log) { 1824 Rlog.e(TAG, prefix + "[" + subId + "]: " + log + ", attr = [" + attr + "]"); 1825 } 1826 log(String s)1827 private void log(String s) { 1828 Rlog.d(TAG, s); 1829 } 1830 log(String prefix, int slotId, String s)1831 private void log(String prefix, int slotId, String s) { 1832 Rlog.d(TAG, prefix + "[" + slotId + "] " + s); 1833 } 1834 logi(String prefix, int slotId, String s)1835 private void logi(String prefix, int slotId, String s) { 1836 Rlog.i(TAG, prefix + "[" + slotId + "] " + s); 1837 } 1838 logw(String s)1839 private void logw(String s) { 1840 Rlog.w(TAG, s); 1841 } 1842 logw(String prefix, int slotId, String s)1843 private void logw(String prefix, int slotId, String s) { 1844 Rlog.w(TAG, prefix + "[" + slotId + "] " + s); 1845 } 1846 loge(String s)1847 private void loge(String s) { 1848 Rlog.e(TAG, s); 1849 } 1850 loge(String prefix, int slotId, String s)1851 private void loge(String prefix, int slotId, String s) { 1852 Rlog.e(TAG, prefix + "[" + slotId + "] " + s); 1853 } 1854 } 1855