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("registerImsRegistrationCallback: 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 } catch (UnsupportedOperationException e) { 285 loge("registerSipDialogStateCallback: couldn't register callback, " + e); 286 } 287 } 288 } 289 stopTrackingImsState(int feature)290 protected synchronized void stopTrackingImsState(int feature) { 291 if (feature == ImsFeature.FEATURE_MMTEL 292 && mImsMmTelManager != null 293 && mMmTelStateCallback != null) { 294 try { 295 mImsMmTelManager.unregisterImsStateCallback(mMmTelStateCallback); 296 } catch (Exception e) { 297 // do-nothing 298 } 299 } 300 if (feature == ImsFeature.FEATURE_RCS 301 && mImsRcsManager != null 302 && mRcsStateCallback != null) { 303 try { 304 mImsRcsManager.unregisterImsStateCallback(mRcsStateCallback); 305 } catch (Exception e) { 306 // do-nothing 307 } 308 } 309 } 310 stopTrackingImsRegistration(int feature)311 protected synchronized void stopTrackingImsRegistration(int feature) { 312 if (feature == ImsFeature.FEATURE_MMTEL 313 && mImsMmTelManager != null 314 && mMmtelImsRegistrationCallback != null) { 315 try { 316 mImsMmTelManager.unregisterImsRegistrationCallback(mMmtelImsRegistrationCallback); 317 } catch (Exception e) { 318 // do-nothing 319 } 320 } 321 if (feature == ImsFeature.FEATURE_RCS 322 && mImsRcsManager != null 323 && mRcsImsRegistrationCallback != null) { 324 try { 325 mImsRcsManager.unregisterImsRegistrationCallback(mRcsImsRegistrationCallback); 326 } catch (Exception e) { 327 // do-nothing 328 } 329 } 330 } 331 stopTrackingSipDialogSessionState(int feature)332 protected synchronized void stopTrackingSipDialogSessionState(int feature) { 333 if (feature == ImsFeature.FEATURE_RCS 334 && mSipDelegateManager != null 335 && mRcsSipDialogSessionStateCallback != null) { 336 try { 337 mSipDelegateManager.unregisterSipDialogStateCallback( 338 mRcsSipDialogSessionStateCallback); 339 } catch (Exception e) { 340 // do-nothing 341 } 342 } 343 } 344 345 @VisibleForTesting clearQnsImsManager()346 protected synchronized void clearQnsImsManager() { 347 log("clearQnsImsManager"); 348 349 stopTrackingImsState(ImsFeature.FEATURE_MMTEL); 350 stopTrackingImsState(ImsFeature.FEATURE_RCS); 351 stopTrackingImsRegistration(ImsFeature.FEATURE_MMTEL); 352 stopTrackingImsRegistration(ImsFeature.FEATURE_RCS); 353 stopTrackingSipDialogSessionState(ImsFeature.FEATURE_RCS); 354 355 mImsManager = null; 356 mImsMmTelManager = null; 357 mImsRcsManager = null; 358 mSipDelegateManager = null; 359 mMmTelStateCallback = null; 360 mMmtelImsRegistrationCallback = null; 361 mRcsStateCallback = null; 362 mRcsImsRegistrationCallback = null; 363 mRcsSipDialogSessionStateCallback = null; 364 mQnsImsManagerInitialized = false; 365 } 366 367 @VisibleForTesting close()368 protected synchronized void close() { 369 if (mSubscriptionManager != null) { 370 mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionsChangeListener); 371 } 372 mHandlerThread.quitSafely(); 373 clearQnsImsManager(); 374 375 mMmTelImsStateListener.removeAll(); 376 mRcsImsStateListener.removeAll(); 377 mMmTelImsRegistrationListener.removeAll(); 378 mRcsImsRegistrationListener.removeAll(); 379 mRcsSipDialogSessionStateListener.removeAll(); 380 } 381 getSlotIndex()382 int getSlotIndex() { 383 return mSlotId; 384 } 385 getImsMmTelManagerOrThrowExceptionIfNotReady()386 private synchronized ImsMmTelManager getImsMmTelManagerOrThrowExceptionIfNotReady() 387 throws ImsException { 388 initQnsImsManager(); 389 if (mImsManager == null || mImsMmTelManager == null || mMmTelStateCallback == null) { 390 throw new ImsException( 391 "IMS service is down.", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 392 } 393 return mImsMmTelManager; 394 } 395 396 /** 397 * Get the boolean config from carrier config manager. 398 * 399 * @param key config key defined in CarrierConfigManager 400 * @return boolean value of corresponding key. 401 */ getBooleanCarrierConfig(String key)402 private boolean getBooleanCarrierConfig(String key) { 403 PersistableBundle b = null; 404 if (mConfigManager != null) { 405 // If an invalid subId is used, this bundle will contain default values. 406 b = mConfigManager.getConfigForSubId(getSubId()); 407 } 408 if (b != null) { 409 return b.getBoolean(key); 410 } else { 411 // Return static default defined in CarrierConfigManager. 412 return CarrierConfigManager.getDefaultConfig().getBoolean(key); 413 } 414 } 415 416 /** 417 * Get the int config from carrier config manager. 418 * 419 * @param key config key defined in CarrierConfigManager 420 * @return integer value of corresponding key. 421 */ getIntCarrierConfig(String key)422 private int getIntCarrierConfig(String key) { 423 PersistableBundle b = null; 424 if (mConfigManager != null) { 425 // If an invalid subId is used, this bundle will contain default values. 426 b = mConfigManager.getConfigForSubId(getSubId()); 427 } 428 if (b != null) { 429 return b.getInt(key); 430 } else { 431 // Return static default defined in CarrierConfigManager. 432 return CarrierConfigManager.getDefaultConfig().getInt(key); 433 } 434 } 435 isCrossSimCallingEnabledByUser()436 private boolean isCrossSimCallingEnabledByUser() { 437 boolean crossSimCallingEnabled; 438 try { 439 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 440 crossSimCallingEnabled = mmTelManager.isCrossSimCallingEnabled(); 441 } catch (Exception e) { 442 crossSimCallingEnabled = false; 443 } 444 log("isCrossSimCallingEnabledByUser:" + crossSimCallingEnabled); 445 return crossSimCallingEnabled; 446 } 447 isGbaValid()448 private boolean isGbaValid() { 449 if (getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) { 450 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); 451 if (tm == null) { 452 loge("isGbaValid: TelephonyManager is null, returning false."); 453 return false; 454 } 455 tm = tm.createForSubscriptionId(getSubId()); 456 String efIst = tm.getIsimIst(); 457 if (efIst == null) { 458 loge("isGbaValid - ISF is NULL"); 459 return true; 460 } 461 boolean result = efIst.length() > 1 && (0x02 & (byte) efIst.charAt(1)) != 0; 462 log("isGbaValid - GBA capable=" + result + ", ISF=" + efIst); 463 return result; 464 } 465 return true; 466 } 467 isCrossSimEnabledByPlatform()468 private boolean isCrossSimEnabledByPlatform() { 469 if (isWfcEnabledByPlatform()) { 470 return getBooleanCarrierConfig( 471 CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL); 472 } 473 return false; 474 } 475 isVolteProvisionedOnDevice()476 private boolean isVolteProvisionedOnDevice() { 477 if (isMmTelProvisioningRequired(REGISTRATION_TECH_LTE)) { 478 return isVolteProvisioned(); 479 } 480 481 return true; 482 } 483 isVolteProvisioned()484 private boolean isVolteProvisioned() { 485 return getImsProvisionedBoolNoException(REGISTRATION_TECH_LTE); 486 } 487 isWfcProvisioned()488 private boolean isWfcProvisioned() { 489 return getImsProvisionedBoolNoException(REGISTRATION_TECH_IWLAN); 490 } 491 isMmTelProvisioningRequired(int tech)492 private boolean isMmTelProvisioningRequired(int tech) { 493 if (!SubscriptionManager.isValidSubscriptionId(getSubId())) { 494 return false; 495 } 496 497 boolean required = false; 498 try { 499 ProvisioningManager p = ProvisioningManager.createForSubscriptionId(getSubId()); 500 required = p.isProvisioningRequiredForCapability(CAPABILITY_TYPE_VOICE, tech); 501 } catch (RuntimeException e) { 502 loge("isMmTelProvisioningRequired, tech:" + tech + ". e:" + e); 503 } 504 505 log("isMmTelProvisioningRequired " + required + " for tech:" + tech); 506 return required; 507 } 508 getImsProvisionedBoolNoException(int tech)509 private boolean getImsProvisionedBoolNoException(int tech) { 510 if (!SubscriptionManager.isValidSubscriptionId(getSubId())) { 511 return false; 512 } 513 514 boolean status = false; 515 try { 516 ProvisioningManager p = ProvisioningManager.createForSubscriptionId(getSubId()); 517 status = p.getProvisioningStatusForCapability(CAPABILITY_TYPE_VOICE, tech); 518 } catch (RuntimeException e) { 519 loge("getImsProvisionedBoolNoException, tech:" + tech + ". e:" + e); 520 } 521 522 log("getImsProvisionedBoolNoException " + status + " for tech:" + tech); 523 return status; 524 } 525 getSubId()526 private int getSubId() { 527 return QnsUtils.getSubId(mContext, mSlotId); 528 } 529 530 private static class QnsImsManagerExecutor implements Executor { 531 private Executor mExecutor; 532 533 @Override execute(Runnable runnable)534 public void execute(Runnable runnable) { 535 startExecutorIfNeeded(); 536 mExecutor.execute(runnable); 537 } 538 startExecutorIfNeeded()539 private synchronized void startExecutorIfNeeded() { 540 if (mExecutor != null) return; 541 mExecutor = Executors.newSingleThreadExecutor(); 542 } 543 } 544 545 private class QnsImsStateCallback extends ImsStateCallback { 546 int mImsFeature; 547 boolean mImsAvailable; 548 isImsAvailable()549 public boolean isImsAvailable() { 550 return mImsAvailable; 551 } 552 QnsImsStateCallback(int imsFeature)553 QnsImsStateCallback(int imsFeature) { 554 mImsFeature = imsFeature; 555 } 556 557 @Override onUnavailable(int reason)558 public void onUnavailable(int reason) { 559 changeImsState(false); 560 } 561 562 @Override onAvailable()563 public void onAvailable() { 564 changeImsState(true); 565 } 566 567 @Override onError()568 public void onError() { 569 changeImsState(false); 570 } 571 changeImsState(boolean imsAvailable)572 private void changeImsState(boolean imsAvailable) { 573 if (mImsAvailable != imsAvailable) { 574 mImsAvailable = imsAvailable; 575 onImsStateChanged(mImsFeature, imsAvailable); 576 } 577 } 578 } 579 580 /** class for the IMS State. */ 581 static class ImsState { 582 private final boolean mImsAvailable; 583 ImsState(boolean imsAvailable)584 ImsState(boolean imsAvailable) { 585 mImsAvailable = imsAvailable; 586 } 587 isImsAvailable()588 boolean isImsAvailable() { 589 return mImsAvailable; 590 } 591 } 592 onImsStateChanged(int imsFeature, boolean imsAvailable)593 private void onImsStateChanged(int imsFeature, boolean imsAvailable) { 594 if (imsFeature == ImsFeature.FEATURE_MMTEL) { 595 log("onImsStateChanged ImsFeature.MMTEL:" + imsAvailable); 596 } 597 if (imsFeature == ImsFeature.FEATURE_RCS) { 598 log("onImsStateChanged ImsFeature.RCS:" + imsAvailable); 599 } 600 601 if (imsAvailable) { 602 startTrackingImsRegistration(imsFeature); 603 if (imsFeature == ImsFeature.FEATURE_RCS) { 604 startTrackingSipDialogSessionState(imsFeature); 605 } 606 } 607 608 ImsState imsState = new ImsState(imsAvailable); 609 notifyImsStateChanged(imsFeature, imsState); 610 } 611 612 /** 613 * Registers to monitor Ims State 614 * 615 * @param h Handler to get an event 616 * @param what message id. 617 */ registerImsStateChanged(Handler h, int what)618 void registerImsStateChanged(Handler h, int what) { 619 QnsRegistrant r = new QnsRegistrant(h, what, null); 620 mMmTelImsStateListener.add(r); 621 } 622 623 /** 624 * Unregisters ims state for given handler. 625 * 626 * @param h Handler 627 */ unregisterImsStateChanged(Handler h)628 void unregisterImsStateChanged(Handler h) { 629 mMmTelImsStateListener.remove(h); 630 } 631 632 /** 633 * Registers to monitor Rcs State 634 * 635 * @param h Handler to get an event 636 * @param what message id. 637 */ registerRcsStateChanged(Handler h, int what)638 void registerRcsStateChanged(Handler h, int what) { 639 QnsRegistrant r = new QnsRegistrant(h, what, null); 640 mRcsImsStateListener.add(r); 641 } 642 643 /** 644 * Unregisters rcs state for given handler. 645 * 646 * @param h Handler 647 */ unregisterRcsStateChanged(Handler h)648 void unregisterRcsStateChanged(Handler h) { 649 mRcsImsStateListener.remove(h); 650 } 651 notifyImsStateChanged(int imsFeature, ImsState imsState)652 protected void notifyImsStateChanged(int imsFeature, ImsState imsState) { 653 if (imsFeature == ImsFeature.FEATURE_MMTEL) { 654 mMmTelImsStateListener.notifyResult(imsState); 655 } else if (imsFeature == ImsFeature.FEATURE_RCS) { 656 mRcsImsStateListener.notifyResult(imsState); 657 } 658 } 659 660 private static class StateConsumer extends Semaphore implements Consumer<Integer> { 661 private static final long TIMEOUT_MILLIS = 2000; 662 StateConsumer()663 StateConsumer() { 664 super(0); 665 mValue = new AtomicInteger(); 666 } 667 668 private final AtomicInteger mValue; 669 getOrTimeOut()670 int getOrTimeOut() throws InterruptedException { 671 if (tryAcquire(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) { 672 return mValue.get(); 673 } 674 return ImsFeature.STATE_UNAVAILABLE; 675 } 676 accept(Integer value)677 public void accept(Integer value) { 678 if (value != null) { 679 mValue.set(value); 680 } 681 release(); 682 } 683 } 684 685 private class QnsImsRegistrationCallback extends RegistrationManager.RegistrationCallback { 686 int mImsFeature; 687 ImsRegistrationState mImsRegistrationState; 688 QnsImsRegistrationCallback(int imsFeature)689 QnsImsRegistrationCallback(int imsFeature) { 690 mImsFeature = imsFeature; 691 mImsRegistrationState = null; 692 } 693 694 @Override onRegistered(ImsRegistrationAttributes attribute)695 public void onRegistered(ImsRegistrationAttributes attribute) { 696 int transportType = attribute.getTransportType(); 697 log("on IMS registered on :" + QnsConstants.transportTypeToString(transportType)); 698 mImsRegistrationState = 699 new ImsRegistrationState( 700 QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED, transportType, null); 701 notifyImsRegistrationChangedEvent( 702 mImsFeature, new ImsRegistrationState(mImsRegistrationState)); 703 } 704 705 @Override onTechnologyChangeFailed(int transportType, ImsReasonInfo reason)706 public void onTechnologyChangeFailed(int transportType, ImsReasonInfo reason) { 707 log( 708 "onTechnologyChangeFailed[" 709 + QnsConstants.transportTypeToString(transportType) 710 + "] " 711 + reason.toString()); 712 mImsRegistrationState = 713 new ImsRegistrationState( 714 QnsConstants.IMS_REGISTRATION_CHANGED_ACCESS_NETWORK_CHANGE_FAILED, 715 transportType, 716 reason); 717 notifyImsRegistrationChangedEvent( 718 mImsFeature, new ImsRegistrationState(mImsRegistrationState)); 719 } 720 721 @Override onUnregistered(ImsReasonInfo reason)722 public void onUnregistered(ImsReasonInfo reason) { 723 log("onUnregistered " + reason.toString()); 724 mImsRegistrationState = 725 new ImsRegistrationState( 726 QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED, 727 AccessNetworkConstants.TRANSPORT_TYPE_INVALID, 728 reason); 729 notifyImsRegistrationChangedEvent( 730 mImsFeature, new ImsRegistrationState(mImsRegistrationState)); 731 } 732 } 733 734 private class QnsSipDialogStateCallback extends SipDialogStateCallback { 735 boolean mIsActive; 736 isActive()737 public boolean isActive() { 738 return mIsActive; 739 } 740 741 @Override onActiveSipDialogsChanged(@onNull List<SipDialogState> dialogs)742 public void onActiveSipDialogsChanged(@NonNull List<SipDialogState> dialogs) { 743 for (SipDialogState state : dialogs) { 744 if (state.getState() == SipDialogState.STATE_CONFIRMED) { 745 if (!mIsActive) { 746 mIsActive = true; 747 notifySipDialogSessionStateChanged(mIsActive); 748 } 749 return; 750 } 751 } 752 if (mIsActive) { 753 mIsActive = false; 754 notifySipDialogSessionStateChanged(mIsActive); 755 } 756 } 757 758 @Override onError()759 public void onError() { 760 mIsActive = false; 761 notifySipDialogSessionStateChanged(mIsActive); 762 // TODO do nothing? 763 } 764 } 765 766 /** State class for the IMS Registration. */ 767 static class ImsRegistrationState { 768 @QnsConstants.QnsImsRegiEvent private final int mEvent; 769 private final int mTransportType; 770 private final ImsReasonInfo mReasonInfo; 771 ImsRegistrationState(int event, int transportType, ImsReasonInfo reason)772 ImsRegistrationState(int event, int transportType, ImsReasonInfo reason) { 773 mEvent = event; 774 mTransportType = transportType; 775 mReasonInfo = reason; 776 } 777 ImsRegistrationState(ImsRegistrationState state)778 ImsRegistrationState(ImsRegistrationState state) { 779 mEvent = state.mEvent; 780 mTransportType = state.mTransportType; 781 mReasonInfo = state.mReasonInfo; 782 } 783 getEvent()784 int getEvent() { 785 return mEvent; 786 } 787 getTransportType()788 int getTransportType() { 789 return mTransportType; 790 } 791 getReasonInfo()792 ImsReasonInfo getReasonInfo() { 793 return mReasonInfo; 794 } 795 796 @Override toString()797 public String toString() { 798 String reason = getReasonInfo() == null ? "null" : mReasonInfo.toString(); 799 String event = Integer.toString(mEvent); 800 switch (mEvent) { 801 case QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED: 802 event = "IMS_REGISTERED"; 803 break; 804 case QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED: 805 event = "IMS_UNREGISTERED"; 806 break; 807 case QnsConstants.IMS_REGISTRATION_CHANGED_ACCESS_NETWORK_CHANGE_FAILED: 808 event = "IMS_ACCESS_NETWORK_CHANGE_FAILED"; 809 break; 810 } 811 return "ImsRegistrationState[" 812 + QnsConstants.transportTypeToString(mTransportType) 813 + "] " 814 + "Event:" 815 + event 816 + " reason:" 817 + reason; 818 } 819 } 820 821 /** 822 * Get the status of whether the IMS is registered or not for given transport type 823 * 824 * @param transportType Transport Type 825 * @return true when ims is registered. 826 */ isImsRegistered(int transportType)827 boolean isImsRegistered(int transportType) { 828 if (mMmtelImsRegistrationCallback == null) { 829 return false; 830 } 831 ImsRegistrationState state = mMmtelImsRegistrationCallback.mImsRegistrationState; 832 return state != null 833 && state.getTransportType() == transportType 834 && state.getEvent() == QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED; 835 } 836 837 /** 838 * Get the status of whether the Rcs is registered or not for given transport type 839 * 840 * @param transportType Transport Type 841 * @return true when ims is registered. 842 */ isRcsRegistered(int transportType)843 boolean isRcsRegistered(int transportType) { 844 if (mRcsImsRegistrationCallback == null) { 845 return false; 846 } 847 ImsRegistrationState state = mRcsImsRegistrationCallback.mImsRegistrationState; 848 return state != null 849 && state.getTransportType() == transportType 850 && state.getEvent() == QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED; 851 } 852 853 /** 854 * Registers to monitor Ims registration status 855 * 856 * @param h Handler to get an event 857 * @param what message id. 858 */ registerImsRegistrationStatusChanged(Handler h, int what)859 void registerImsRegistrationStatusChanged(Handler h, int what) { 860 QnsRegistrant r = new QnsRegistrant(h, what, null); 861 mMmTelImsRegistrationListener.add(r); 862 } 863 864 /** 865 * Unregisters ims registration status for given handler. 866 * 867 * @param h Handler 868 */ unregisterImsRegistrationStatusChanged(Handler h)869 void unregisterImsRegistrationStatusChanged(Handler h) { 870 mMmTelImsRegistrationListener.remove(h); 871 } 872 873 /** 874 * Registers to monitor Ims registration status 875 * 876 * @param h Handler to get an event 877 * @param what message id. 878 */ registerRcsRegistrationStatusChanged(Handler h, int what)879 void registerRcsRegistrationStatusChanged(Handler h, int what) { 880 QnsRegistrant r = new QnsRegistrant(h, what, null); 881 mRcsImsRegistrationListener.add(r); 882 } 883 884 /** 885 * Unregisters ims registration status for given handler. 886 * 887 * @param h Handler 888 */ unregisterRcsRegistrationStatusChanged(Handler h)889 void unregisterRcsRegistrationStatusChanged(Handler h) { 890 mRcsImsRegistrationListener.remove(h); 891 } 892 893 @VisibleForTesting notifyImsRegistrationChangedEvent(int imsFeature, ImsRegistrationState state)894 protected void notifyImsRegistrationChangedEvent(int imsFeature, ImsRegistrationState state) { 895 if (imsFeature == ImsFeature.FEATURE_MMTEL) { 896 mMmTelImsRegistrationListener.notifyResult(state); 897 } else if (imsFeature == ImsFeature.FEATURE_RCS) { 898 mRcsImsRegistrationListener.notifyResult(state); 899 } 900 } 901 902 /** 903 * Get the active status of SipDialogState 904 * 905 * @return true when one of Sip Dialogs is active. 906 */ isSipDialogSessionActive()907 boolean isSipDialogSessionActive() { 908 return mRcsSipDialogSessionStateCallback != null 909 && mRcsSipDialogSessionStateCallback.isActive(); 910 } 911 912 /** 913 * Registers to monitor SipDialogSession State 914 * 915 * @param h Handler to get an event 916 * @param what message id. 917 */ registerSipDialogSessionStateChanged(Handler h, int what)918 void registerSipDialogSessionStateChanged(Handler h, int what) { 919 QnsRegistrant r = new QnsRegistrant(h, what, null); 920 mRcsSipDialogSessionStateListener.add(r); 921 } 922 923 /** 924 * Unregisters SipDialogState status for given handler. 925 * 926 * @param h Handler 927 */ unregisterSipDialogSessionStateChanged(Handler h)928 void unregisterSipDialogSessionStateChanged(Handler h) { 929 mRcsSipDialogSessionStateListener.remove(h); 930 } 931 932 @VisibleForTesting notifySipDialogSessionStateChanged(boolean isActive)933 protected void notifySipDialogSessionStateChanged(boolean isActive) { 934 mRcsSipDialogSessionStateListener.notifyResult(isActive); 935 } 936 isImsSupportedOnDevice(Context context)937 private static boolean isImsSupportedOnDevice(Context context) { 938 return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS); 939 } 940 941 /** 942 * Get the status of the MmTel Feature corresponding to this subscription. 943 * 944 * <p>This function is a blocking function and there may be a timeout of up to 2 seconds. 945 * 946 * @return MmTel Feature Status. Returns one of the following: {@link 947 * ImsFeature#STATE_UNAVAILABLE}, {@link ImsFeature#STATE_INITIALIZING}, {@link 948 * ImsFeature#STATE_READY}. 949 * @throws ImsException if the IMS service associated with this subscription is not available or 950 * the IMS service is not available. 951 * @throws InterruptedException if the thread to get value is timed out. (max 2000ms) 952 */ getImsServiceState()953 int getImsServiceState() throws ImsException, InterruptedException { 954 if (!isImsSupportedOnDevice(mContext)) { 955 throw new ImsException( 956 "IMS not supported on device.", 957 ImsReasonInfo.CODE_LOCAL_IMS_NOT_SUPPORTED_ON_DEVICE); 958 } 959 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 960 final StateConsumer stateConsumer = new StateConsumer(); 961 mmTelManager.getFeatureState(mExecutor, stateConsumer); 962 int state = stateConsumer.getOrTimeOut(); // ImsFeature.STATE_READY 963 log("getImsServiceState state:" + state); 964 return state; 965 } 966 967 /** 968 * Returns whether wi-fi calling feature is enabled by platform. 969 * 970 * <p>This function is a blocking function and there may be a timeout of up to 2 seconds. 971 * 972 * @return true, if wi-fi calling feature is enabled by platform. 973 */ isWfcEnabledByPlatform()974 boolean isWfcEnabledByPlatform() { 975 // We first read the per slot value. If it doesn't exist, we read the general value. 976 // If still doesn't exist, we use the hardcoded default value. 977 if (SystemProperties.getInt(PROP_DBG_WFC_AVAIL_OVERRIDE + mSlotId, SYS_PROP_NOT_SET) == 1 978 || SystemProperties.getInt(PROP_DBG_WFC_AVAIL_OVERRIDE, SYS_PROP_NOT_SET) == 1) { 979 return true; 980 } 981 982 return mContext.getResources() 983 .getBoolean(com.android.internal.R.bool.config_device_wfc_ims_available) 984 && getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) 985 && isGbaValid(); 986 } 987 988 /** 989 * Returns whether wi-fi calling setting is enabled by user. 990 * 991 * @return true, if wi-fi calling setting is enabled by user. 992 */ isWfcEnabledByUser()993 boolean isWfcEnabledByUser() { 994 boolean wfcEnabled; 995 try { 996 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 997 wfcEnabled = mmTelManager.isVoWiFiSettingEnabled(); 998 } catch (Exception e) { 999 wfcEnabled = 1000 getBooleanCarrierConfig( 1001 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL); 1002 } 1003 log("isWfcEnabledByUser:" + wfcEnabled); 1004 return wfcEnabled; 1005 } 1006 1007 /** 1008 * Returns whether wi-fi calling roaming setting is enabled by user. 1009 * 1010 * @return true, if wi-fi calling roaming setting is enabled by user. 1011 */ isWfcRoamingEnabledByUser()1012 boolean isWfcRoamingEnabledByUser() { 1013 boolean wfcRoamingEnabled; 1014 try { 1015 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 1016 wfcRoamingEnabled = mmTelManager.isVoWiFiRoamingSettingEnabled(); 1017 } catch (Exception e) { 1018 wfcRoamingEnabled = 1019 getBooleanCarrierConfig( 1020 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL); 1021 } 1022 log("isWfcRoamingEnabledByUser:" + wfcRoamingEnabled); 1023 return wfcRoamingEnabled; 1024 } 1025 1026 /** 1027 * Returns whether cross sim wi-fi calling is enabled. 1028 * 1029 * @return true, if cross sim wi-fi calling is enabled. 1030 */ isCrossSimCallingEnabled()1031 boolean isCrossSimCallingEnabled() { 1032 boolean userEnabled = isCrossSimCallingEnabledByUser(); 1033 boolean platformEnabled = isCrossSimEnabledByPlatform(); 1034 boolean isProvisioned = isWfcProvisionedOnDevice(); 1035 1036 log( 1037 "isCrossSimCallingEnabled: platformEnabled = " 1038 + platformEnabled 1039 + ", provisioned = " 1040 + isProvisioned 1041 + ", userEnabled = " 1042 + userEnabled); 1043 return userEnabled && platformEnabled && isProvisioned; 1044 } 1045 1046 /** 1047 * Returns Voice over Wi-Fi mode preference 1048 * 1049 * @param roaming false:mode pref for home, true:mode pref for roaming 1050 * @return voice over Wi-Fi mode preference, which can be one of the following: {@link 1051 * ImsMmTelManager#WIFI_MODE_WIFI_ONLY}, {@link 1052 * ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}, {@link 1053 * ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED} 1054 */ getWfcMode(boolean roaming)1055 int getWfcMode(boolean roaming) { 1056 if (!roaming) { 1057 int wfcMode; 1058 try { 1059 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 1060 wfcMode = mmTelManager.getVoWiFiModeSetting(); 1061 } catch (Exception e) { 1062 wfcMode = 1063 getIntCarrierConfig( 1064 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT); 1065 } 1066 log("getWfcMode:" + wfcMode); 1067 return wfcMode; 1068 } else { 1069 int wfcRoamingMode; 1070 try { 1071 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady(); 1072 wfcRoamingMode = mmTelManager.getVoWiFiRoamingModeSetting(); 1073 } catch (Exception e) { 1074 wfcRoamingMode = 1075 getIntCarrierConfig( 1076 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT); 1077 } 1078 log("getWfcMode(roaming):" + wfcRoamingMode); 1079 return wfcRoamingMode; 1080 } 1081 } 1082 1083 /** 1084 * Indicates whether VoWifi is provisioned on slot. 1085 * 1086 * <p>When CarrierConfig KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL is true, and VoLTE is 1087 * not provisioned on device, this method returns false. 1088 */ isWfcProvisionedOnDevice()1089 boolean isWfcProvisionedOnDevice() { 1090 if (getBooleanCarrierConfig( 1091 CarrierConfigManager.KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL)) { 1092 if (!isVolteProvisionedOnDevice()) { 1093 return false; 1094 } 1095 } 1096 1097 if (isMmTelProvisioningRequired(REGISTRATION_TECH_IWLAN)) { 1098 return isWfcProvisioned(); 1099 } 1100 1101 return true; 1102 } 1103 log(String s)1104 protected void log(String s) { 1105 Log.d(mLogTag, s); 1106 } 1107 loge(String s)1108 protected void loge(String s) { 1109 Log.e(mLogTag, s); 1110 } 1111 } 1112