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