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