1 /* 2 * Copyright (C) 2020 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.ims.rcs.uce.presence.publish; 18 19 import android.content.BroadcastReceiver; 20 import android.content.ContentResolver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.database.ContentObserver; 25 import android.net.Uri; 26 import android.os.Handler; 27 import android.os.HandlerThread; 28 import android.os.Looper; 29 import android.os.Message; 30 import android.provider.Settings; 31 import android.provider.Telephony; 32 import android.telecom.TelecomManager; 33 import android.telephony.AccessNetworkConstants; 34 import android.telephony.AccessNetworkConstants.TransportType; 35 import android.telephony.ims.ImsException; 36 import android.telephony.ims.ImsManager; 37 import android.telephony.ims.ImsMmTelManager; 38 import android.telephony.ims.ImsMmTelManager.CapabilityCallback; 39 import android.telephony.ims.ImsRcsManager; 40 import android.telephony.ims.ImsReasonInfo; 41 import android.telephony.ims.ImsRegistrationAttributes; 42 import android.telephony.ims.ProvisioningManager; 43 import android.telephony.ims.RegistrationManager; 44 import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities; 45 import android.util.IndentingPrintWriter; 46 import android.util.LocalLog; 47 import android.util.Log; 48 49 import com.android.ims.rcs.uce.UceStatsWriter; 50 import com.android.ims.rcs.uce.presence.publish.PublishController.PublishControllerCallback; 51 import com.android.ims.rcs.uce.presence.publish.PublishController.PublishTriggerType; 52 import com.android.ims.rcs.uce.util.UceUtils; 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.internal.telephony.util.HandlerExecutor; 55 56 import java.io.PrintWriter; 57 import java.util.ArrayList; 58 import java.util.Arrays; 59 import java.util.Collections; 60 import java.util.List; 61 import java.util.Objects; 62 import java.util.Set; 63 64 /** 65 * Listen to the device changes and notify the PublishController to publish the device's 66 * capabilities to the Presence server. 67 */ 68 public class DeviceCapabilityListener { 69 70 private static final String LOG_TAG = UceUtils.getLogPrefix() + "DeviceCapListener"; 71 72 private static final long REGISTER_IMS_CHANGED_DELAY = 15000L; // 15 seconds 73 74 private final UceStatsWriter mUceStatsWriter; 75 76 /** 77 * Used to inject ImsMmTelManager instances for testing. 78 */ 79 @VisibleForTesting 80 public interface ImsMmTelManagerFactory { getImsMmTelManager(int subId)81 ImsMmTelManager getImsMmTelManager(int subId); 82 } 83 84 /** 85 * Used to inject ImsRcsManager instances for testing. 86 */ 87 @VisibleForTesting 88 public interface ImsRcsManagerFactory { getImsRcsManager(int subId)89 ImsRcsManager getImsRcsManager(int subId); 90 } 91 92 /** 93 * Used to inject ProvisioningManager instances for testing. 94 */ 95 @VisibleForTesting 96 public interface ProvisioningManagerFactory { getProvisioningManager(int subId)97 ProvisioningManager getProvisioningManager(int subId); 98 } 99 100 /* 101 * Handle registering IMS callback and triggering the publish request because of the 102 * capabilities changed. 103 */ 104 private class DeviceCapabilityHandler extends Handler { 105 private static final long TRIGGER_PUBLISH_REQUEST_DELAY_MS = 500L; 106 107 private static final int EVENT_REGISTER_IMS_CONTENT_CHANGE = 1; 108 private static final int EVENT_UNREGISTER_IMS_CHANGE = 2; 109 private static final int EVENT_REQUEST_PUBLISH = 3; 110 private static final int EVENT_IMS_UNREGISTERED = 4; 111 DeviceCapabilityHandler(Looper looper)112 DeviceCapabilityHandler(Looper looper) { 113 super(looper); 114 } 115 116 @Override handleMessage(Message msg)117 public void handleMessage(Message msg) { 118 logd("handleMessage: " + msg.what); 119 if (mIsDestroyed) return; 120 switch (msg.what) { 121 case EVENT_REGISTER_IMS_CONTENT_CHANGE: 122 registerImsProvisionCallback(); 123 break; 124 case EVENT_UNREGISTER_IMS_CHANGE: 125 unregisterImsProvisionCallback(); 126 break; 127 case EVENT_REQUEST_PUBLISH: 128 int triggerType = msg.arg1; 129 mCallback.requestPublishFromInternal(triggerType); 130 break; 131 case EVENT_IMS_UNREGISTERED: 132 mCallback.updateImsUnregistered(); 133 break; 134 } 135 } 136 sendRegisterImsContentChangedMessage(long delay)137 public void sendRegisterImsContentChangedMessage(long delay) { 138 // Remove the existing message and send a new one with the delayed time. 139 removeMessages(EVENT_REGISTER_IMS_CONTENT_CHANGE); 140 Message msg = obtainMessage(EVENT_REGISTER_IMS_CONTENT_CHANGE); 141 sendMessageDelayed(msg, delay); 142 } 143 removeRegisterImsContentChangedMessage()144 public void removeRegisterImsContentChangedMessage() { 145 removeMessages(EVENT_REGISTER_IMS_CONTENT_CHANGE); 146 } 147 sendUnregisterImsCallbackMessage()148 public void sendUnregisterImsCallbackMessage() { 149 removeMessages(EVENT_REGISTER_IMS_CONTENT_CHANGE); 150 sendEmptyMessage(EVENT_UNREGISTER_IMS_CHANGE); 151 } 152 sendTriggeringPublishMessage(@ublishTriggerType int type)153 public void sendTriggeringPublishMessage(@PublishTriggerType int type) { 154 logd("sendTriggeringPublishMessage: type=" + type); 155 // Remove the existing message and resend a new message. 156 removeMessages(EVENT_REQUEST_PUBLISH); 157 Message message = obtainMessage(); 158 message.what = EVENT_REQUEST_PUBLISH; 159 message.arg1 = type; 160 sendMessageDelayed(message, TRIGGER_PUBLISH_REQUEST_DELAY_MS); 161 } 162 sendImsUnregisteredMessage()163 public void sendImsUnregisteredMessage() { 164 logd("sendImsUnregisteredMessage"); 165 // The IMS has been unregistered. Remove the existing message not processed. 166 removeMessages(EVENT_REQUEST_PUBLISH); 167 // Remove the existing message and resend a new message. 168 removeMessages(EVENT_IMS_UNREGISTERED); 169 Message msg = obtainMessage(EVENT_IMS_UNREGISTERED); 170 sendMessageDelayed(msg, TRIGGER_PUBLISH_REQUEST_DELAY_MS); 171 } 172 } 173 174 private final int mSubId; 175 private final Context mContext; 176 private final LocalLog mLocalLog = new LocalLog(UceUtils.LOG_SIZE); 177 private volatile boolean mInitialized; 178 private volatile boolean mIsDestroyed; 179 private volatile boolean mIsRcsConnected; 180 private volatile boolean mIsImsCallbackRegistered; 181 182 // The callback to trigger the internal publish request 183 private final PublishControllerCallback mCallback; 184 private final DeviceCapabilityInfo mCapabilityInfo; 185 private final HandlerThread mHandlerThread; 186 private final DeviceCapabilityHandler mHandler; 187 private final HandlerExecutor mHandlerExecutor; 188 189 private ImsMmTelManager mImsMmTelManager; 190 private ImsMmTelManagerFactory mImsMmTelManagerFactory = (subId) -> getImsMmTelManager(subId); 191 192 private ImsRcsManager mImsRcsManager; 193 private ImsRcsManagerFactory mImsRcsManagerFactory = (subId) -> getImsRcsManager(subId); 194 195 private ProvisioningManager mProvisioningManager; 196 private ProvisioningManagerFactory mProvisioningMgrFactory = (subId) 197 -> ProvisioningManager.createForSubscriptionId(subId); 198 199 private ContentObserver mMobileDataObserver = null; 200 private ContentObserver mSimInfoContentObserver = null; 201 202 private final Object mLock = new Object(); 203 DeviceCapabilityListener(Context context, int subId, DeviceCapabilityInfo info, PublishControllerCallback callback, UceStatsWriter uceStatsWriter)204 public DeviceCapabilityListener(Context context, int subId, DeviceCapabilityInfo info, 205 PublishControllerCallback callback, UceStatsWriter uceStatsWriter) { 206 mSubId = subId; 207 logi("create"); 208 209 mContext = context; 210 mCallback = callback; 211 mCapabilityInfo = info; 212 mInitialized = false; 213 mUceStatsWriter = uceStatsWriter; 214 215 mHandlerThread = new HandlerThread("DeviceCapListenerThread"); 216 mHandlerThread.start(); 217 mHandler = new DeviceCapabilityHandler(mHandlerThread.getLooper()); 218 mHandlerExecutor = new HandlerExecutor(mHandler); 219 } 220 221 /** 222 * Turn on the device capabilities changed listener 223 */ initialize()224 public void initialize() { 225 synchronized (mLock) { 226 if (mIsDestroyed) { 227 logw("initialize: This instance is already destroyed"); 228 return; 229 } 230 if (mInitialized) return; 231 232 logi("initialize"); 233 mImsMmTelManager = mImsMmTelManagerFactory.getImsMmTelManager(mSubId); 234 mImsRcsManager = mImsRcsManagerFactory.getImsRcsManager(mSubId); 235 mProvisioningManager = mProvisioningMgrFactory.getProvisioningManager(mSubId); 236 registerReceivers(); 237 registerImsProvisionCallback(); 238 239 mInitialized = true; 240 } 241 } 242 243 // The RcsFeature has been connected to the framework onRcsConnected()244 public void onRcsConnected() { 245 mIsRcsConnected = true; 246 mHandler.sendRegisterImsContentChangedMessage(0L); 247 } 248 249 // The framework has lost the binding to the RcsFeature. onRcsDisconnected()250 public void onRcsDisconnected() { 251 mIsRcsConnected = false; 252 mHandler.sendUnregisterImsCallbackMessage(); 253 } 254 255 /** 256 * Notify the instance is destroyed 257 */ onDestroy()258 public void onDestroy() { 259 logi("onDestroy"); 260 mIsDestroyed = true; 261 synchronized (mLock) { 262 if (!mInitialized) return; 263 logi("turnOffListener"); 264 mInitialized = false; 265 unregisterReceivers(); 266 unregisterImsProvisionCallback(); 267 mHandlerThread.quit(); 268 } 269 } 270 271 /* 272 * Register receivers to listen to the data changes. 273 */ registerReceivers()274 private void registerReceivers() { 275 logd("registerReceivers"); 276 IntentFilter filter = new IntentFilter(); 277 filter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED); 278 mContext.registerReceiver(mReceiver, filter, android.Manifest.permission.MODIFY_PHONE_STATE, 279 null, Context.RECEIVER_EXPORTED); 280 281 ContentResolver resolver = mContext.getContentResolver(); 282 if (resolver != null) { 283 // Listen to the mobile data content changed. 284 resolver.registerContentObserver( 285 Settings.Global.getUriFor(Settings.Global.MOBILE_DATA), false, 286 getMobileDataObserver()); 287 // Listen to the SIM info content changed. 288 resolver.registerContentObserver(Telephony.SimInfo.CONTENT_URI, false, 289 getSimInfoContentObserver()); 290 } 291 } 292 unregisterReceivers()293 private void unregisterReceivers() { 294 logd("unregisterReceivers"); 295 mContext.unregisterReceiver(mReceiver); 296 ContentResolver resolver = mContext.getContentResolver(); 297 if (resolver != null) { 298 resolver.unregisterContentObserver(getMobileDataObserver()); 299 resolver.unregisterContentObserver(getSimInfoContentObserver()); 300 } 301 } 302 registerImsProvisionCallback()303 private void registerImsProvisionCallback() { 304 if (mIsImsCallbackRegistered) { 305 logd("registerImsProvisionCallback: already registered."); 306 return; 307 } 308 309 logd("registerImsProvisionCallback"); 310 try { 311 // Register mmtel callback 312 if (mImsMmTelManager != null) { 313 mImsMmTelManager.registerImsRegistrationCallback(mHandlerExecutor, 314 mMmtelRegistrationCallback); 315 mImsMmTelManager.registerMmTelCapabilityCallback(mHandlerExecutor, 316 mMmtelCapabilityCallback); 317 } 318 319 // Register rcs callback 320 if (mImsRcsManager != null) { 321 mImsRcsManager.registerImsRegistrationCallback(mHandlerExecutor, 322 mRcsRegistrationCallback); 323 } 324 325 // Register provisioning changed callback 326 mProvisioningManager.registerProvisioningChangedCallback(mHandlerExecutor, 327 mProvisionChangedCallback); 328 329 // Set the IMS callback is registered. 330 mIsImsCallbackRegistered = true; 331 } catch (ImsException e) { 332 logw("registerImsProvisionCallback error: " + e); 333 // Unregister the callback 334 unregisterImsProvisionCallback(); 335 336 // Retry registering IMS callback only when the RCS is connected. 337 if (mIsRcsConnected) { 338 mHandler.sendRegisterImsContentChangedMessage(REGISTER_IMS_CHANGED_DELAY); 339 } 340 } 341 } 342 unregisterImsProvisionCallback()343 private void unregisterImsProvisionCallback() { 344 logd("unregisterImsProvisionCallback"); 345 346 // Unregister mmtel callback 347 if (mImsMmTelManager != null) { 348 try { 349 mImsMmTelManager.unregisterImsRegistrationCallback(mMmtelRegistrationCallback); 350 } catch (RuntimeException e) { 351 logw("unregister MMTel registration error: " + e.getMessage()); 352 } 353 try { 354 mImsMmTelManager.unregisterMmTelCapabilityCallback(mMmtelCapabilityCallback); 355 } catch (RuntimeException e) { 356 logw("unregister MMTel capability error: " + e.getMessage()); 357 } 358 } 359 360 // Unregister rcs callback 361 if (mImsRcsManager != null) { 362 try { 363 mImsRcsManager.unregisterImsRegistrationCallback(mRcsRegistrationCallback); 364 } catch (RuntimeException e) { 365 logw("unregister rcs capability error: " + e.getMessage()); 366 } 367 } 368 369 try { 370 // Unregister provisioning changed callback 371 mProvisioningManager.unregisterProvisioningChangedCallback(mProvisionChangedCallback); 372 } catch (RuntimeException e) { 373 logw("unregister provisioning callback error: " + e.getMessage()); 374 } 375 376 // Clear the IMS callback registered flag. 377 mIsImsCallbackRegistered = false; 378 } 379 380 @VisibleForTesting 381 public final BroadcastReceiver mReceiver = new BroadcastReceiver() { 382 @Override 383 public void onReceive(Context context, Intent intent) { 384 if (intent == null || intent.getAction() == null) return; 385 switch (intent.getAction()) { 386 case TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED: 387 int preferredMode = intent.getIntExtra(TelecomManager.EXTRA_TTY_PREFERRED_MODE, 388 TelecomManager.TTY_MODE_OFF); 389 handleTtyPreferredModeChanged(preferredMode); 390 break; 391 } 392 } 393 }; 394 getMobileDataObserver()395 private ContentObserver getMobileDataObserver() { 396 synchronized (mLock) { 397 if (mMobileDataObserver == null) { 398 mMobileDataObserver = new ContentObserver(new Handler(mHandler.getLooper())) { 399 @Override 400 public void onChange(boolean selfChange) { 401 boolean isEnabled = Settings.Global.getInt(mContext.getContentResolver(), 402 Settings.Global.MOBILE_DATA, 1) == 1; 403 handleMobileDataChanged(isEnabled); 404 } 405 }; 406 } 407 return mMobileDataObserver; 408 } 409 } 410 getSimInfoContentObserver()411 private ContentObserver getSimInfoContentObserver() { 412 synchronized (mLock) { 413 if (mSimInfoContentObserver == null) { 414 mSimInfoContentObserver = new ContentObserver(new Handler(mHandler.getLooper())) { 415 @Override 416 public void onChange(boolean selfChange) { 417 if (mImsMmTelManager == null) { 418 logw("SimInfo change error: MmTelManager is null"); 419 return; 420 } 421 422 try { 423 boolean isEnabled = mImsMmTelManager.isVtSettingEnabled(); 424 handleVtSettingChanged(isEnabled); 425 } catch (RuntimeException e) { 426 logw("SimInfo change error: " + e); 427 } 428 } 429 }; 430 } 431 return mSimInfoContentObserver; 432 } 433 } 434 getImsMmTelManager(int subId)435 private ImsMmTelManager getImsMmTelManager(int subId) { 436 try { 437 ImsManager imsManager = mContext.getSystemService( 438 android.telephony.ims.ImsManager.class); 439 return (imsManager == null) ? null : imsManager.getImsMmTelManager(subId); 440 } catch (IllegalArgumentException e) { 441 logw("getImsMmTelManager error: " + e.getMessage()); 442 return null; 443 } 444 } 445 getImsRcsManager(int subId)446 private ImsRcsManager getImsRcsManager(int subId) { 447 try { 448 ImsManager imsManager = mContext.getSystemService( 449 android.telephony.ims.ImsManager.class); 450 return (imsManager == null) ? null : imsManager.getImsRcsManager(subId); 451 } catch (IllegalArgumentException e) { 452 logw("getImsRcsManager error: " + e.getMessage()); 453 return null; 454 } 455 } 456 457 @VisibleForTesting 458 public final RegistrationManager.RegistrationCallback mRcsRegistrationCallback = 459 new RegistrationManager.RegistrationCallback() { 460 @Override 461 public void onRegistered(ImsRegistrationAttributes attributes) { 462 synchronized (mLock) { 463 logi("onRcsRegistered: " + attributes); 464 if (!mIsImsCallbackRegistered) return; 465 466 List<String> featureTagList = new ArrayList<>(attributes.getFeatureTags()); 467 int registrationTech = attributes.getRegistrationTechnology(); 468 469 mUceStatsWriter.setImsRegistrationFeatureTagStats( 470 mSubId, featureTagList, registrationTech); 471 handleImsRcsRegistered(attributes); 472 } 473 } 474 475 @Override 476 public void onUnregistered(ImsReasonInfo info) { 477 synchronized (mLock) { 478 logi("onRcsUnregistered: " + info); 479 if (!mIsImsCallbackRegistered) return; 480 mUceStatsWriter.setStoreCompleteImsRegistrationFeatureTagStats(mSubId); 481 handleImsRcsUnregistered(); 482 } 483 } 484 485 @Override 486 public void onSubscriberAssociatedUriChanged(Uri[] uris) { 487 synchronized (mLock) { 488 logi("onRcsSubscriberAssociatedUriChanged"); 489 handleRcsSubscriberAssociatedUriChanged(uris, false); 490 } 491 } 492 }; 493 494 @VisibleForTesting 495 public final RegistrationManager.RegistrationCallback mMmtelRegistrationCallback = 496 new RegistrationManager.RegistrationCallback() { 497 @Override 498 public void onRegistered(@TransportType int transportType) { 499 synchronized (mLock) { 500 String type = AccessNetworkConstants.transportTypeToString(transportType); 501 logi("onMmTelRegistered: " + type); 502 if (!mIsImsCallbackRegistered) return; 503 handleImsMmtelRegistered(transportType); 504 } 505 } 506 507 @Override 508 public void onUnregistered(ImsReasonInfo info) { 509 synchronized (mLock) { 510 logi("onMmTelUnregistered: " + info); 511 if (!mIsImsCallbackRegistered) return; 512 handleImsMmtelUnregistered(); 513 } 514 } 515 516 @Override 517 public void onSubscriberAssociatedUriChanged(Uri[] uris) { 518 synchronized (mLock) { 519 logi("onMmTelSubscriberAssociatedUriChanged"); 520 handleMmTelSubscriberAssociatedUriChanged(uris, false); 521 } 522 } 523 }; 524 525 @VisibleForTesting 526 public final ImsMmTelManager.CapabilityCallback mMmtelCapabilityCallback = 527 new CapabilityCallback() { 528 @Override 529 public void onCapabilitiesStatusChanged(MmTelCapabilities capabilities) { 530 if (capabilities == null) { 531 logw("onCapabilitiesStatusChanged: parameter is null"); 532 return; 533 } 534 synchronized (mLock) { 535 handleMmtelCapabilitiesStatusChanged(capabilities); 536 } 537 } 538 }; 539 540 @VisibleForTesting 541 public final ProvisioningManager.Callback mProvisionChangedCallback = 542 new ProvisioningManager.Callback() { 543 @Override 544 public void onProvisioningIntChanged(int item, int value) { 545 logi("onProvisioningIntChanged: item=" + item + ", value=" + value); 546 switch (item) { 547 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS: 548 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS: 549 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS: 550 handleProvisioningChanged(); 551 break; 552 case ProvisioningManager.KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS: 553 handlePublishThrottleChanged(value); 554 break; 555 } 556 } 557 }; 558 handleTtyPreferredModeChanged(int preferredMode)559 private void handleTtyPreferredModeChanged(int preferredMode) { 560 boolean isChanged = mCapabilityInfo.updateTtyPreferredMode(preferredMode); 561 logi("TTY preferred mode changed: " + preferredMode + ", isChanged=" + isChanged); 562 if (isChanged) { 563 mHandler.sendTriggeringPublishMessage( 564 PublishController.PUBLISH_TRIGGER_TTY_PREFERRED_CHANGE); 565 } 566 } 567 handleMobileDataChanged(boolean isEnabled)568 private void handleMobileDataChanged(boolean isEnabled) { 569 boolean isChanged = mCapabilityInfo.updateMobileData(isEnabled); 570 logi("Mobile data changed: " + isEnabled + ", isChanged=" + isChanged); 571 if (isChanged) { 572 mHandler.sendTriggeringPublishMessage( 573 PublishController.PUBLISH_TRIGGER_MOBILE_DATA_CHANGE); 574 } 575 } 576 handleVtSettingChanged(boolean isEnabled)577 private void handleVtSettingChanged(boolean isEnabled) { 578 boolean isChanged = mCapabilityInfo.updateVtSetting(isEnabled); 579 logi("VT setting changed: " + isEnabled + ", isChanged=" + isChanged); 580 if (isChanged) { 581 mHandler.sendTriggeringPublishMessage( 582 PublishController.PUBLISH_TRIGGER_VT_SETTING_CHANGE); 583 } 584 } 585 586 /* 587 * This method is called when the MMTEL is registered. 588 */ handleImsMmtelRegistered(int imsTransportType)589 private void handleImsMmtelRegistered(int imsTransportType) { 590 // update capability, but not trigger PUBLISH message. 591 // PUBLISH message will be sent when the Capability status changed callback is called. 592 mCapabilityInfo.updateImsMmtelRegistered(imsTransportType); 593 } 594 595 /* 596 * This method is called when the MMTEL is unregistered. 597 */ handleImsMmtelUnregistered()598 private void handleImsMmtelUnregistered() { 599 boolean hasChanged = mCapabilityInfo.updateImsMmtelUnregistered(); 600 // When the MMTEL is unregistered, the mmtel associated uri should be cleared. 601 handleMmTelSubscriberAssociatedUriChanged(null, hasChanged); 602 603 // If the RCS is already unregistered, it informs that the IMS is unregistered. 604 if (mCapabilityInfo.isImsRegistered() == false) { 605 mHandler.sendImsUnregisteredMessage(); 606 } 607 } 608 609 /* 610 * This method is called when the MMTEL associated uri has changed. 611 */ handleMmTelSubscriberAssociatedUriChanged(Uri[] uris, boolean regiChanged)612 private void handleMmTelSubscriberAssociatedUriChanged(Uri[] uris, boolean regiChanged) { 613 Uri originalUri = mCapabilityInfo.getMmtelAssociatedUri(); 614 mCapabilityInfo.updateMmTelAssociatedUri(uris); 615 Uri currentUri = mCapabilityInfo.getMmtelAssociatedUri(); 616 617 boolean hasChanged = regiChanged || !(Objects.equals(originalUri, currentUri)); 618 619 logi("handleMmTelSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); 620 621 // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. 622 if (mCapabilityInfo.isImsRegistered() && hasChanged) { 623 mHandler.sendTriggeringPublishMessage( 624 PublishController.PUBLISH_TRIGGER_MMTEL_URI_CHANGE); 625 } 626 } 627 handleMmtelCapabilitiesStatusChanged(MmTelCapabilities capabilities)628 private void handleMmtelCapabilitiesStatusChanged(MmTelCapabilities capabilities) { 629 boolean isChanged = mCapabilityInfo.updateMmtelCapabilitiesChanged(capabilities); 630 logi("MMTel capabilities status changed: isChanged=" + isChanged); 631 if (isChanged) { 632 mHandler.sendTriggeringPublishMessage( 633 PublishController.PUBLISH_TRIGGER_MMTEL_CAPABILITY_CHANGE); 634 } 635 } 636 637 /* 638 * This method is called when RCS is registered. 639 */ handleImsRcsRegistered(ImsRegistrationAttributes attr)640 private void handleImsRcsRegistered(ImsRegistrationAttributes attr) { 641 if (mCapabilityInfo.updateImsRcsRegistered(attr)) { 642 mHandler.sendTriggeringPublishMessage(PublishController.PUBLISH_TRIGGER_RCS_REGISTERED); 643 } 644 } 645 646 /* 647 * This method is called when RCS is unregistered. 648 */ handleImsRcsUnregistered()649 private void handleImsRcsUnregistered() { 650 boolean hasChanged = mCapabilityInfo.updateImsRcsUnregistered(); 651 // When the RCS is unregistered, the rcs associated uri should be cleared. 652 handleRcsSubscriberAssociatedUriChanged(null, hasChanged); 653 // If the MMTEL is already unregistered, it informs that the IMS is unregistered. 654 if (mCapabilityInfo.isImsRegistered() == false) { 655 mHandler.sendImsUnregisteredMessage(); 656 } 657 } 658 659 /* 660 * This method is called when the RCS associated uri has changed. 661 */ handleRcsSubscriberAssociatedUriChanged(Uri[] uris, boolean regiChanged)662 private void handleRcsSubscriberAssociatedUriChanged(Uri[] uris, boolean regiChanged) { 663 Uri originalUri = mCapabilityInfo.getRcsAssociatedUri(); 664 mCapabilityInfo.updateRcsAssociatedUri(uris); 665 Uri currentUri = mCapabilityInfo.getRcsAssociatedUri(); 666 667 boolean hasChanged = regiChanged || !(Objects.equals(originalUri, currentUri)); 668 669 logi("handleRcsSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); 670 671 // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. 672 if (mCapabilityInfo.isImsRegistered() && hasChanged) { 673 mHandler.sendTriggeringPublishMessage(PublishController.PUBLISH_TRIGGER_RCS_URI_CHANGE); 674 } 675 } 676 677 /* 678 * This method is called when the provisioning is changed 679 */ handleProvisioningChanged()680 private void handleProvisioningChanged() { 681 mHandler.sendTriggeringPublishMessage( 682 PublishController.PUBLISH_TRIGGER_PROVISIONING_CHANGE); 683 } 684 685 /* 686 * Update the publish throttle. 687 */ handlePublishThrottleChanged(int value)688 private void handlePublishThrottleChanged(int value) { 689 mCallback.updatePublishThrottle(value); 690 } 691 692 @VisibleForTesting getHandler()693 public Handler getHandler() { 694 return mHandler; 695 } 696 697 @VisibleForTesting setImsMmTelManagerFactory(ImsMmTelManagerFactory factory)698 public void setImsMmTelManagerFactory(ImsMmTelManagerFactory factory) { 699 mImsMmTelManagerFactory = factory; 700 } 701 702 @VisibleForTesting setImsRcsManagerFactory(ImsRcsManagerFactory factory)703 public void setImsRcsManagerFactory(ImsRcsManagerFactory factory) { 704 mImsRcsManagerFactory = factory; 705 } 706 707 @VisibleForTesting setProvisioningMgrFactory(ProvisioningManagerFactory factory)708 public void setProvisioningMgrFactory(ProvisioningManagerFactory factory) { 709 mProvisioningMgrFactory = factory; 710 } 711 712 @VisibleForTesting setImsCallbackRegistered(boolean registered)713 public void setImsCallbackRegistered(boolean registered) { 714 mIsImsCallbackRegistered = registered; 715 } 716 logd(String log)717 private void logd(String log) { 718 Log.d(LOG_TAG, getLogPrefix().append(log).toString()); 719 mLocalLog.log("[D] " + log); 720 } 721 logi(String log)722 private void logi(String log) { 723 Log.i(LOG_TAG, getLogPrefix().append(log).toString()); 724 mLocalLog.log("[I] " + log); 725 } 726 logw(String log)727 private void logw(String log) { 728 Log.w(LOG_TAG, getLogPrefix().append(log).toString()); 729 mLocalLog.log("[W] " + log); 730 } 731 getLogPrefix()732 private StringBuilder getLogPrefix() { 733 StringBuilder builder = new StringBuilder("["); 734 builder.append(mSubId); 735 builder.append("] "); 736 return builder; 737 } 738 dump(PrintWriter printWriter)739 public void dump(PrintWriter printWriter) { 740 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 741 pw.println("DeviceCapListener" + "[subId: " + mSubId + "]:"); 742 pw.increaseIndent(); 743 744 mCapabilityInfo.dump(pw); 745 746 pw.println("Log:"); 747 pw.increaseIndent(); 748 mLocalLog.dump(pw); 749 pw.decreaseIndent(); 750 pw.println("---"); 751 752 pw.decreaseIndent(); 753 } 754 } 755