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