1 /* 2 * Copyright (C) 2022 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 package com.android.telephony.qns; 17 18 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE; 19 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; 20 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; 21 22 import android.content.Context; 23 import android.content.pm.PackageManager; 24 import android.os.Handler; 25 import android.os.HandlerThread; 26 import android.os.PersistableBundle; 27 import android.os.SystemProperties; 28 import android.telephony.AccessNetworkConstants; 29 import android.telephony.CarrierConfigManager; 30 import android.telephony.SubscriptionManager; 31 import android.telephony.TelephonyManager; 32 import android.telephony.ims.ImsException; 33 import android.telephony.ims.ImsManager; 34 import android.telephony.ims.ImsMmTelManager; 35 import android.telephony.ims.ImsRcsManager; 36 import android.telephony.ims.ImsReasonInfo; 37 import android.telephony.ims.ImsRegistrationAttributes; 38 import android.telephony.ims.ImsStateCallback; 39 import android.telephony.ims.ProvisioningManager; 40 import android.telephony.ims.RegistrationManager; 41 import android.telephony.ims.SipDelegateManager; 42 import android.telephony.ims.SipDialogState; 43 import android.telephony.ims.SipDialogStateCallback; 44 import android.telephony.ims.feature.ImsFeature; 45 import android.util.Log; 46 47 import androidx.annotation.NonNull; 48 49 import com.android.internal.annotations.VisibleForTesting; 50 51 import java.util.List; 52 import java.util.concurrent.Executor; 53 import java.util.concurrent.Executors; 54 import java.util.concurrent.Semaphore; 55 import java.util.concurrent.TimeUnit; 56 import java.util.concurrent.atomic.AtomicInteger; 57 import java.util.function.Consumer; 58 59 /** 60 * QnsImsManager is helper class to get wi-fi calling related items from ImsManager 61 * 62 * @hide 63 */ 64 class QnsImsManager { 65 66 static final String PROP_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr"; 67 68 private static final int SYS_PROP_NOT_SET = -1; 69 70 private final String mLogTag; 71 private final Context mContext; 72 private final int mSlotId; 73 private final Executor mExecutor; 74 private final Handler mHandler; 75 private final HandlerThread mHandlerThread; 76 private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 77 private final SubscriptionManager mSubscriptionManager; 78 private boolean mQnsImsManagerInitialized; 79 private CarrierConfigManager mConfigManager; 80 private ImsManager mImsManager; 81 private ImsMmTelManager mImsMmTelManager; 82 private ImsRcsManager mImsRcsManager; 83 private SipDelegateManager mSipDelegateManager; 84 QnsImsStateCallback mMmTelStateCallback; 85 QnsImsStateCallback mRcsStateCallback; 86 QnsImsRegistrationCallback mMmtelImsRegistrationCallback; 87 QnsImsRegistrationCallback mRcsImsRegistrationCallback; 88 QnsSipDialogStateCallback mRcsSipDialogSessionStateCallback; 89 90 final QnsRegistrantList mMmTelImsStateListener; 91 final QnsRegistrantList mRcsImsStateListener; 92 final QnsRegistrantList mMmTelImsRegistrationListener; 93 final QnsRegistrantList mRcsImsRegistrationListener; 94 final QnsRegistrantList mRcsSipDialogSessionStateListener; 95 96 @VisibleForTesting 97 final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangeListener; 98 99 /** QnsImsManager default constructor */ QnsImsManager(Context context, int slotId)100 QnsImsManager(Context context, int slotId) { 101 mSlotId = slotId; 102 mLogTag = QnsImsManager.class.getSimpleName() + "_" + mSlotId; 103 mContext = context; 104 mExecutor = new QnsImsManagerExecutor(); 105 106 mHandlerThread = new HandlerThread(mLogTag); 107 mHandlerThread.start(); 108 mHandler = new Handler(mHandlerThread.getLooper()); 109 110 mMmTelImsStateListener = new QnsRegistrantList(); 111 mRcsImsStateListener = new QnsRegistrantList(); 112 mMmTelImsRegistrationListener = new QnsRegistrantList(); 113 mRcsImsRegistrationListener = new QnsRegistrantList(); 114 mRcsSipDialogSessionStateListener = new QnsRegistrantList(); 115 116 initQnsImsManager(); 117 118 mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); 119 mSubscriptionsChangeListener = new QnsSubscriptionsChangedListener(); 120 if (mSubscriptionManager != null) { 121 mSubscriptionManager.addOnSubscriptionsChangedListener( 122 new QnsUtils.QnsExecutor(mHandler), mSubscriptionsChangeListener); 123 } 124 } 125 126 class QnsSubscriptionsChangedListener 127 extends SubscriptionManager.OnSubscriptionsChangedListener { 128 129 /** 130 * Callback invoked when there is any change to any SubscriptionInfo. 131 */ 132 @Override onSubscriptionsChanged()133 public void onSubscriptionsChanged() { 134 int newSubId = QnsUtils.getSubId(mContext, mSlotId); 135 if (newSubId != mSubId) { 136 mSubId = newSubId; 137 if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 138 clearQnsImsManager(); 139 } else { 140 clearQnsImsManager(); 141 initQnsImsManager(); 142 } 143 } 144 } 145 } 146 147 @VisibleForTesting initQnsImsManager()148 protected synchronized void initQnsImsManager() { 149 if (mQnsImsManagerInitialized) { 150 return; 151 } 152 log("initQnsImsManager."); 153 154 if (mConfigManager == null) { 155 mConfigManager = mContext.getSystemService(CarrierConfigManager.class); 156 if (mConfigManager == null) { 157 loge("initQnsImsManager: couldn't initialize. failed to get CarrierConfigManager."); 158 clearQnsImsManager(); 159 return; 160 } 161 } 162 163 if (mImsManager == null) { 164 mImsManager = mContext.getSystemService(ImsManager.class); 165 if (mImsManager == null) { 166 loge("initQnsImsManager: couldn't initialize. failed to get ImsManager."); 167 clearQnsImsManager(); 168 return; 169 } 170 } 171 172 int subId = getSubId(); 173 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 174 return; 175 } 176 177 mImsMmTelManager = mImsManager.getImsMmTelManager(subId); 178 if (mImsMmTelManager == null) { 179 loge("initQnsImsManager: couldn't initialize. failed to get ImsMmTelManager."); 180 clearQnsImsManager(); 181 return; 182 } 183 184 mImsRcsManager = mImsManager.getImsRcsManager(subId); 185 if (mImsRcsManager == null) { 186 loge("initQnsImsManager: couldn't initialize. failed to get ImsRcsManager."); 187 clearQnsImsManager(); 188 return; 189 } 190 191 mSipDelegateManager = mImsManager.getSipDelegateManager(subId); 192 if (mSipDelegateManager == null) { 193 loge("initQnsImsManager: couldn't initialize. failed to get mSipDelegateManager."); 194 clearQnsImsManager(); 195 return; 196 } 197 198 mQnsImsManagerInitialized = true; 199 200 startTrackingImsState(ImsFeature.FEATURE_MMTEL); 201 startTrackingImsState(ImsFeature.FEATURE_RCS); 202 startTrackingImsRegistration(ImsFeature.FEATURE_MMTEL); 203 startTrackingImsRegistration(ImsFeature.FEATURE_RCS); 204 startTrackingSipDialogSessionState(ImsFeature.FEATURE_RCS); 205 } 206 207 @VisibleForTesting startTrackingImsState(int feature)208 protected synchronized void startTrackingImsState(int feature) { 209 if (feature == ImsFeature.FEATURE_MMTEL 210 && mImsMmTelManager != null 211 && mMmTelStateCallback == null) { 212 try { 213 QnsImsStateCallback imsStateCallback = new QnsImsStateCallback(feature); 214 mImsMmTelManager.registerImsStateCallback(mExecutor, imsStateCallback); 215 log("startTrackingImsState: registered ImsFeature.MMTEL State Callback."); 216 mMmTelStateCallback = imsStateCallback; 217 } catch (ImsException e) { 218 loge("startTrackingImsState: couldn't register MMTEL state callback, " + e); 219 } 220 } 221 222 if (feature == ImsFeature.FEATURE_RCS 223 && mImsRcsManager != null 224 && mRcsStateCallback == null) { 225 try { 226 QnsImsStateCallback rcsStateCallback = new QnsImsStateCallback(feature); 227 mImsRcsManager.registerImsStateCallback(mExecutor, rcsStateCallback); 228 log("startTrackingImsState: registered ImsFeature.RCS State Callback."); 229 mRcsStateCallback = rcsStateCallback; 230 } catch (ImsException e) { 231 loge("startTrackingImsState: couldn't register RCS state callback, " + e); 232 } 233 } 234 } 235 236 @VisibleForTesting startTrackingImsRegistration(int feature)237 protected synchronized void startTrackingImsRegistration(int feature) { 238 if (feature == ImsFeature.FEATURE_MMTEL 239 && mImsMmTelManager != null 240 && mMmtelImsRegistrationCallback == null) { 241 try { 242 QnsImsRegistrationCallback imsRegistrationCallback = 243 new QnsImsRegistrationCallback(feature); 244 mImsMmTelManager.registerImsRegistrationCallback( 245 mExecutor, imsRegistrationCallback); 246 log("startTrackingImsRegistration: registered MMTEL registration callback"); 247 mMmtelImsRegistrationCallback = imsRegistrationCallback; 248 } catch (ImsException e) { 249 loge("startTrackingImsRegistration: couldn't register MMTEL callback, " + e); 250 } 251 } 252 253 if (feature == ImsFeature.FEATURE_RCS 254 && mImsRcsManager != null 255 && mRcsImsRegistrationCallback == null) { 256 try { 257 QnsImsRegistrationCallback rcsRegistrationCallback = 258 new QnsImsRegistrationCallback(feature); 259 mImsRcsManager.registerImsRegistrationCallback(mExecutor, rcsRegistrationCallback); 260 log("startTrackingImsRegistration: registered RCS registration callback"); 261 mRcsImsRegistrationCallback = rcsRegistrationCallback; 262 } catch (ImsException e) { 263 loge("startTrackingImsRegistration: couldn't register RCS callback, " + e); 264 } 265 } 266 } 267 268 @VisibleForTesting startTrackingSipDialogSessionState(int feature)269 protected synchronized void startTrackingSipDialogSessionState(int feature) { 270 if (feature == ImsFeature.FEATURE_RCS 271 && mImsRcsManager != null 272 && mRcsStateCallback != null 273 && mRcsStateCallback.isImsAvailable() 274 && mRcsSipDialogSessionStateCallback == null) { 275 try { 276 QnsSipDialogStateCallback rcsSipDialogStateCallback = 277 new QnsSipDialogStateCallback(); 278 mSipDelegateManager.registerSipDialogStateCallback( 279 mExecutor, rcsSipDialogStateCallback); 280 log("startTrackingSipDialogSessionState: registered SipDialogState callback."); 281 mRcsSipDialogSessionStateCallback = rcsSipDialogStateCallback; 282 } catch (ImsException e) { 283 loge("startTrackingSipDialogSessionState: couldn't register callback, " + e); 284 } 285 } 286 } 287 stopTrackingImsState(int feature)288 protected synchronized void stopTrackingImsState(int feature) { 289 if (feature == ImsFeature.FEATURE_MMTEL 290 && mImsMmTelManager != null 291 && mMmTelStateCallback != null) { 292 try { 293 mImsMmTelManager.unregisterImsStateCallback(mMmTelStateCallback); 294 } catch (Exception e) { 295 // do-nothing 296 } 297 } 298 if (feature == ImsFeature.FEATURE_RCS 299 && mImsRcsManager != null 300 && mRcsStateCallback != null) { 301 try { 302 mImsRcsManager.unregisterImsStateCallback(mRcsStateCallback); 303 } catch (Exception e) { 304 // do-nothing 305 } 306 } 307 } 308 stopTrackingImsRegistration(int feature)309 protected synchronized void stopTrackingImsRegistration(int feature) { 310 if (feature == ImsFeature.FEATURE_MMTEL 311 && mImsMmTelManager != null 312 && mMmtelImsRegistrationCallback != null) { 313 try { 314 mImsMmTelManager.unregisterImsRegistrationCallback(mMmtelImsRegistrationCallback); 315 } catch (Exception e) { 316 // do-nothing 317 } 318 } 319 if (feature == ImsFeature.FEATURE_RCS 320 && mImsRcsManager != null 321 && mRcsImsRegistrationCallback != null) { 322 try { 323 mImsRcsManager.unregisterImsRegistrationCallback(mRcsImsRegistrationCallback); 324 } catch (Exception e) { 325 // do-nothing 326 } 327 } 328 } 329 stopTrackingSipDialogSessionState(int feature)330 protected synchronized void stopTrackingSipDialogSessionState(int feature) { 331 if (feature == ImsFeature.FEATURE_RCS 332 && mSipDelegateManager != null 333 && mRcsSipDialogSessionStateCallback != null) { 334 try { 335 mSipDelegateManager.unregisterSipDialogStateCallback( 336 mRcsSipDialogSessionStateCallback); 337 } catch (Exception e) { 338 // do-nothing 339 } 340 } 341 } 342 343 @VisibleForTesting clearQnsImsManager()344 protected synchronized void clearQnsImsManager() { 345 log("clearQnsImsManager"); 346 347 stopTrackingImsState(ImsFeature.FEATURE_MMTEL); 348 stopTrackingImsState(ImsFeature.FEATURE_RCS); 349 stopTrackingImsRegistration(ImsFeature.FEATURE_MMTEL); 350 stopTrackingImsRegistration(ImsFeature.FEATURE_RCS); 351 stopTrackingSipDialogSessionState(ImsFeature.FEATURE_RCS); 352 353 mImsManager = null; 354 mImsMmTelManager = null; 355 mImsRcsManager = null; 356 mSipDelegateManager = null; 357 mMmTelStateCallback = null; 358 mMmtelImsRegistrationCallback = null; 359 mRcsStateCallback = null; 360 mRcsImsRegistrationCallback = null; 361 mRcsSipDialogSessionStateCallback = null; 362 mQnsImsManagerInitialized = false; 363 } 364 365 @VisibleForTesting close()366 protected synchronized void close() { 367 if (mSubscriptionManager != null) { 368 mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionsChangeListener); 369 } 370 mHandlerThread.quitSafely(); 371 clearQnsImsManager(); 372 373 mMmTelImsStateListener.removeAll(); 374 mRcsImsStateListener.removeAll(); 375 mMmTelImsRegistrationListener.removeAll(); 376 mRcsImsRegistrationListener.removeAll(); 377 mRcsSipDialogSessionStateListener.removeAll(); 378 } 379 getSlotIndex()380 int getSlotIndex() { 381 return mSlotId; 382 } 383 getImsMmTelManagerOrThrowExceptionIfNotReady()384 private synchronized ImsMmTelManager getImsMmTelManagerOrThrowExceptionIfNotReady() 385 throws ImsException { 386 initQnsImsManager(); 387 if (mImsManager == null || mImsMmTelManager == null || mMmTelStateCallback == null) { 388 throw new ImsException( 389 "IMS service is down.", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 390 } 391 return mImsMmTelManager; 392 } 393 394 /** 395 * Get the boolean config from carrier config manager. 396 * 397 * @param key config key defined in CarrierConfigManager 398 * @return boolean value of corresponding key. 399 */ getBooleanCarrierConfig(String key)400 private boolean getBooleanCarrierConfig(String key) { 401 PersistableBundle b = null; 402 if (mConfigManager != null) { 403 // If an invalid subId is used, this bundle will contain default values. 404 b = mConfigManager.getConfigForSubId(getSubId()); 405 } 406 if (b != null) { 407 return b.getBoolean(key); 408 } else { 409 // Return static default defined in CarrierConfigManager. 410 return CarrierConfigManager.getDefaultConfig().getBoolean(key); 411 } 412 } 413 414 /** 415 * Get the int config from carrier config manager. 416 * 417 * @param key config key defined in CarrierConfigManager 418 * @return integer value of corresponding key. 419 */ getIntCarrierConfig(String key)420 private int getIntCarrierConfig(String key) { 421 PersistableBundle b = null; 422 if (mConfigManager != null) { 423 // If an invalid subId is used, this bundle will contain default values. 424 b = mConfigManager.getConfigForSubId(getSubId()); 425 } 426 if (b != null) { 427 return b.getInt(key); 428 } else { 429 // Return static default defined in CarrierConfigManager. 430 return CarrierConfigManager.getDefaultConfig().getInt(key); 431 } 432 } 433 isCrossSimCallingEnabledByUser()434 private boolean isCrossSimCallingEnabledByUser() { 435 boolean crossSimCallingEnabled; 436 try { 437 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 438 crossSimCallingEnabled = mmTelManager.isCrossSimCallingEnabled(); 439 } catch (Exception e) { 440 crossSimCallingEnabled = false; 441 } 442 log("isCrossSimCallingEnabledByUser:" + crossSimCallingEnabled); 443 return crossSimCallingEnabled; 444 } 445 isGbaValid()446 private boolean isGbaValid() { 447 if (getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) { 448 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); 449 if (tm == null) { 450 loge("isGbaValid: TelephonyManager is null, returning false."); 451 return false; 452 } 453 tm = tm.createForSubscriptionId(getSubId()); 454 String efIst = tm.getIsimIst(); 455 if (efIst == null) { 456 loge("isGbaValid - ISF is NULL"); 457 return true; 458 } 459 boolean result = efIst.length() > 1 && (0x02 & (byte) efIst.charAt(1)) != 0; 460 log("isGbaValid - GBA capable=" + result + ", ISF=" + efIst); 461 return result; 462 } 463 return true; 464 } 465 isCrossSimEnabledByPlatform()466 private boolean isCrossSimEnabledByPlatform() { 467 if (isWfcEnabledByPlatform()) { 468 return getBooleanCarrierConfig( 469 CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL); 470 } 471 return false; 472 } 473 isVolteProvisionedOnDevice()474 private boolean isVolteProvisionedOnDevice() { 475 if (isMmTelProvisioningRequired(REGISTRATION_TECH_LTE)) { 476 return isVolteProvisioned(); 477 } 478 479 return true; 480 } 481 isVolteProvisioned()482 private boolean isVolteProvisioned() { 483 return getImsProvisionedBoolNoException(REGISTRATION_TECH_LTE); 484 } 485 isWfcProvisioned()486 private boolean isWfcProvisioned() { 487 return getImsProvisionedBoolNoException(REGISTRATION_TECH_IWLAN); 488 } 489 isMmTelProvisioningRequired(int tech)490 private boolean isMmTelProvisioningRequired(int tech) { 491 if (!SubscriptionManager.isValidSubscriptionId(getSubId())) { 492 return false; 493 } 494 495 boolean required = false; 496 try { 497 ProvisioningManager p = ProvisioningManager.createForSubscriptionId(getSubId()); 498 required = p.isProvisioningRequiredForCapability(CAPABILITY_TYPE_VOICE, tech); 499 } catch (RuntimeException e) { 500 loge("isMmTelProvisioningRequired, tech:" + tech + ". e:" + e); 501 } 502 503 log("isMmTelProvisioningRequired " + required + " for tech:" + tech); 504 return required; 505 } 506 getImsProvisionedBoolNoException(int tech)507 private boolean getImsProvisionedBoolNoException(int tech) { 508 if (!SubscriptionManager.isValidSubscriptionId(getSubId())) { 509 return false; 510 } 511 512 boolean status = false; 513 try { 514 ProvisioningManager p = ProvisioningManager.createForSubscriptionId(getSubId()); 515 status = p.getProvisioningStatusForCapability(CAPABILITY_TYPE_VOICE, tech); 516 } catch (RuntimeException e) { 517 loge("getImsProvisionedBoolNoException, tech:" + tech + ". e:" + e); 518 } 519 520 log("getImsProvisionedBoolNoException " + status + " for tech:" + tech); 521 return status; 522 } 523 getSubId()524 private int getSubId() { 525 return QnsUtils.getSubId(mContext, mSlotId); 526 } 527 528 private static class QnsImsManagerExecutor implements Executor { 529 private Executor mExecutor; 530 531 @Override execute(Runnable runnable)532 public void execute(Runnable runnable) { 533 startExecutorIfNeeded(); 534 mExecutor.execute(runnable); 535 } 536 startExecutorIfNeeded()537 private synchronized void startExecutorIfNeeded() { 538 if (mExecutor != null) return; 539 mExecutor = Executors.newSingleThreadExecutor(); 540 } 541 } 542 543 private class QnsImsStateCallback extends ImsStateCallback { 544 int mImsFeature; 545 boolean mImsAvailable; 546 isImsAvailable()547 public boolean isImsAvailable() { 548 return mImsAvailable; 549 } 550 QnsImsStateCallback(int imsFeature)551 QnsImsStateCallback(int imsFeature) { 552 mImsFeature = imsFeature; 553 } 554 555 @Override onUnavailable(int reason)556 public void onUnavailable(int reason) { 557 changeImsState(false); 558 } 559 560 @Override onAvailable()561 public void onAvailable() { 562 changeImsState(true); 563 } 564 565 @Override onError()566 public void onError() { 567 changeImsState(false); 568 } 569 changeImsState(boolean imsAvailable)570 private void changeImsState(boolean imsAvailable) { 571 if (mImsAvailable != imsAvailable) { 572 mImsAvailable = imsAvailable; 573 onImsStateChanged(mImsFeature, imsAvailable); 574 } 575 } 576 } 577 578 /** class for the IMS State. */ 579 static class ImsState { 580 private final boolean mImsAvailable; 581 ImsState(boolean imsAvailable)582 ImsState(boolean imsAvailable) { 583 mImsAvailable = imsAvailable; 584 } 585 isImsAvailable()586 boolean isImsAvailable() { 587 return mImsAvailable; 588 } 589 } 590 onImsStateChanged(int imsFeature, boolean imsAvailable)591 private void onImsStateChanged(int imsFeature, boolean imsAvailable) { 592 if (imsFeature == ImsFeature.FEATURE_MMTEL) { 593 log("onImsStateChanged ImsFeature.MMTEL:" + imsAvailable); 594 } 595 if (imsFeature == ImsFeature.FEATURE_RCS) { 596 log("onImsStateChanged ImsFeature.RCS:" + imsAvailable); 597 } 598 599 if (imsAvailable) { 600 startTrackingImsRegistration(imsFeature); 601 startTrackingSipDialogSessionState(imsFeature); 602 } 603 604 ImsState imsState = new ImsState(imsAvailable); 605 notifyImsStateChanged(imsFeature, imsState); 606 } 607 608 /** 609 * Registers to monitor Ims State 610 * 611 * @param h Handler to get an event 612 * @param what message id. 613 */ registerImsStateChanged(Handler h, int what)614 void registerImsStateChanged(Handler h, int what) { 615 QnsRegistrant r = new QnsRegistrant(h, what, null); 616 mMmTelImsStateListener.add(r); 617 } 618 619 /** 620 * Unregisters ims state for given handler. 621 * 622 * @param h Handler 623 */ unregisterImsStateChanged(Handler h)624 void unregisterImsStateChanged(Handler h) { 625 mMmTelImsStateListener.remove(h); 626 } 627 628 /** 629 * Registers to monitor Rcs State 630 * 631 * @param h Handler to get an event 632 * @param what message id. 633 */ registerRcsStateChanged(Handler h, int what)634 void registerRcsStateChanged(Handler h, int what) { 635 QnsRegistrant r = new QnsRegistrant(h, what, null); 636 mRcsImsStateListener.add(r); 637 } 638 639 /** 640 * Unregisters rcs state for given handler. 641 * 642 * @param h Handler 643 */ unregisterRcsStateChanged(Handler h)644 void unregisterRcsStateChanged(Handler h) { 645 mRcsImsStateListener.remove(h); 646 } 647 notifyImsStateChanged(int imsFeature, ImsState imsState)648 protected void notifyImsStateChanged(int imsFeature, ImsState imsState) { 649 if (imsFeature == ImsFeature.FEATURE_MMTEL) { 650 mMmTelImsStateListener.notifyResult(imsState); 651 } else if (imsFeature == ImsFeature.FEATURE_RCS) { 652 mRcsImsStateListener.notifyResult(imsState); 653 } 654 } 655 656 private static class StateConsumer extends Semaphore implements Consumer<Integer> { 657 private static final long TIMEOUT_MILLIS = 2000; 658 StateConsumer()659 StateConsumer() { 660 super(0); 661 mValue = new AtomicInteger(); 662 } 663 664 private final AtomicInteger mValue; 665 getOrTimeOut()666 int getOrTimeOut() throws InterruptedException { 667 if (tryAcquire(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { 668 return mValue.get(); 669 } 670 return ImsFeature.STATE_UNAVAILABLE; 671 } 672 accept(Integer value)673 public void accept(Integer value) { 674 if (value != null) { 675 mValue.set(value); 676 } 677 release(); 678 } 679 } 680 681 private class QnsImsRegistrationCallback extends RegistrationManager.RegistrationCallback { 682 int mImsFeature; 683 ImsRegistrationState mImsRegistrationState; 684 QnsImsRegistrationCallback(int imsFeature)685 QnsImsRegistrationCallback(int imsFeature) { 686 mImsFeature = imsFeature; 687 mImsRegistrationState = null; 688 } 689 690 @Override onRegistered(ImsRegistrationAttributes attribute)691 public void onRegistered(ImsRegistrationAttributes attribute) { 692 int transportType = attribute.getTransportType(); 693 log("on IMS registered on :" + QnsConstants.transportTypeToString(transportType)); 694 mImsRegistrationState = 695 new ImsRegistrationState( 696 QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED, transportType, null); 697 notifyImsRegistrationChangedEvent( 698 mImsFeature, new ImsRegistrationState(mImsRegistrationState)); 699 } 700 701 @Override onTechnologyChangeFailed(int transportType, ImsReasonInfo reason)702 public void onTechnologyChangeFailed(int transportType, ImsReasonInfo reason) { 703 log( 704 "onTechnologyChangeFailed[" 705 + QnsConstants.transportTypeToString(transportType) 706 + "] " 707 + reason.toString()); 708 mImsRegistrationState = 709 new ImsRegistrationState( 710 QnsConstants.IMS_REGISTRATION_CHANGED_ACCESS_NETWORK_CHANGE_FAILED, 711 transportType, 712 reason); 713 notifyImsRegistrationChangedEvent( 714 mImsFeature, new ImsRegistrationState(mImsRegistrationState)); 715 } 716 717 @Override onUnregistered(ImsReasonInfo reason)718 public void onUnregistered(ImsReasonInfo reason) { 719 log("onUnregistered " + reason.toString()); 720 mImsRegistrationState = 721 new ImsRegistrationState( 722 QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED, 723 AccessNetworkConstants.TRANSPORT_TYPE_INVALID, 724 reason); 725 notifyImsRegistrationChangedEvent( 726 mImsFeature, new ImsRegistrationState(mImsRegistrationState)); 727 } 728 } 729 730 private class QnsSipDialogStateCallback extends SipDialogStateCallback { 731 boolean mIsActive; 732 isActive()733 public boolean isActive() { 734 return mIsActive; 735 } 736 737 @Override onActiveSipDialogsChanged(@onNull List<SipDialogState> dialogs)738 public void onActiveSipDialogsChanged(@NonNull List<SipDialogState> dialogs) { 739 for (SipDialogState state : dialogs) { 740 if (state.getState() == SipDialogState.STATE_CONFIRMED) { 741 if (!mIsActive) { 742 mIsActive = true; 743 notifySipDialogSessionStateChanged(mIsActive); 744 } 745 return; 746 } 747 } 748 if (mIsActive) { 749 mIsActive = false; 750 notifySipDialogSessionStateChanged(mIsActive); 751 } 752 } 753 754 @Override onError()755 public void onError() { 756 mIsActive = false; 757 notifySipDialogSessionStateChanged(mIsActive); 758 // TODO do nothing? 759 } 760 } 761 762 /** State class for the IMS Registration. */ 763 static class ImsRegistrationState { 764 @QnsConstants.QnsImsRegiEvent private final int mEvent; 765 private final int mTransportType; 766 private final ImsReasonInfo mReasonInfo; 767 ImsRegistrationState(int event, int transportType, ImsReasonInfo reason)768 ImsRegistrationState(int event, int transportType, ImsReasonInfo reason) { 769 mEvent = event; 770 mTransportType = transportType; 771 mReasonInfo = reason; 772 } 773 ImsRegistrationState(ImsRegistrationState state)774 ImsRegistrationState(ImsRegistrationState state) { 775 mEvent = state.mEvent; 776 mTransportType = state.mTransportType; 777 mReasonInfo = state.mReasonInfo; 778 } 779 getEvent()780 int getEvent() { 781 return mEvent; 782 } 783 getTransportType()784 int getTransportType() { 785 return mTransportType; 786 } 787 getReasonInfo()788 ImsReasonInfo getReasonInfo() { 789 return mReasonInfo; 790 } 791 792 @Override toString()793 public String toString() { 794 String reason = getReasonInfo() == null ? "null" : mReasonInfo.toString(); 795 String event = Integer.toString(mEvent); 796 switch (mEvent) { 797 case QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED: 798 event = "IMS_REGISTERED"; 799 break; 800 case QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED: 801 event = "IMS_UNREGISTERED"; 802 break; 803 case QnsConstants.IMS_REGISTRATION_CHANGED_ACCESS_NETWORK_CHANGE_FAILED: 804 event = "IMS_ACCESS_NETWORK_CHANGE_FAILED"; 805 break; 806 } 807 return "ImsRegistrationState[" 808 + QnsConstants.transportTypeToString(mTransportType) 809 + "] " 810 + "Event:" 811 + event 812 + " reason:" 813 + reason; 814 } 815 } 816 817 /** 818 * Get the status of whether the IMS is registered or not for given transport type 819 * 820 * @param transportType Transport Type 821 * @return true when ims is registered. 822 */ isImsRegistered(int transportType)823 boolean isImsRegistered(int transportType) { 824 if (mMmtelImsRegistrationCallback == null) { 825 return false; 826 } 827 ImsRegistrationState state = mMmtelImsRegistrationCallback.mImsRegistrationState; 828 return state != null 829 && state.getTransportType() == transportType 830 && state.getEvent() == QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED; 831 } 832 833 /** 834 * Get the status of whether the Rcs is registered or not for given transport type 835 * 836 * @param transportType Transport Type 837 * @return true when ims is registered. 838 */ isRcsRegistered(int transportType)839 boolean isRcsRegistered(int transportType) { 840 if (mRcsImsRegistrationCallback == null) { 841 return false; 842 } 843 ImsRegistrationState state = mRcsImsRegistrationCallback.mImsRegistrationState; 844 return state != null 845 && state.getTransportType() == transportType 846 && state.getEvent() == QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED; 847 } 848 849 /** 850 * Registers to monitor Ims registration status 851 * 852 * @param h Handler to get an event 853 * @param what message id. 854 */ registerImsRegistrationStatusChanged(Handler h, int what)855 void registerImsRegistrationStatusChanged(Handler h, int what) { 856 QnsRegistrant r = new QnsRegistrant(h, what, null); 857 mMmTelImsRegistrationListener.add(r); 858 } 859 860 /** 861 * Unregisters ims registration status for given handler. 862 * 863 * @param h Handler 864 */ unregisterImsRegistrationStatusChanged(Handler h)865 void unregisterImsRegistrationStatusChanged(Handler h) { 866 mMmTelImsRegistrationListener.remove(h); 867 } 868 869 /** 870 * Registers to monitor Ims registration status 871 * 872 * @param h Handler to get an event 873 * @param what message id. 874 */ registerRcsRegistrationStatusChanged(Handler h, int what)875 void registerRcsRegistrationStatusChanged(Handler h, int what) { 876 QnsRegistrant r = new QnsRegistrant(h, what, null); 877 mRcsImsRegistrationListener.add(r); 878 } 879 880 /** 881 * Unregisters ims registration status for given handler. 882 * 883 * @param h Handler 884 */ unregisterRcsRegistrationStatusChanged(Handler h)885 void unregisterRcsRegistrationStatusChanged(Handler h) { 886 mRcsImsRegistrationListener.remove(h); 887 } 888 889 @VisibleForTesting notifyImsRegistrationChangedEvent(int imsFeature, ImsRegistrationState state)890 protected void notifyImsRegistrationChangedEvent(int imsFeature, ImsRegistrationState state) { 891 if (imsFeature == ImsFeature.FEATURE_MMTEL) { 892 mMmTelImsRegistrationListener.notifyResult(state); 893 } else if (imsFeature == ImsFeature.FEATURE_RCS) { 894 mRcsImsRegistrationListener.notifyResult(state); 895 } 896 } 897 898 /** 899 * Get the active status of SipDialogState 900 * 901 * @return true when one of Sip Dialogs is active. 902 */ isSipDialogSessionActive()903 boolean isSipDialogSessionActive() { 904 return mRcsSipDialogSessionStateCallback != null 905 && mRcsSipDialogSessionStateCallback.isActive(); 906 } 907 908 /** 909 * Registers to monitor SipDialogSession State 910 * 911 * @param h Handler to get an event 912 * @param what message id. 913 */ registerSipDialogSessionStateChanged(Handler h, int what)914 void registerSipDialogSessionStateChanged(Handler h, int what) { 915 QnsRegistrant r = new QnsRegistrant(h, what, null); 916 mRcsSipDialogSessionStateListener.add(r); 917 } 918 919 /** 920 * Unregisters SipDialogState status for given handler. 921 * 922 * @param h Handler 923 */ unregisterSipDialogSessionStateChanged(Handler h)924 void unregisterSipDialogSessionStateChanged(Handler h) { 925 mRcsSipDialogSessionStateListener.remove(h); 926 } 927 928 @VisibleForTesting notifySipDialogSessionStateChanged(boolean isActive)929 protected void notifySipDialogSessionStateChanged(boolean isActive) { 930 mRcsSipDialogSessionStateListener.notifyResult(isActive); 931 } 932 isImsSupportedOnDevice(Context context)933 private static boolean isImsSupportedOnDevice(Context context) { 934 return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS); 935 } 936 937 /** 938 * Get the status of the MmTel Feature corresponding to this subscription. 939 * 940 * <p>This function is a blocking function and there may be a timeout of up to 2 seconds. 941 * 942 * @return MmTel Feature Status. Returns one of the following: {@link 943 * ImsFeature#STATE_UNAVAILABLE}, {@link ImsFeature#STATE_INITIALIZING}, {@link 944 * ImsFeature#STATE_READY}. 945 * @throws ImsException if the IMS service associated with this subscription is not available or 946 * the IMS service is not available. 947 * @throws InterruptedException if the thread to get value is timed out. (max 2000ms) 948 */ getImsServiceState()949 int getImsServiceState() throws ImsException, InterruptedException { 950 if (!isImsSupportedOnDevice(mContext)) { 951 throw new ImsException( 952 "IMS not supported on device.", 953 ImsReasonInfo.CODE_LOCAL_IMS_NOT_SUPPORTED_ON_DEVICE); 954 } 955 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 956 final StateConsumer stateConsumer = new StateConsumer(); 957 mmTelManager.getFeatureState(mExecutor, stateConsumer); 958 int state = stateConsumer.getOrTimeOut(); // ImsFeature.STATE_READY 959 log("getImsServiceState state:" + state); 960 return state; 961 } 962 963 /** 964 * Returns whether wi-fi calling feature is enabled by platform. 965 * 966 * <p>This function is a blocking function and there may be a timeout of up to 2 seconds. 967 * 968 * @return true, if wi-fi calling feature is enabled by platform. 969 */ isWfcEnabledByPlatform()970 boolean isWfcEnabledByPlatform() { 971 // We first read the per slot value. If it doesn't exist, we read the general value. 972 // If still doesn't exist, we use the hardcoded default value. 973 if (SystemProperties.getInt(PROP_DBG_WFC_AVAIL_OVERRIDE + mSlotId, SYS_PROP_NOT_SET) == 1 974 || SystemProperties.getInt(PROP_DBG_WFC_AVAIL_OVERRIDE, SYS_PROP_NOT_SET) == 1) { 975 return true; 976 } 977 978 return mContext.getResources() 979 .getBoolean(com.android.internal.R.bool.config_device_wfc_ims_available) 980 && getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) 981 && isGbaValid(); 982 } 983 984 /** 985 * Returns whether wi-fi calling setting is enabled by user. 986 * 987 * @return true, if wi-fi calling setting is enabled by user. 988 */ isWfcEnabledByUser()989 boolean isWfcEnabledByUser() { 990 boolean wfcEnabled; 991 try { 992 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 993 wfcEnabled = mmTelManager.isVoWiFiSettingEnabled(); 994 } catch (Exception e) { 995 wfcEnabled = 996 getBooleanCarrierConfig( 997 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL); 998 } 999 log("isWfcEnabledByUser:" + wfcEnabled); 1000 return wfcEnabled; 1001 } 1002 1003 /** 1004 * Returns whether wi-fi calling roaming setting is enabled by user. 1005 * 1006 * @return true, if wi-fi calling roaming setting is enabled by user. 1007 */ isWfcRoamingEnabledByUser()1008 boolean isWfcRoamingEnabledByUser() { 1009 boolean wfcRoamingEnabled; 1010 try { 1011 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 1012 wfcRoamingEnabled = mmTelManager.isVoWiFiRoamingSettingEnabled(); 1013 } catch (Exception e) { 1014 wfcRoamingEnabled = 1015 getBooleanCarrierConfig( 1016 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL); 1017 } 1018 log("isWfcRoamingEnabledByUser:" + wfcRoamingEnabled); 1019 return wfcRoamingEnabled; 1020 } 1021 1022 /** 1023 * Returns whether cross sim wi-fi calling is enabled. 1024 * 1025 * @return true, if cross sim wi-fi calling is enabled. 1026 */ isCrossSimCallingEnabled()1027 boolean isCrossSimCallingEnabled() { 1028 boolean userEnabled = isCrossSimCallingEnabledByUser(); 1029 boolean platformEnabled = isCrossSimEnabledByPlatform(); 1030 boolean isProvisioned = isWfcProvisionedOnDevice(); 1031 1032 log( 1033 "isCrossSimCallingEnabled: platformEnabled = " 1034 + platformEnabled 1035 + ", provisioned = " 1036 + isProvisioned 1037 + ", userEnabled = " 1038 + userEnabled); 1039 return userEnabled && platformEnabled && isProvisioned; 1040 } 1041 1042 /** 1043 * Returns Voice over Wi-Fi mode preference 1044 * 1045 * @param roaming false:mode pref for home, true:mode pref for roaming 1046 * @return voice over Wi-Fi mode preference, which can be one of the following: {@link 1047 * ImsMmTelManager#WIFI_MODE_WIFI_ONLY}, {@link 1048 * ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}, {@link 1049 * ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED} 1050 */ getWfcMode(boolean roaming)1051 int getWfcMode(boolean roaming) { 1052 if (!roaming) { 1053 int wfcMode; 1054 try { 1055 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 1056 wfcMode = mmTelManager.getVoWiFiModeSetting(); 1057 } catch (Exception e) { 1058 wfcMode = 1059 getIntCarrierConfig( 1060 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT); 1061 } 1062 log("getWfcMode:" + wfcMode); 1063 return wfcMode; 1064 } else { 1065 int wfcRoamingMode; 1066 try { 1067 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 1068 wfcRoamingMode = mmTelManager.getVoWiFiRoamingModeSetting(); 1069 } catch (Exception e) { 1070 wfcRoamingMode = 1071 getIntCarrierConfig( 1072 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT); 1073 } 1074 log("getWfcMode(roaming):" + wfcRoamingMode); 1075 return wfcRoamingMode; 1076 } 1077 } 1078 1079 /** 1080 * Indicates whether VoWifi is provisioned on slot. 1081 * 1082 * <p>When CarrierConfig KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL is true, and VoLTE is 1083 * not provisioned on device, this method returns false. 1084 */ isWfcProvisionedOnDevice()1085 boolean isWfcProvisionedOnDevice() { 1086 if (getBooleanCarrierConfig( 1087 CarrierConfigManager.KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL)) { 1088 if (!isVolteProvisionedOnDevice()) { 1089 return false; 1090 } 1091 } 1092 1093 if (isMmTelProvisioningRequired(REGISTRATION_TECH_IWLAN)) { 1094 return isWfcProvisioned(); 1095 } 1096 1097 return true; 1098 } 1099 log(String s)1100 protected void log(String s) { 1101 Log.d(mLogTag, s); 1102 } 1103 loge(String s)1104 protected void loge(String s) { 1105 Log.e(mLogTag, s); 1106 } 1107 } 1108