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