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