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