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; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.Context; 23 import android.net.Uri; 24 import android.os.HandlerThread; 25 import android.os.Looper; 26 import android.os.RemoteException; 27 import android.telephony.ims.RcsContactUceCapability; 28 import android.telephony.ims.RcsContactUceCapability.CapabilityMechanism; 29 import android.telephony.ims.RcsUceAdapter; 30 import android.telephony.ims.RcsUceAdapter.PublishState; 31 import android.telephony.ims.RcsUceAdapter.StackPublishTriggerType; 32 import android.telephony.ims.SipDetails; 33 import android.telephony.ims.aidl.IOptionsRequestCallback; 34 import android.telephony.ims.aidl.IRcsUceControllerCallback; 35 import android.telephony.ims.aidl.IRcsUcePublishStateCallback; 36 import android.util.IndentingPrintWriter; 37 import android.util.LocalLog; 38 import android.util.Log; 39 40 import com.android.ims.RcsFeatureManager; 41 import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; 42 import com.android.ims.rcs.uce.eab.EabCapabilityResult; 43 import com.android.ims.rcs.uce.eab.EabController; 44 import com.android.ims.rcs.uce.eab.EabControllerImpl; 45 import com.android.ims.rcs.uce.options.OptionsController; 46 import com.android.ims.rcs.uce.options.OptionsControllerImpl; 47 import com.android.ims.rcs.uce.presence.publish.PublishController; 48 import com.android.ims.rcs.uce.presence.publish.PublishControllerImpl; 49 import com.android.ims.rcs.uce.presence.subscribe.SubscribeController; 50 import com.android.ims.rcs.uce.presence.subscribe.SubscribeControllerImpl; 51 import com.android.ims.rcs.uce.request.UceRequestManager; 52 import com.android.ims.rcs.uce.util.UceUtils; 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.internal.os.SomeArgs; 55 56 import java.io.PrintWriter; 57 import java.lang.annotation.Retention; 58 import java.lang.annotation.RetentionPolicy; 59 import java.util.HashMap; 60 import java.util.List; 61 import java.util.Map; 62 import java.util.Optional; 63 import java.util.Set; 64 65 /** 66 * The UceController will manage the RCS UCE requests on a per subscription basis. When it receives 67 * the UCE requests from the RCS applications and from the ImsService, it will coordinate the 68 * cooperation between the publish/subscribe/options components to complete the requests. 69 */ 70 public class UceController { 71 72 private static final String LOG_TAG = UceUtils.getLogPrefix() + "UceController"; 73 74 /** 75 * The callback interface is called by the internal controllers to receive information from 76 * others controllers. 77 */ 78 public interface UceControllerCallback { 79 /** 80 * Retrieve the capabilities associated with the given uris from the cache. 81 */ getCapabilitiesFromCache(@onNull List<Uri> uris)82 List<EabCapabilityResult> getCapabilitiesFromCache(@NonNull List<Uri> uris); 83 84 /** 85 * Retrieve the capabilities associated with the given uris from the cache including 86 * expired capabilities. 87 */ getCapabilitiesFromCacheIncludingExpired(@onNull List<Uri> uris)88 List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(@NonNull List<Uri> uris); 89 90 /** 91 * Retrieve the contact's capabilities from the availability cache. 92 */ getAvailabilityFromCache(@onNull Uri uri)93 EabCapabilityResult getAvailabilityFromCache(@NonNull Uri uri); 94 95 /** 96 * Retrieve the contact's capabilities from the availability cache including expired 97 * capabilities 98 */ getAvailabilityFromCacheIncludingExpired(@onNull Uri uri)99 EabCapabilityResult getAvailabilityFromCacheIncludingExpired(@NonNull Uri uri); 100 101 /** 102 * Store the given capabilities to the cache. 103 */ saveCapabilities(List<RcsContactUceCapability> contactCapabilities)104 void saveCapabilities(List<RcsContactUceCapability> contactCapabilities); 105 106 /** 107 * Retrieve the device's capabilities. 108 */ getDeviceCapabilities(@apabilityMechanism int mechanism)109 RcsContactUceCapability getDeviceCapabilities(@CapabilityMechanism int mechanism); 110 111 /** 112 * Refresh the device state. It is called when receive the UCE request response. 113 * @param sipCode The SIP code of the request response. 114 * @param reason The reason from the network response. 115 * @param type The type of the request 116 */ refreshDeviceState(int sipCode, String reason, @RequestType int type)117 void refreshDeviceState(int sipCode, String reason, @RequestType int type); 118 119 /** 120 * Reset the device state when then device disallowed state is expired. 121 */ resetDeviceState()122 void resetDeviceState(); 123 124 /** 125 * Get the current device state to check if the device is allowed to send UCE requests. 126 */ getDeviceState()127 DeviceStateResult getDeviceState(); 128 129 /** 130 * Setup timer to exit device disallowed state. 131 */ setupResetDeviceStateTimer(long resetAfterSec)132 void setupResetDeviceStateTimer(long resetAfterSec); 133 134 /** 135 * The device state is already reset, clear the timer. 136 */ clearResetDeviceStateTimer()137 void clearResetDeviceStateTimer(); 138 139 /** 140 * The method is called when the given contacts' capabilities are expired and need to be 141 * refreshed. 142 */ refreshCapabilities(@onNull List<Uri> contactNumbers, @NonNull IRcsUceControllerCallback callback)143 void refreshCapabilities(@NonNull List<Uri> contactNumbers, 144 @NonNull IRcsUceControllerCallback callback) throws RemoteException; 145 } 146 147 /** 148 * Used to inject RequestManger instances for testing. 149 */ 150 @VisibleForTesting 151 public interface RequestManagerFactory { createRequestManager(Context context, int subId, Looper looper, UceControllerCallback callback)152 UceRequestManager createRequestManager(Context context, int subId, Looper looper, 153 UceControllerCallback callback); 154 } 155 156 private RequestManagerFactory mRequestManagerFactory = (context, subId, looper, callback) -> 157 new UceRequestManager(context, subId, looper, callback); 158 159 /** 160 * Used to inject Controller instances for testing. 161 */ 162 @VisibleForTesting 163 public interface ControllerFactory { 164 /** 165 * @return an {@link EabController} associated with the subscription id specified. 166 */ createEabController(Context context, int subId, UceControllerCallback c, Looper looper)167 EabController createEabController(Context context, int subId, UceControllerCallback c, 168 Looper looper); 169 170 /** 171 * @return an {@link PublishController} associated with the subscription id specified. 172 */ createPublishController(Context context, int subId, UceControllerCallback c, Looper looper)173 PublishController createPublishController(Context context, int subId, 174 UceControllerCallback c, Looper looper); 175 176 /** 177 * @return an {@link SubscribeController} associated with the subscription id specified. 178 */ createSubscribeController(Context context, int subId)179 SubscribeController createSubscribeController(Context context, int subId); 180 181 /** 182 * @return an {@link OptionsController} associated with the subscription id specified. 183 */ createOptionsController(Context context, int subId)184 OptionsController createOptionsController(Context context, int subId); 185 } 186 187 private ControllerFactory mControllerFactory = new ControllerFactory() { 188 @Override 189 public EabController createEabController(Context context, int subId, 190 UceControllerCallback c, Looper looper) { 191 return new EabControllerImpl(context, subId, c, looper); 192 } 193 194 @Override 195 public PublishController createPublishController(Context context, int subId, 196 UceControllerCallback c, Looper looper) { 197 return new PublishControllerImpl(context, subId, c, looper); 198 } 199 200 @Override 201 public SubscribeController createSubscribeController(Context context, int subId) { 202 return new SubscribeControllerImpl(context, subId); 203 } 204 205 @Override 206 public OptionsController createOptionsController(Context context, int subId) { 207 return new OptionsControllerImpl(context, subId); 208 } 209 }; 210 211 /** 212 * Cache the capabilities events triggered by the ImsService during the RCS connected procedure. 213 */ 214 private static class CachedCapabilityEvent { 215 private Optional<Integer> mRequestPublishCapabilitiesEvent; 216 private Optional<Boolean> mUnpublishEvent; 217 private Optional<SipDetails> mPublishUpdatedEvent; 218 private Optional<SomeArgs> mRemoteCapabilityRequestEvent; 219 CachedCapabilityEvent()220 public CachedCapabilityEvent() { 221 mRequestPublishCapabilitiesEvent = Optional.empty(); 222 mUnpublishEvent = Optional.empty(); 223 mPublishUpdatedEvent = Optional.empty(); 224 mRemoteCapabilityRequestEvent = Optional.empty(); 225 } 226 227 /** 228 * Cache the publish capabilities request event triggered by the ImsService. 229 */ setRequestPublishCapabilitiesEvent(int triggerType)230 public synchronized void setRequestPublishCapabilitiesEvent(int triggerType) { 231 mRequestPublishCapabilitiesEvent = Optional.of(triggerType); 232 } 233 234 /** 235 * Cache the unpublish event triggered by the ImsService. 236 */ setOnUnpublishEvent()237 public synchronized void setOnUnpublishEvent() { 238 mUnpublishEvent = Optional.of(Boolean.TRUE); 239 } 240 241 /** 242 * Cache the publish update event triggered by the ImsService. 243 */ setOnPublishUpdatedEvent(SipDetails details)244 public synchronized void setOnPublishUpdatedEvent(SipDetails details) { 245 mPublishUpdatedEvent = Optional.of(details); 246 } 247 248 /** 249 * Cache the remote capability request event triggered by the ImsService. 250 */ setRemoteCapabilityRequestEvent(Uri contactUri, List<String> remoteCapabilities, IOptionsRequestCallback callback)251 public synchronized void setRemoteCapabilityRequestEvent(Uri contactUri, 252 List<String> remoteCapabilities, IOptionsRequestCallback callback) { 253 SomeArgs args = SomeArgs.obtain(); 254 args.arg1 = contactUri; 255 args.arg2 = remoteCapabilities; 256 args.arg3 = callback; 257 mRemoteCapabilityRequestEvent = Optional.of(args); 258 } 259 260 /** @Return the cached publish request event */ getRequestPublishEvent()261 public synchronized Optional<Integer> getRequestPublishEvent() { 262 return mRequestPublishCapabilitiesEvent; 263 } 264 265 /** @Return the cached unpublish event */ getUnpublishEvent()266 public synchronized Optional<Boolean> getUnpublishEvent() { 267 return mUnpublishEvent; 268 } 269 270 /** @Return the cached pubilsh update event */ getPublishUpdatedEvent()271 public synchronized Optional<SipDetails> getPublishUpdatedEvent() { 272 return mPublishUpdatedEvent; 273 } 274 275 /** @Return the cached remote capability request event */ getRemoteCapabilityRequestEvent()276 public synchronized Optional<SomeArgs> getRemoteCapabilityRequestEvent() { 277 return mRemoteCapabilityRequestEvent; 278 } 279 280 /** Clear the cached */ clear()281 public synchronized void clear() { 282 mRequestPublishCapabilitiesEvent = Optional.empty(); 283 mUnpublishEvent = Optional.empty(); 284 mPublishUpdatedEvent = Optional.empty(); 285 mRemoteCapabilityRequestEvent.ifPresent(args -> args.recycle()); 286 mRemoteCapabilityRequestEvent = Optional.empty(); 287 } 288 } 289 290 /** 291 * The request type is PUBLISH. 292 */ 293 public static final int REQUEST_TYPE_PUBLISH = 1; 294 295 /** 296 * The request type is CAPABILITY. 297 */ 298 public static final int REQUEST_TYPE_CAPABILITY = 2; 299 300 @IntDef(value = { 301 REQUEST_TYPE_PUBLISH, 302 REQUEST_TYPE_CAPABILITY, 303 }, prefix="REQUEST_TYPE_") 304 @Retention(RetentionPolicy.SOURCE) 305 public @interface RequestType {} 306 307 public static final Map<Integer, String> REQUEST_TYPE_DESCRIPTION = new HashMap<>(); 308 static { REQUEST_TYPE_DESCRIPTION.put(REQUEST_TYPE_PUBLISH, "REQUEST_TYPE_PUBLISH")309 REQUEST_TYPE_DESCRIPTION.put(REQUEST_TYPE_PUBLISH, "REQUEST_TYPE_PUBLISH"); REQUEST_TYPE_DESCRIPTION.put(REQUEST_TYPE_CAPABILITY, "REQUEST_TYPE_CAPABILITY")310 REQUEST_TYPE_DESCRIPTION.put(REQUEST_TYPE_CAPABILITY, "REQUEST_TYPE_CAPABILITY"); 311 } 312 313 /** The RCS state is disconnected */ 314 private static final int RCS_STATE_DISCONNECTED = 0; 315 316 /** The RCS state is connecting */ 317 private static final int RCS_STATE_CONNECTING = 1; 318 319 /** The RCS state is connected */ 320 private static final int RCS_STATE_CONNECTED = 2; 321 322 @IntDef(value = { 323 RCS_STATE_DISCONNECTED, 324 RCS_STATE_CONNECTING, 325 RCS_STATE_CONNECTED, 326 }, prefix="RCS_STATE_") 327 @Retention(RetentionPolicy.SOURCE) 328 @interface RcsConnectedState {} 329 330 private final int mSubId; 331 private final Context mContext; 332 private final LocalLog mLocalLog = new LocalLog(UceUtils.LOG_SIZE); 333 334 private volatile Looper mLooper; 335 private volatile boolean mIsDestroyedFlag; 336 private volatile @RcsConnectedState int mRcsConnectedState; 337 338 private RcsFeatureManager mRcsFeatureManager; 339 private EabController mEabController; 340 private PublishController mPublishController; 341 private SubscribeController mSubscribeController; 342 private OptionsController mOptionsController; 343 private UceRequestManager mRequestManager; 344 // The device state to execute UCE requests. 345 private UceDeviceState mDeviceState; 346 // The cache of the capability request event triggered by ImsService 347 private final CachedCapabilityEvent mCachedCapabilityEvent; 348 UceController(Context context, int subId)349 public UceController(Context context, int subId) { 350 mSubId = subId; 351 mContext = context; 352 mCachedCapabilityEvent = new CachedCapabilityEvent(); 353 mRcsConnectedState = RCS_STATE_DISCONNECTED; 354 logi("create"); 355 356 initLooper(); 357 initControllers(); 358 initRequestManager(); 359 initUceDeviceState(); 360 } 361 362 @VisibleForTesting UceController(Context context, int subId, UceDeviceState deviceState, ControllerFactory controllerFactory, RequestManagerFactory requestManagerFactory)363 public UceController(Context context, int subId, UceDeviceState deviceState, 364 ControllerFactory controllerFactory, RequestManagerFactory requestManagerFactory) { 365 mSubId = subId; 366 mContext = context; 367 mDeviceState = deviceState; 368 mControllerFactory = controllerFactory; 369 mRequestManagerFactory = requestManagerFactory; 370 mCachedCapabilityEvent = new CachedCapabilityEvent(); 371 mRcsConnectedState = RCS_STATE_DISCONNECTED; 372 initLooper(); 373 initControllers(); 374 initRequestManager(); 375 } 376 initLooper()377 private void initLooper() { 378 // Init the looper, it will be passed to each controller. 379 HandlerThread handlerThread = new HandlerThread("UceControllerHandlerThread"); 380 handlerThread.start(); 381 mLooper = handlerThread.getLooper(); 382 } 383 initControllers()384 private void initControllers() { 385 mEabController = mControllerFactory.createEabController(mContext, mSubId, mCtrlCallback, 386 mLooper); 387 mPublishController = mControllerFactory.createPublishController(mContext, mSubId, 388 mCtrlCallback, mLooper); 389 mSubscribeController = mControllerFactory.createSubscribeController(mContext, mSubId); 390 mOptionsController = mControllerFactory.createOptionsController(mContext, mSubId); 391 } 392 initRequestManager()393 private void initRequestManager() { 394 mRequestManager = mRequestManagerFactory.createRequestManager(mContext, mSubId, mLooper, 395 mCtrlCallback); 396 mRequestManager.setSubscribeController(mSubscribeController); 397 mRequestManager.setOptionsController(mOptionsController); 398 } 399 initUceDeviceState()400 private void initUceDeviceState() { 401 mDeviceState = new UceDeviceState(mSubId, mContext, mCtrlCallback); 402 mDeviceState.checkSendResetDeviceStateTimer(); 403 } 404 405 /** 406 * The RcsFeature has been connected to the framework. This method runs on main thread. 407 */ onRcsConnected(RcsFeatureManager manager)408 public void onRcsConnected(RcsFeatureManager manager) { 409 logi("onRcsConnected"); 410 // Set the RCS is connecting flag 411 mRcsConnectedState = RCS_STATE_CONNECTING; 412 413 // Listen to the capability exchange event which is triggered by the ImsService 414 mRcsFeatureManager = manager; 415 mRcsFeatureManager.addCapabilityEventCallback(mCapabilityEventListener); 416 417 // Notify each controllers that RCS is connected. 418 mEabController.onRcsConnected(manager); 419 mPublishController.onRcsConnected(manager); 420 mSubscribeController.onRcsConnected(manager); 421 mOptionsController.onRcsConnected(manager); 422 423 // Set the RCS is connected flag and check if there is any capability event received during 424 // the connecting process. 425 mRcsConnectedState = RCS_STATE_CONNECTED; 426 handleCachedCapabilityEvent(); 427 } 428 429 /** 430 * The framework has lost the binding to the RcsFeature. This method runs on main thread. 431 */ onRcsDisconnected()432 public void onRcsDisconnected() { 433 logi("onRcsDisconnected"); 434 mRcsConnectedState = RCS_STATE_DISCONNECTED; 435 // Remove the listener because RCS is disconnected. 436 if (mRcsFeatureManager != null) { 437 mRcsFeatureManager.removeCapabilityEventCallback(mCapabilityEventListener); 438 mRcsFeatureManager = null; 439 } 440 // Notify each controllers that RCS is disconnected. 441 mEabController.onRcsDisconnected(); 442 mPublishController.onRcsDisconnected(); 443 mSubscribeController.onRcsDisconnected(); 444 mOptionsController.onRcsDisconnected(); 445 } 446 447 /** 448 * Notify to destroy this instance. This instance is unusable after destroyed. 449 */ onDestroy()450 public void onDestroy() { 451 logi("onDestroy"); 452 mIsDestroyedFlag = true; 453 // Remove the listener because the UceController instance is destroyed. 454 if (mRcsFeatureManager != null) { 455 mRcsFeatureManager.removeCapabilityEventCallback(mCapabilityEventListener); 456 mRcsFeatureManager = null; 457 } 458 // Destroy all the controllers 459 mRequestManager.onDestroy(); 460 mEabController.onDestroy(); 461 mPublishController.onDestroy(); 462 mSubscribeController.onDestroy(); 463 mOptionsController.onDestroy(); 464 465 // Execute all the existing requests before quitting the looper. 466 mLooper.quitSafely(); 467 } 468 469 /** 470 * Notify all associated classes that the carrier configuration has changed for the subId. 471 */ onCarrierConfigChanged()472 public void onCarrierConfigChanged() { 473 mEabController.onCarrierConfigChanged(); 474 mPublishController.onCarrierConfigChanged(); 475 mSubscribeController.onCarrierConfigChanged(); 476 mOptionsController.onCarrierConfigChanged(); 477 } 478 handleCachedCapabilityEvent()479 private void handleCachedCapabilityEvent() { 480 Optional<Integer> requestPublishEvent = mCachedCapabilityEvent.getRequestPublishEvent(); 481 requestPublishEvent.ifPresent(triggerType -> 482 onRequestPublishCapabilitiesFromService(triggerType)); 483 484 Optional<Boolean> unpublishEvent = mCachedCapabilityEvent.getUnpublishEvent(); 485 unpublishEvent.ifPresent(unpublish -> onUnpublish()); 486 487 Optional<SipDetails> publishUpdatedEvent = mCachedCapabilityEvent.getPublishUpdatedEvent(); 488 publishUpdatedEvent.ifPresent(details -> 489 onPublishUpdated(details)); 490 491 Optional<SomeArgs> remoteRequest = mCachedCapabilityEvent.getRemoteCapabilityRequestEvent(); 492 remoteRequest.ifPresent(args -> { 493 Uri contactUri = (Uri) args.arg1; 494 List<String> remoteCapabilities = (List<String>) args.arg2; 495 IOptionsRequestCallback callback = (IOptionsRequestCallback) args.arg3; 496 retrieveOptionsCapabilitiesForRemote(contactUri, remoteCapabilities, callback); 497 }); 498 mCachedCapabilityEvent.clear(); 499 } 500 501 /* 502 * The implementation of the interface UceControllerCallback. These methods are called by other 503 * controllers. 504 */ 505 private UceControllerCallback mCtrlCallback = new UceControllerCallback() { 506 @Override 507 public List<EabCapabilityResult> getCapabilitiesFromCache(List<Uri> uris) { 508 return mEabController.getCapabilities(uris); 509 } 510 511 @Override 512 public List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(List<Uri> uris) { 513 return mEabController.getCapabilitiesIncludingExpired(uris); 514 } 515 516 @Override 517 public EabCapabilityResult getAvailabilityFromCache(Uri contactUri) { 518 return mEabController.getAvailability(contactUri); 519 } 520 521 @Override 522 public EabCapabilityResult getAvailabilityFromCacheIncludingExpired(Uri contactUri) { 523 return mEabController.getAvailabilityIncludingExpired(contactUri); 524 } 525 526 @Override 527 public void saveCapabilities(List<RcsContactUceCapability> contactCapabilities) { 528 mEabController.saveCapabilities(contactCapabilities); 529 } 530 531 @Override 532 public RcsContactUceCapability getDeviceCapabilities(@CapabilityMechanism int mechanism) { 533 return mPublishController.getDeviceCapabilities(mechanism); 534 } 535 536 @Override 537 public void refreshDeviceState(int sipCode, String reason, @RequestType int type) { 538 mDeviceState.refreshDeviceState(sipCode, reason, type); 539 } 540 541 @Override 542 public void resetDeviceState() { 543 mDeviceState.resetDeviceState(); 544 } 545 546 @Override 547 public DeviceStateResult getDeviceState() { 548 return mDeviceState.getCurrentState(); 549 } 550 551 @Override 552 public void setupResetDeviceStateTimer(long resetAfterSec) { 553 mPublishController.setupResetDeviceStateTimer(resetAfterSec); 554 } 555 556 @Override 557 public void clearResetDeviceStateTimer() { 558 mPublishController.clearResetDeviceStateTimer(); 559 } 560 561 @Override 562 public void refreshCapabilities(@NonNull List<Uri> contactNumbers, 563 @NonNull IRcsUceControllerCallback callback) throws RemoteException{ 564 logd("refreshCapabilities: " + contactNumbers.size()); 565 UceController.this.requestCapabilitiesInternal(contactNumbers, true, callback); 566 } 567 }; 568 569 @VisibleForTesting setUceControllerCallback(UceControllerCallback callback)570 public void setUceControllerCallback(UceControllerCallback callback) { 571 mCtrlCallback = callback; 572 } 573 574 /* 575 * Setup the listener to listen to the requests and updates from ImsService. 576 */ 577 private RcsFeatureManager.CapabilityExchangeEventCallback mCapabilityEventListener = 578 new RcsFeatureManager.CapabilityExchangeEventCallback() { 579 @Override 580 public void onRequestPublishCapabilities( 581 @StackPublishTriggerType int triggerType) { 582 if (isRcsConnecting()) { 583 mCachedCapabilityEvent.setRequestPublishCapabilitiesEvent(triggerType); 584 return; 585 } 586 onRequestPublishCapabilitiesFromService(triggerType); 587 } 588 589 @Override 590 public void onUnpublish() { 591 if (isRcsConnecting()) { 592 mCachedCapabilityEvent.setOnUnpublishEvent(); 593 return; 594 } 595 UceController.this.onUnpublish(); 596 } 597 598 @Override 599 public void onPublishUpdated(@NonNull SipDetails details) { 600 if (isRcsConnecting()) { 601 mCachedCapabilityEvent.setOnPublishUpdatedEvent(details); 602 return; 603 } 604 UceController.this.onPublishUpdated(details); 605 } 606 607 @Override 608 public void onRemoteCapabilityRequest(Uri contactUri, 609 List<String> remoteCapabilities, IOptionsRequestCallback cb) { 610 if (contactUri == null || remoteCapabilities == null || cb == null) { 611 logw("onRemoteCapabilityRequest: parameter cannot be null"); 612 return; 613 } 614 if (isRcsConnecting()) { 615 mCachedCapabilityEvent.setRemoteCapabilityRequestEvent(contactUri, 616 remoteCapabilities, cb); 617 return; 618 } 619 retrieveOptionsCapabilitiesForRemote(contactUri, remoteCapabilities, cb); 620 } 621 }; 622 623 /** 624 * Request to get the contacts' capabilities. This method will retrieve the capabilities from 625 * the cache If the capabilities are out of date, it will trigger another request to get the 626 * latest contact's capabilities from the network. 627 */ requestCapabilities(@onNull List<Uri> uriList, @NonNull IRcsUceControllerCallback c)628 public void requestCapabilities(@NonNull List<Uri> uriList, 629 @NonNull IRcsUceControllerCallback c) throws RemoteException { 630 requestCapabilitiesInternal(uriList, false, c); 631 } 632 requestCapabilitiesInternal(@onNull List<Uri> uriList, boolean skipFromCache, @NonNull IRcsUceControllerCallback c)633 private void requestCapabilitiesInternal(@NonNull List<Uri> uriList, boolean skipFromCache, 634 @NonNull IRcsUceControllerCallback c) throws RemoteException { 635 if (uriList == null || uriList.isEmpty() || c == null) { 636 logw("requestCapabilities: parameter is empty"); 637 if (c != null) { 638 c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); 639 } 640 return; 641 } 642 643 if (isUnavailable()) { 644 logw("requestCapabilities: controller is unavailable"); 645 c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); 646 return; 647 } 648 649 // Return if the device is not allowed to execute UCE requests. 650 DeviceStateResult deviceStateResult = mDeviceState.getCurrentState(); 651 if (deviceStateResult.isRequestForbidden()) { 652 int deviceState = deviceStateResult.getDeviceState(); 653 int errorCode = deviceStateResult.getErrorCode() 654 .orElse(RcsUceAdapter.ERROR_GENERIC_FAILURE); 655 long retryAfterMillis = deviceStateResult.getRequestRetryAfterMillis(); 656 logw("requestCapabilities: The device is disallowed, deviceState= " + deviceState + 657 ", errorCode=" + errorCode + ", retryAfterMillis=" + retryAfterMillis); 658 c.onError(errorCode, retryAfterMillis, null); 659 return; 660 } 661 662 // Trigger the capabilities request task 663 logd("requestCapabilities: size=" + uriList.size()); 664 mRequestManager.sendCapabilityRequest(uriList, skipFromCache, c); 665 } 666 667 /** 668 * Request to get the contact's capabilities. It will check the availability cache first. If 669 * the capability in the availability cache is expired then it will retrieve the capability 670 * from the network. 671 */ requestAvailability(@onNull Uri uri, @NonNull IRcsUceControllerCallback c)672 public void requestAvailability(@NonNull Uri uri, @NonNull IRcsUceControllerCallback c) 673 throws RemoteException { 674 if (uri == null || c == null) { 675 logw("requestAvailability: parameter is empty"); 676 if (c != null) { 677 c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); 678 } 679 return; 680 } 681 682 if (isUnavailable()) { 683 logw("requestAvailability: controller is unavailable"); 684 c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); 685 return; 686 } 687 688 // Return if the device is not allowed to execute UCE requests. 689 DeviceStateResult deviceStateResult = mDeviceState.getCurrentState(); 690 if (deviceStateResult.isRequestForbidden()) { 691 int deviceState = deviceStateResult.getDeviceState(); 692 int errorCode = deviceStateResult.getErrorCode() 693 .orElse(RcsUceAdapter.ERROR_GENERIC_FAILURE); 694 long retryAfterMillis = deviceStateResult.getRequestRetryAfterMillis(); 695 logw("requestAvailability: The device is disallowed, deviceState= " + deviceState + 696 ", errorCode=" + errorCode + ", retryAfterMillis=" + retryAfterMillis); 697 c.onError(errorCode, retryAfterMillis, null); 698 return; 699 } 700 701 // Trigger the availability request task 702 logd("requestAvailability"); 703 mRequestManager.sendAvailabilityRequest(uri, c); 704 } 705 706 /** 707 * Publish the device's capabilities. This request is triggered from the ImsService. 708 */ onRequestPublishCapabilitiesFromService(@tackPublishTriggerType int triggerType)709 public void onRequestPublishCapabilitiesFromService(@StackPublishTriggerType int triggerType) { 710 logd("onRequestPublishCapabilitiesFromService: " + triggerType); 711 // Reset the device state when the service triggers to publish the device's capabilities 712 mDeviceState.resetDeviceState(); 713 // Send the publish request. 714 mPublishController.requestPublishCapabilitiesFromService(triggerType); 715 } 716 717 /** 718 * This method is triggered by the ImsService to notify framework that the device's 719 * capabilities has been unpublished from the network. 720 */ onUnpublish()721 public void onUnpublish() { 722 logi("onUnpublish"); 723 mPublishController.onUnpublish(); 724 } 725 726 /** 727 * This method is triggered by the ImsService to notify framework that the device's 728 * publish status has been changed. 729 */ onPublishUpdated(@onNull SipDetails details)730 public void onPublishUpdated(@NonNull SipDetails details) { 731 logi("onPublishUpdated"); 732 mPublishController.onPublishUpdated(details); 733 } 734 735 /** 736 * Request publish the device's capabilities. This request is from the ImsService to send the 737 * capabilities to the remote side. 738 */ retrieveOptionsCapabilitiesForRemote(@onNull Uri contactUri, @NonNull List<String> remoteCapabilities, @NonNull IOptionsRequestCallback c)739 public void retrieveOptionsCapabilitiesForRemote(@NonNull Uri contactUri, 740 @NonNull List<String> remoteCapabilities, @NonNull IOptionsRequestCallback c) { 741 logi("retrieveOptionsCapabilitiesForRemote"); 742 mRequestManager.retrieveCapabilitiesForRemote(contactUri, remoteCapabilities, c); 743 } 744 745 /** 746 * Register a {@link PublishStateCallback} to receive the published state changed. 747 */ registerPublishStateCallback(@onNull IRcsUcePublishStateCallback c, boolean supportPublishingState)748 public void registerPublishStateCallback(@NonNull IRcsUcePublishStateCallback c, 749 boolean supportPublishingState) { 750 mPublishController.registerPublishStateCallback(c, supportPublishingState); 751 } 752 753 /** 754 * Removes an existing {@link PublishStateCallback}. 755 */ unregisterPublishStateCallback(@onNull IRcsUcePublishStateCallback c)756 public void unregisterPublishStateCallback(@NonNull IRcsUcePublishStateCallback c) { 757 mPublishController.unregisterPublishStateCallback(c); 758 } 759 760 /** 761 * Get the UCE publish state if the PUBLISH is supported by the carrier. 762 */ getUcePublishState(boolean isSupportPublishingState)763 public @PublishState int getUcePublishState(boolean isSupportPublishingState) { 764 return mPublishController.getUcePublishState(isSupportPublishingState); 765 } 766 767 /** 768 * Add new feature tags to the Set used to calculate the capabilities in PUBLISH. 769 * <p> 770 * Used for testing ONLY. 771 * @return the new capabilities that will be used for PUBLISH. 772 */ addRegistrationOverrideCapabilities(Set<String> featureTags)773 public RcsContactUceCapability addRegistrationOverrideCapabilities(Set<String> featureTags) { 774 return mPublishController.addRegistrationOverrideCapabilities(featureTags); 775 } 776 777 /** 778 * Remove existing feature tags to the Set used to calculate the capabilities in PUBLISH. 779 * <p> 780 * Used for testing ONLY. 781 * @return the new capabilities that will be used for PUBLISH. 782 */ removeRegistrationOverrideCapabilities(Set<String> featureTags)783 public RcsContactUceCapability removeRegistrationOverrideCapabilities(Set<String> featureTags) { 784 return mPublishController.removeRegistrationOverrideCapabilities(featureTags); 785 } 786 787 /** 788 * Clear all overrides in the Set used to calculate the capabilities in PUBLISH. 789 * <p> 790 * Used for testing ONLY. 791 * @return the new capabilities that will be used for PUBLISH. 792 */ clearRegistrationOverrideCapabilities()793 public RcsContactUceCapability clearRegistrationOverrideCapabilities() { 794 return mPublishController.clearRegistrationOverrideCapabilities(); 795 } 796 797 /** 798 * @return current RcsContactUceCapability instance that will be used for PUBLISH. 799 */ getLatestRcsContactUceCapability()800 public RcsContactUceCapability getLatestRcsContactUceCapability() { 801 return mPublishController.getLatestRcsContactUceCapability(); 802 } 803 804 /** 805 * Get the PIDF XML associated with the last successful publish or null if not PUBLISHed to the 806 * network. 807 */ getLastPidfXml()808 public String getLastPidfXml() { 809 return mPublishController.getLastPidfXml(); 810 } 811 812 /** 813 * Remove the device disallowed state. 814 * <p> 815 * Used for testing ONLY. 816 */ removeRequestDisallowedStatus()817 public void removeRequestDisallowedStatus() { 818 logd("removeRequestDisallowedStatus"); 819 mDeviceState.resetDeviceState(); 820 mRequestManager.resetThrottlingList(); 821 } 822 823 /** 824 * Set the milliseconds of capabilities request timeout. 825 * <p> 826 * Used for testing ONLY. 827 */ setCapabilitiesRequestTimeout(long timeoutAfterMs)828 public void setCapabilitiesRequestTimeout(long timeoutAfterMs) { 829 logd("setCapabilitiesRequestTimeout: " + timeoutAfterMs); 830 UceUtils.setCapRequestTimeoutAfterMillis(timeoutAfterMs); 831 } 832 833 /** 834 * Get the subscription ID. 835 */ getSubId()836 public int getSubId() { 837 return mSubId; 838 } 839 840 /** 841 * Check if the UceController is available. 842 * @return true if RCS is connected without destroyed. 843 */ isUnavailable()844 public boolean isUnavailable() { 845 if (!isRcsConnected() || mIsDestroyedFlag) { 846 return true; 847 } 848 return false; 849 } 850 isRcsConnecting()851 private boolean isRcsConnecting() { 852 return mRcsConnectedState == RCS_STATE_CONNECTING; 853 } 854 isRcsConnected()855 private boolean isRcsConnected() { 856 return mRcsConnectedState == RCS_STATE_CONNECTED; 857 } 858 dump(PrintWriter printWriter)859 public void dump(PrintWriter printWriter) { 860 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 861 pw.println("UceController" + "[subId: " + mSubId + "]:"); 862 pw.increaseIndent(); 863 864 pw.println("Log:"); 865 pw.increaseIndent(); 866 mLocalLog.dump(pw); 867 pw.decreaseIndent(); 868 pw.println("---"); 869 870 mPublishController.dump(pw); 871 872 pw.decreaseIndent(); 873 } 874 logd(String log)875 private void logd(String log) { 876 Log.d(LOG_TAG, getLogPrefix().append(log).toString()); 877 mLocalLog.log("[D] " + log); 878 } 879 logi(String log)880 private void logi(String log) { 881 Log.i(LOG_TAG, getLogPrefix().append(log).toString()); 882 mLocalLog.log("[I] " + log); 883 } 884 logw(String log)885 private void logw(String log) { 886 Log.w(LOG_TAG, getLogPrefix().append(log).toString()); 887 mLocalLog.log("[W] " + log); 888 } 889 getLogPrefix()890 private StringBuilder getLogPrefix() { 891 StringBuilder builder = new StringBuilder("["); 892 builder.append(mSubId); 893 builder.append("] "); 894 return builder; 895 } 896 } 897