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