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.request; 18 19 import static com.android.ims.rcs.uce.request.UceRequest.REQUEST_TYPE_CAPABILITY; 20 21 import android.content.Context; 22 import android.net.Uri; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.os.Message; 26 import android.os.PersistableBundle; 27 import android.os.RemoteException; 28 import android.telephony.CarrierConfigManager; 29 import android.telephony.TelephonyManager; 30 import android.telephony.ims.RcsContactUceCapability; 31 import android.telephony.ims.RcsContactUceCapability.CapabilityMechanism; 32 import android.telephony.ims.RcsUceAdapter; 33 import android.telephony.ims.aidl.IOptionsRequestCallback; 34 import android.telephony.ims.aidl.IRcsUceControllerCallback; 35 import android.text.TextUtils; 36 import android.util.Log; 37 38 import com.android.i18n.phonenumbers.NumberParseException; 39 import com.android.i18n.phonenumbers.PhoneNumberUtil; 40 import com.android.i18n.phonenumbers.Phonenumber; 41 import com.android.ims.rcs.uce.UceController; 42 import com.android.ims.rcs.uce.UceController.UceControllerCallback; 43 import com.android.ims.rcs.uce.UceDeviceState; 44 import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; 45 import com.android.ims.rcs.uce.eab.EabCapabilityResult; 46 import com.android.ims.rcs.uce.options.OptionsController; 47 import com.android.ims.rcs.uce.presence.subscribe.SubscribeController; 48 import com.android.ims.rcs.uce.request.UceRequest.UceRequestType; 49 import com.android.ims.rcs.uce.request.UceRequestCoordinator.UceRequestUpdate; 50 import com.android.ims.rcs.uce.util.UceUtils; 51 import com.android.internal.annotations.VisibleForTesting; 52 import com.android.internal.os.SomeArgs; 53 import com.android.internal.telephony.flags.FeatureFlags; 54 55 import java.lang.ref.WeakReference; 56 import java.util.ArrayList; 57 import java.util.Collections; 58 import java.util.HashMap; 59 import java.util.List; 60 import java.util.Map; 61 import java.util.Objects; 62 import java.util.Optional; 63 import java.util.stream.Collectors; 64 65 /** 66 * Managers the capabilities requests and the availability requests from UceController. 67 */ 68 public class UceRequestManager { 69 70 private static final String LOG_TAG = UceUtils.getLogPrefix() + "UceRequestManager"; 71 72 /** 73 * When enabled, skip the request queue for requests that have numbers with valid cached 74 * capabilities and return that cached info directly. 75 * Note: This also has a CTS test associated with it, so this can not be disabled without 76 * disabling the corresponding RcsUceAdapterTest#testCacheQuerySuccessWhenNetworkBlocked test. 77 */ 78 private static final boolean FEATURE_SHORTCUT_QUEUE_FOR_CACHED_CAPS = true; 79 80 /** 81 * Testing interface used to mock UceUtils in testing. 82 */ 83 @VisibleForTesting 84 public interface UceUtilsProxy { 85 /** 86 * The interface for {@link UceUtils#isPresenceCapExchangeEnabled(Context, int)} used for 87 * testing. 88 */ isPresenceCapExchangeEnabled(Context context, int subId)89 boolean isPresenceCapExchangeEnabled(Context context, int subId); 90 91 /** 92 * The interface for {@link UceUtils#isPresenceSupported(Context, int)} used for testing. 93 */ isPresenceSupported(Context context, int subId)94 boolean isPresenceSupported(Context context, int subId); 95 96 /** 97 * The interface for {@link UceUtils#isSipOptionsSupported(Context, int)} used for testing. 98 */ isSipOptionsSupported(Context context, int subId)99 boolean isSipOptionsSupported(Context context, int subId); 100 101 /** 102 * @return true when the Presence group subscribe is enabled. 103 */ isPresenceGroupSubscribeEnabled(Context context, int subId)104 boolean isPresenceGroupSubscribeEnabled(Context context, int subId); 105 106 /** 107 * Retrieve the maximum number of contacts that can be included in a request. 108 */ getRclMaxNumberEntries(int subId)109 int getRclMaxNumberEntries(int subId); 110 111 /** 112 * @return true if the given phone number is blocked by the network. 113 */ isNumberBlocked(Context context, String phoneNumber)114 boolean isNumberBlocked(Context context, String phoneNumber); 115 116 /** 117 * @return subscribe retry duration in milliseconds. 118 */ getSubscribeRetryDuration(Context context, int subId)119 long getSubscribeRetryDuration(Context context, int subId); 120 } 121 122 private static UceUtilsProxy sUceUtilsProxy = new UceUtilsProxy() { 123 @Override 124 public boolean isPresenceCapExchangeEnabled(Context context, int subId) { 125 return UceUtils.isPresenceCapExchangeEnabled(context, subId); 126 } 127 128 @Override 129 public boolean isPresenceSupported(Context context, int subId) { 130 return UceUtils.isPresenceSupported(context, subId); 131 } 132 133 @Override 134 public boolean isSipOptionsSupported(Context context, int subId) { 135 return UceUtils.isSipOptionsSupported(context, subId); 136 } 137 138 @Override 139 public boolean isPresenceGroupSubscribeEnabled(Context context, int subId) { 140 return UceUtils.isPresenceGroupSubscribeEnabled(context, subId); 141 } 142 143 @Override 144 public int getRclMaxNumberEntries(int subId) { 145 return UceUtils.getRclMaxNumberEntries(subId); 146 } 147 148 @Override 149 public boolean isNumberBlocked(Context context, String phoneNumber) { 150 return UceUtils.isNumberBlocked(context, phoneNumber); 151 } 152 153 @Override 154 public long getSubscribeRetryDuration(Context context, int subId) { 155 return UceUtils.getSubscribeRetryInterval(context, subId); 156 } 157 }; 158 159 @VisibleForTesting setsUceUtilsProxy(UceUtilsProxy uceUtilsProxy)160 public void setsUceUtilsProxy(UceUtilsProxy uceUtilsProxy) { 161 sUceUtilsProxy = uceUtilsProxy; 162 163 // Update values for testing 164 mRetryDuration = sUceUtilsProxy.getSubscribeRetryDuration(mContext, mSubId); 165 mRetryEnabled = mRetryDuration >= 0L; 166 } 167 168 /** 169 * The callback interface to receive the request and the result from the UceRequest. 170 */ 171 public interface RequestManagerCallback { 172 /** 173 * Notify sending the UceRequest 174 */ notifySendingRequest(long coordinator, long taskId, long delayTimeMs)175 void notifySendingRequest(long coordinator, long taskId, long delayTimeMs); 176 177 /** 178 * Retrieve the contact capabilities from the cache. 179 */ getCapabilitiesFromCache(List<Uri> uriList)180 List<EabCapabilityResult> getCapabilitiesFromCache(List<Uri> uriList); 181 182 /** 183 * Retrieve the contact capabilities from the cache including the expired capabilities. 184 */ getCapabilitiesFromCacheIncludingExpired(List<Uri> uriList)185 List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(List<Uri> uriList); 186 187 /** 188 * Retrieve the contact availability from the cache. 189 */ getAvailabilityFromCache(Uri uri)190 EabCapabilityResult getAvailabilityFromCache(Uri uri); 191 192 /** 193 * Retrieve the contact availability from the cache including the expired capabilities. 194 */ getAvailabilityFromCacheIncludingExpired(Uri uri)195 EabCapabilityResult getAvailabilityFromCacheIncludingExpired(Uri uri); 196 197 /** 198 * Store the given contact capabilities to the cache. 199 */ saveCapabilities(List<RcsContactUceCapability> contactCapabilities)200 void saveCapabilities(List<RcsContactUceCapability> contactCapabilities); 201 202 /** 203 * Retrieve the device's capabilities. 204 */ getDeviceCapabilities(@apabilityMechanism int capMechanism)205 RcsContactUceCapability getDeviceCapabilities(@CapabilityMechanism int capMechanism); 206 207 /** 208 * Get the device state to check whether the device is disallowed by the network or not. 209 */ getDeviceState()210 DeviceStateResult getDeviceState(); 211 212 /** 213 * Refresh the device state. It is called when receive the UCE request response. 214 */ refreshDeviceState(int sipCode, String reason)215 void refreshDeviceState(int sipCode, String reason); 216 217 /** 218 * Notify that the UceRequest associated with the given taskId encounters error. 219 */ notifyRequestError(long requestCoordinatorId, long taskId)220 void notifyRequestError(long requestCoordinatorId, long taskId); 221 222 /** 223 * Notify that the UceRequest received the onCommandError callback from the ImsService. 224 */ notifyCommandError(long requestCoordinatorId, long taskId)225 void notifyCommandError(long requestCoordinatorId, long taskId); 226 227 /** 228 * Notify that the UceRequest received the onNetworkResponse callback from the ImsService. 229 */ notifyNetworkResponse(long requestCoordinatorId, long taskId)230 void notifyNetworkResponse(long requestCoordinatorId, long taskId); 231 232 /** 233 * Notify that the UceRequest received the onTerminated callback from the ImsService. 234 */ notifyTerminated(long requestCoordinatorId, long taskId)235 void notifyTerminated(long requestCoordinatorId, long taskId); 236 237 /** 238 * Notify that some contacts are not RCS anymore. It will updated the cached capabilities 239 * and trigger the callback IRcsUceControllerCallback#onCapabilitiesReceived 240 */ notifyResourceTerminated(long requestCoordinatorId, long taskId)241 void notifyResourceTerminated(long requestCoordinatorId, long taskId); 242 243 /** 244 * Notify that the capabilities updates. It will update the cached and trigger the callback 245 * IRcsUceControllerCallback#onCapabilitiesReceived 246 */ notifyCapabilitiesUpdated(long requestCoordinatorId, long taskId)247 void notifyCapabilitiesUpdated(long requestCoordinatorId, long taskId); 248 249 /** 250 * Notify that some of the request capabilities can be retrieved from the cached. 251 */ notifyCachedCapabilitiesUpdated(long requestCoordinatorId, long taskId)252 void notifyCachedCapabilitiesUpdated(long requestCoordinatorId, long taskId); 253 254 /** 255 * Notify that all the requested capabilities can be retrieved from the cache. It does not 256 * need to request capabilities from the network. 257 */ notifyNoNeedRequestFromNetwork(long requestCoordinatorId, long taskId)258 void notifyNoNeedRequestFromNetwork(long requestCoordinatorId, long taskId); 259 260 /** 261 * Notify that the remote options request is done. This is sent by RemoteOptionsRequest and 262 * it will notify the RemoteOptionsCoordinator to handle it. 263 */ notifyRemoteRequestDone(long requestCoordinatorId, long taskId)264 void notifyRemoteRequestDone(long requestCoordinatorId, long taskId); 265 266 /** 267 * Set the timer for the request timeout. It will cancel the request when the time is up. 268 */ setRequestTimeoutTimer(long requestCoordinatorId, long taskId, long timeoutAfterMs)269 void setRequestTimeoutTimer(long requestCoordinatorId, long taskId, long timeoutAfterMs); 270 271 /** 272 * Remove the timeout timer of the capabilities request. 273 */ removeRequestTimeoutTimer(long taskId)274 void removeRequestTimeoutTimer(long taskId); 275 276 /** 277 * Notify that the UceRequest has finished. This is sent by UceRequestCoordinator. 278 */ notifyUceRequestFinished(long requestCoordinatorId, long taskId)279 void notifyUceRequestFinished(long requestCoordinatorId, long taskId); 280 281 /** 282 * Notify that the RequestCoordinator has finished. This is sent by UceRequestCoordinator 283 * to remove the coordinator from the UceRequestRepository. 284 */ notifyRequestCoordinatorFinished(long requestCoordinatorId)285 void notifyRequestCoordinatorFinished(long requestCoordinatorId); 286 287 /** 288 * Check whether the given uris are in the throttling list. 289 * @param uriList the uris to check if it is in the throttling list 290 * @return the uris in the throttling list 291 */ getInThrottlingListUris(List<Uri> uriList)292 List<Uri> getInThrottlingListUris(List<Uri> uriList); 293 294 /** 295 * Add the given uris to the throttling list because the capabilities request result 296 * is inconclusive. 297 */ addToThrottlingList(List<Uri> uriList, int sipCode)298 void addToThrottlingList(List<Uri> uriList, int sipCode); 299 300 /** 301 * Send subscribe request to retry. 302 */ sendSubscribeRetryRequest(UceRequest request)303 void sendSubscribeRetryRequest(UceRequest request); 304 } 305 306 private RequestManagerCallback mRequestMgrCallback = new RequestManagerCallback() { 307 @Override 308 public void notifySendingRequest(long coordinatorId, long taskId, long delayTimeMs) { 309 mHandler.sendRequestMessage(coordinatorId, taskId, delayTimeMs); 310 } 311 312 @Override 313 public List<EabCapabilityResult> getCapabilitiesFromCache(List<Uri> uriList) { 314 return mControllerCallback.getCapabilitiesFromCache(uriList); 315 } 316 317 @Override 318 public List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(List<Uri> uris) { 319 return mControllerCallback.getCapabilitiesFromCacheIncludingExpired(uris); 320 } 321 322 @Override 323 public EabCapabilityResult getAvailabilityFromCache(Uri uri) { 324 return mControllerCallback.getAvailabilityFromCache(uri); 325 } 326 327 @Override 328 public EabCapabilityResult getAvailabilityFromCacheIncludingExpired(Uri uri) { 329 return mControllerCallback.getAvailabilityFromCacheIncludingExpired(uri); 330 } 331 332 @Override 333 public void saveCapabilities(List<RcsContactUceCapability> contactCapabilities) { 334 mControllerCallback.saveCapabilities(contactCapabilities); 335 } 336 337 @Override 338 public RcsContactUceCapability getDeviceCapabilities(@CapabilityMechanism int mechanism) { 339 return mControllerCallback.getDeviceCapabilities(mechanism); 340 } 341 342 @Override 343 public DeviceStateResult getDeviceState() { 344 return mControllerCallback.getDeviceState(); 345 } 346 347 @Override 348 public void refreshDeviceState(int sipCode, String reason) { 349 mControllerCallback.refreshDeviceState(sipCode, reason, 350 UceController.REQUEST_TYPE_CAPABILITY); 351 } 352 353 @Override 354 public void notifyRequestError(long requestCoordinatorId, long taskId) { 355 mHandler.sendRequestUpdatedMessage(requestCoordinatorId, taskId, 356 UceRequestCoordinator.REQUEST_UPDATE_ERROR); 357 } 358 359 @Override 360 public void notifyCommandError(long requestCoordinatorId, long taskId) { 361 mHandler.sendRequestUpdatedMessage(requestCoordinatorId, taskId, 362 UceRequestCoordinator.REQUEST_UPDATE_COMMAND_ERROR); 363 } 364 365 @Override 366 public void notifyNetworkResponse(long requestCoordinatorId, long taskId) { 367 mHandler.sendRequestUpdatedMessage(requestCoordinatorId, taskId, 368 UceRequestCoordinator.REQUEST_UPDATE_NETWORK_RESPONSE); 369 } 370 @Override 371 public void notifyTerminated(long requestCoordinatorId, long taskId) { 372 mHandler.sendRequestUpdatedMessage(requestCoordinatorId, taskId, 373 UceRequestCoordinator.REQUEST_UPDATE_TERMINATED); 374 } 375 @Override 376 public void notifyResourceTerminated(long requestCoordinatorId, long taskId) { 377 mHandler.sendRequestUpdatedMessage(requestCoordinatorId, taskId, 378 UceRequestCoordinator.REQUEST_UPDATE_RESOURCE_TERMINATED); 379 } 380 @Override 381 public void notifyCapabilitiesUpdated(long requestCoordinatorId, long taskId) { 382 mHandler.sendRequestUpdatedMessage(requestCoordinatorId, taskId, 383 UceRequestCoordinator.REQUEST_UPDATE_CAPABILITY_UPDATE); 384 } 385 386 @Override 387 public void notifyCachedCapabilitiesUpdated(long requestCoordinatorId, long taskId) { 388 mHandler.sendRequestUpdatedMessage(requestCoordinatorId, taskId, 389 UceRequestCoordinator.REQUEST_UPDATE_CACHED_CAPABILITY_UPDATE); 390 } 391 392 @Override 393 public void notifyNoNeedRequestFromNetwork(long requestCoordinatorId, long taskId) { 394 mHandler.sendRequestUpdatedMessage(requestCoordinatorId, taskId, 395 UceRequestCoordinator.REQUEST_UPDATE_NO_NEED_REQUEST_FROM_NETWORK); 396 } 397 398 @Override 399 public void notifyRemoteRequestDone(long requestCoordinatorId, long taskId) { 400 mHandler.sendRequestUpdatedMessage(requestCoordinatorId, taskId, 401 UceRequestCoordinator.REQUEST_UPDATE_REMOTE_REQUEST_DONE); 402 } 403 404 @Override 405 public void setRequestTimeoutTimer(long coordinatorId, long taskId, long timeoutAfterMs) { 406 mHandler.sendRequestTimeoutTimerMessage(coordinatorId, taskId, timeoutAfterMs); 407 } 408 409 @Override 410 public void removeRequestTimeoutTimer(long taskId) { 411 mHandler.removeRequestTimeoutTimer(taskId); 412 } 413 414 @Override 415 public void notifyUceRequestFinished(long requestCoordinatorId, long taskId) { 416 mHandler.sendRequestFinishedMessage(requestCoordinatorId, taskId); 417 } 418 419 @Override 420 public void notifyRequestCoordinatorFinished(long requestCoordinatorId) { 421 mHandler.sendRequestCoordinatorFinishedMessage(requestCoordinatorId); 422 } 423 424 @Override 425 public List<Uri> getInThrottlingListUris(List<Uri> uriList) { 426 return mThrottlingList.getInThrottlingListUris(uriList); 427 } 428 429 @Override 430 public void addToThrottlingList(List<Uri> uriList, int sipCode) { 431 mThrottlingList.addToThrottlingList(uriList, sipCode); 432 } 433 434 @Override 435 public void sendSubscribeRetryRequest(UceRequest request) { 436 UceRequestManager.this.sendSubscribeRetryRequest(request); 437 } 438 }; 439 440 private final int mSubId; 441 private final Context mContext; 442 private final UceRequestHandler mHandler; 443 private final UceRequestRepository mRequestRepository; 444 private final ContactThrottlingList mThrottlingList; 445 private final FeatureFlags mFeatureFlags; 446 private volatile boolean mIsDestroyed; 447 448 private OptionsController mOptionsCtrl; 449 private SubscribeController mSubscribeCtrl; 450 private UceControllerCallback mControllerCallback; 451 private boolean mRetryEnabled; 452 private long mRetryDuration; 453 UceRequestManager(Context context, int subId, Looper looper, UceControllerCallback c, FeatureFlags featureFlags)454 public UceRequestManager(Context context, int subId, Looper looper, UceControllerCallback c, 455 FeatureFlags featureFlags) { 456 mSubId = subId; 457 mContext = context; 458 mControllerCallback = c; 459 mHandler = new UceRequestHandler(this, looper); 460 mThrottlingList = new ContactThrottlingList(mSubId); 461 mRequestRepository = new UceRequestRepository(subId, mRequestMgrCallback); 462 mRetryDuration = sUceUtilsProxy.getSubscribeRetryDuration(mContext, mSubId); 463 mRetryEnabled = mRetryDuration >= 0L; 464 mFeatureFlags = featureFlags; 465 logi("create"); 466 } 467 468 @VisibleForTesting UceRequestManager(Context context, int subId, Looper looper, UceControllerCallback c, UceRequestRepository requestRepository, FeatureFlags featureFlags)469 public UceRequestManager(Context context, int subId, Looper looper, UceControllerCallback c, 470 UceRequestRepository requestRepository, FeatureFlags featureFlags) { 471 mSubId = subId; 472 mContext = context; 473 mControllerCallback = c; 474 mHandler = new UceRequestHandler(this, looper); 475 mRequestRepository = requestRepository; 476 mThrottlingList = new ContactThrottlingList(mSubId); 477 mFeatureFlags = featureFlags; 478 } 479 480 /** 481 * Set the OptionsController for requestiong capabilities by OPTIONS mechanism. 482 */ setOptionsController(OptionsController controller)483 public void setOptionsController(OptionsController controller) { 484 mOptionsCtrl = controller; 485 } 486 487 /** 488 * Set the SubscribeController for requesting capabilities by Subscribe mechanism. 489 */ setSubscribeController(SubscribeController controller)490 public void setSubscribeController(SubscribeController controller) { 491 mSubscribeCtrl = controller; 492 } 493 494 /** 495 * Notify that the request manager instance is destroyed. 496 */ onDestroy()497 public void onDestroy() { 498 logi("onDestroy"); 499 mIsDestroyed = true; 500 mHandler.onDestroy(); 501 mThrottlingList.reset(); 502 mRequestRepository.onDestroy(); 503 } 504 505 /** 506 * Clear the throttling list. 507 */ resetThrottlingList()508 public void resetThrottlingList() { 509 mThrottlingList.reset(); 510 } 511 512 /** 513 * Notify carrier config changed and update cached value. 514 */ onCarrierConfigChanged()515 public void onCarrierConfigChanged() { 516 mRetryDuration = sUceUtilsProxy.getSubscribeRetryDuration(mContext, mSubId); 517 mRetryEnabled = mRetryDuration >= 0L; 518 519 logd("carrier config changed : retry duration = " + mRetryDuration); 520 } 521 522 /** 523 * Send a new capability request. It is called by UceController. 524 */ sendCapabilityRequest(List<Uri> uriList, boolean skipFromCache, IRcsUceControllerCallback callback)525 public void sendCapabilityRequest(List<Uri> uriList, boolean skipFromCache, 526 IRcsUceControllerCallback callback) throws RemoteException { 527 if (mIsDestroyed) { 528 callback.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); 529 return; 530 } 531 sendRequestInternal(REQUEST_TYPE_CAPABILITY, uriList, skipFromCache, callback); 532 } 533 534 /** 535 * Send a new availability request. It is called by UceController. 536 */ sendAvailabilityRequest(Uri uri, IRcsUceControllerCallback callback)537 public void sendAvailabilityRequest(Uri uri, IRcsUceControllerCallback callback) 538 throws RemoteException { 539 if (mIsDestroyed) { 540 callback.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); 541 return; 542 } 543 sendRequestInternal(UceRequest.REQUEST_TYPE_AVAILABILITY, 544 Collections.singletonList(uri), false /* skipFromCache */, callback); 545 } 546 sendSubscribeRetryRequest(UceRequest request)547 private void sendSubscribeRetryRequest(UceRequest request) { 548 if (!mFeatureFlags.enableSipSubscribeRetry()) { 549 logw("Retry subscribe is not allowed"); 550 return; 551 } 552 553 if (request == null || !SubscribeRequest.class.isInstance(request)) { 554 logw("parameter is not available for retry"); 555 return; 556 } 557 558 // Handle subscribe retry in background, don't need to consider the cached capabilities 559 // and the callback to notify the result of operation. 560 UceRequestCoordinator requestCoordinator = 561 createSubscribeRequestCoordinatorForRetry(request); 562 563 if (requestCoordinator == null) { 564 logw("createSubscribeRequestCoordinator failed for retry"); 565 return; 566 } 567 addRequestCoordinator(requestCoordinator); 568 569 // Send delay message to retry. 570 Long coordinatorId = requestCoordinator.getCoordinatorId(); 571 Long taskId = request.getTaskId(); 572 mHandler.sendRequestMessage(coordinatorId, taskId, mRetryDuration); 573 logd("sent message for retry " + coordinatorId + " " + taskId + " " + mRetryDuration); 574 } 575 sendRequestInternal(@ceRequestType int type, List<Uri> uriList, boolean skipFromCache, IRcsUceControllerCallback callback)576 private void sendRequestInternal(@UceRequestType int type, List<Uri> uriList, 577 boolean skipFromCache, IRcsUceControllerCallback callback) throws RemoteException { 578 UceRequestCoordinator requestCoordinator = null; 579 List<Uri> nonCachedUris = uriList; 580 if (FEATURE_SHORTCUT_QUEUE_FOR_CACHED_CAPS && !skipFromCache) { 581 nonCachedUris = sendCachedCapInfoToRequester(type, uriList, callback); 582 if (uriList.size() != nonCachedUris.size()) { 583 logd("sendRequestInternal: shortcut queue for caps - request reduced from " 584 + uriList.size() + " entries to " + nonCachedUris.size() + " entries"); 585 } else { 586 logd("sendRequestInternal: shortcut queue for caps - no cached caps."); 587 } 588 if (nonCachedUris.isEmpty()) { 589 logd("sendRequestInternal: shortcut complete, sending success result"); 590 callback.onComplete(null); 591 return; 592 } 593 } 594 if (sUceUtilsProxy.isPresenceCapExchangeEnabled(mContext, mSubId) && 595 sUceUtilsProxy.isPresenceSupported(mContext, mSubId)) { 596 requestCoordinator = createSubscribeRequestCoordinator(type, nonCachedUris, 597 skipFromCache, callback); 598 } else if (sUceUtilsProxy.isSipOptionsSupported(mContext, mSubId)) { 599 requestCoordinator = createOptionsRequestCoordinator(type, nonCachedUris, callback); 600 } 601 602 if (requestCoordinator == null) { 603 logw("sendRequestInternal: Neither Presence nor OPTIONS are supported"); 604 callback.onError(RcsUceAdapter.ERROR_NOT_ENABLED, 0L, null); 605 return; 606 } 607 608 StringBuilder builder = new StringBuilder("sendRequestInternal: "); 609 builder.append("requestType=").append(type) 610 .append(", requestCoordinatorId=").append(requestCoordinator.getCoordinatorId()) 611 .append(", taskId={") 612 .append(requestCoordinator.getActivatedRequestTaskIds().stream() 613 .map(Object::toString).collect(Collectors.joining(","))).append("}"); 614 logd(builder.toString()); 615 616 // Add this RequestCoordinator to the UceRequestRepository. 617 addRequestCoordinatorAndDispatch(requestCoordinator); 618 } 619 620 /** 621 * Try to get the valid capabilities associated with the URI List specified from the EAB cache. 622 * If one or more of the numbers from the URI List have valid cached capabilities, return them 623 * to the requester now and remove them from the returned List of URIs that will require a 624 * network query. 625 * @param type The type of query 626 * @param uriList The List of URIs that we want to send cached capabilities for 627 * @param callback The callback used to communicate with the remote requester 628 * @return The List of URIs that were not found in the capability cache and will require a 629 * network query. 630 */ sendCachedCapInfoToRequester(int type, List<Uri> uriList, IRcsUceControllerCallback callback)631 private List<Uri> sendCachedCapInfoToRequester(int type, List<Uri> uriList, 632 IRcsUceControllerCallback callback) { 633 List<Uri> nonCachedUris = new ArrayList<>(uriList); 634 List<RcsContactUceCapability> numbersWithCachedCaps = 635 getCapabilitiesFromCache(type, nonCachedUris); 636 try { 637 if (!numbersWithCachedCaps.isEmpty()) { 638 logd("sendCachedCapInfoToRequester: cached caps found for " 639 + numbersWithCachedCaps.size() + " entries. Notifying requester."); 640 // Notify caller of the numbers that have cached caps 641 callback.onCapabilitiesReceived(numbersWithCachedCaps); 642 } 643 } catch (RemoteException e) { 644 logw("sendCachedCapInfoToRequester, error sending cap info back to requester: " + e); 645 } 646 // remove these numbers from the numbers pending a cap query from the network. 647 for (RcsContactUceCapability c : numbersWithCachedCaps) { 648 nonCachedUris.removeIf(uri -> c.getContactUri().equals(uri)); 649 } 650 return nonCachedUris; 651 } 652 653 /** 654 * Get the capabilities for the List of given URIs 655 * @param requestType The request type, used to determine if the cached info is "fresh" enough. 656 * @param uriList The List of URIs that we will be requesting cached capabilities for. 657 * @return A list of capabilities corresponding to the subset of numbers that still have 658 * valid cache data associated with them. 659 */ getCapabilitiesFromCache(int requestType, List<Uri> uriList)660 private List<RcsContactUceCapability> getCapabilitiesFromCache(int requestType, 661 List<Uri> uriList) { 662 List<EabCapabilityResult> resultList = Collections.emptyList(); 663 if (requestType == REQUEST_TYPE_CAPABILITY) { 664 resultList = mRequestMgrCallback.getCapabilitiesFromCache(uriList); 665 } else if (requestType == UceRequest.REQUEST_TYPE_AVAILABILITY) { 666 // Always get the first element if the request type is availability. 667 resultList = Collections.singletonList( 668 mRequestMgrCallback.getAvailabilityFromCache(uriList.get(0))); 669 } 670 // Map from EabCapabilityResult -> RcsContactUceCapability. 671 // Pull out only items that have valid cache data. 672 return resultList.stream().filter(Objects::nonNull) 673 .filter(result -> result.getStatus() == EabCapabilityResult.EAB_QUERY_SUCCESSFUL) 674 .map(EabCapabilityResult::getContactCapabilities) 675 .filter(Objects::nonNull).collect(Collectors.toList()); 676 } 677 createSubscribeRequestCoordinator(final @UceRequestType int type, final List<Uri> uriList, boolean skipFromCache, IRcsUceControllerCallback callback)678 private UceRequestCoordinator createSubscribeRequestCoordinator(final @UceRequestType int type, 679 final List<Uri> uriList, boolean skipFromCache, IRcsUceControllerCallback callback) { 680 SubscribeRequestCoordinator.Builder builder; 681 if (!sUceUtilsProxy.isPresenceGroupSubscribeEnabled(mContext, mSubId)) { 682 // When the group subscribe is disabled, each contact is required to be encapsulated 683 // into individual UceRequest. 684 List<UceRequest> requestList = new ArrayList<>(); 685 uriList.forEach(uri -> { 686 List<Uri> individualUri = Collections.singletonList(uri); 687 // Entity-uri, which is used as a request-uri, uses only a single subscription case 688 List<RcsContactUceCapability> capabilities = 689 getCapabilitiesFromCache(type, individualUri); 690 if (!capabilities.isEmpty()) { 691 RcsContactUceCapability capability = capabilities.get(0); 692 Uri entityUri = capability.getEntityUri(); 693 if (entityUri != null) { 694 // The query uri has been replaced by the stored entity uri. 695 individualUri = Collections.singletonList(entityUri); 696 } else { 697 if (UceUtils.isSipUriForPresenceSubscribeEnabled(mContext, mSubId)) { 698 individualUri = Collections.singletonList(getSipUriFromUri(uri)); 699 } 700 } 701 } else { 702 if (UceUtils.isSipUriForPresenceSubscribeEnabled(mContext, mSubId)) { 703 individualUri = Collections.singletonList(getSipUriFromUri(uri)); 704 } 705 } 706 707 UceRequest request = createSubscribeRequest(type, individualUri, skipFromCache); 708 // Set whether retry is allowed 709 request.setRetryEnabled(mRetryEnabled); 710 requestList.add(request); 711 }); 712 builder = new SubscribeRequestCoordinator.Builder(mSubId, requestList, 713 mRequestMgrCallback); 714 builder.setCapabilitiesCallback(callback); 715 } else { 716 // Even when the group subscribe is supported by the network, the number of contacts in 717 // a UceRequest still cannot exceed the maximum. 718 List<UceRequest> requestList = new ArrayList<>(); 719 final int rclMaxNumber = sUceUtilsProxy.getRclMaxNumberEntries(mSubId); 720 int numRequestCoordinators = uriList.size() / rclMaxNumber; 721 for (int count = 0; count < numRequestCoordinators; count++) { 722 List<Uri> subUriList = new ArrayList<>(); 723 for (int index = 0; index < rclMaxNumber; index++) { 724 subUriList.add(uriList.get(count * rclMaxNumber + index)); 725 } 726 727 UceRequest request = createSubscribeRequest(type, subUriList, skipFromCache); 728 // Set whether retry is allowed 729 request.setRetryEnabled(mRetryEnabled); 730 requestList.add(request); 731 } 732 733 List<Uri> subUriList = new ArrayList<>(); 734 for (int i = numRequestCoordinators * rclMaxNumber; i < uriList.size(); i++) { 735 subUriList.add(uriList.get(i)); 736 } 737 738 UceRequest request = createSubscribeRequest(type, subUriList, skipFromCache); 739 // Set whether retry is allowed 740 request.setRetryEnabled(mRetryEnabled); 741 requestList.add(request); 742 743 builder = new SubscribeRequestCoordinator.Builder(mSubId, requestList, 744 mRequestMgrCallback); 745 builder.setCapabilitiesCallback(callback); 746 } 747 return builder.build(); 748 } 749 createSubscribeRequestCoordinatorForRetry(UceRequest request)750 private UceRequestCoordinator createSubscribeRequestCoordinatorForRetry(UceRequest request) { 751 SubscribeRequestCoordinator.Builder builder; 752 753 List<UceRequest> requestList = new ArrayList<>(); 754 requestList.add(request); 755 builder = new SubscribeRequestCoordinator.Builder(mSubId, requestList, 756 mRequestMgrCallback); 757 builder.setCapabilitiesCallback(null); 758 return builder.build(); 759 } 760 createOptionsRequestCoordinator(@ceRequestType int type, List<Uri> uriList, IRcsUceControllerCallback callback)761 private UceRequestCoordinator createOptionsRequestCoordinator(@UceRequestType int type, 762 List<Uri> uriList, IRcsUceControllerCallback callback) { 763 OptionsRequestCoordinator.Builder builder; 764 List<UceRequest> requestList = new ArrayList<>(); 765 uriList.forEach(uri -> { 766 List<Uri> individualUri = Collections.singletonList(uri); 767 UceRequest request = createOptionsRequest(type, individualUri, false); 768 requestList.add(request); 769 }); 770 builder = new OptionsRequestCoordinator.Builder(mSubId, requestList, mRequestMgrCallback); 771 builder.setCapabilitiesCallback(callback); 772 return builder.build(); 773 } 774 createSubscribeRequest(int type, List<Uri> uriList, boolean skipFromCache)775 private CapabilityRequest createSubscribeRequest(int type, List<Uri> uriList, 776 boolean skipFromCache) { 777 CapabilityRequest request = new SubscribeRequest(mSubId, type, mRequestMgrCallback, 778 mSubscribeCtrl, mFeatureFlags); 779 request.setContactUri(uriList); 780 request.setSkipGettingFromCache(skipFromCache); 781 return request; 782 } 783 createOptionsRequest(int type, List<Uri> uriList, boolean skipFromCache)784 private CapabilityRequest createOptionsRequest(int type, List<Uri> uriList, 785 boolean skipFromCache) { 786 CapabilityRequest request = new OptionsRequest(mSubId, type, mRequestMgrCallback, 787 mOptionsCtrl); 788 request.setContactUri(uriList); 789 request.setSkipGettingFromCache(skipFromCache); 790 return request; 791 } 792 793 /** 794 * Retrieve the device's capabilities. This request is from the ImsService to send the 795 * capabilities to the remote side. 796 */ retrieveCapabilitiesForRemote(Uri contactUri, List<String> remoteCapabilities, IOptionsRequestCallback requestCallback)797 public void retrieveCapabilitiesForRemote(Uri contactUri, List<String> remoteCapabilities, 798 IOptionsRequestCallback requestCallback) { 799 RemoteOptionsRequest request = new RemoteOptionsRequest(mSubId, mRequestMgrCallback); 800 request.setContactUri(Collections.singletonList(contactUri)); 801 request.setRemoteFeatureTags(remoteCapabilities); 802 803 // If the remote number is blocked, do not send capabilities back. 804 String number = getNumberFromUri(contactUri); 805 if (!TextUtils.isEmpty(number)) { 806 request.setIsRemoteNumberBlocked(sUceUtilsProxy.isNumberBlocked(mContext, number)); 807 } 808 809 // Create the RemoteOptionsCoordinator instance 810 RemoteOptionsCoordinator.Builder CoordBuilder = new RemoteOptionsCoordinator.Builder( 811 mSubId, Collections.singletonList(request), mRequestMgrCallback); 812 CoordBuilder.setOptionsRequestCallback(requestCallback); 813 RemoteOptionsCoordinator requestCoordinator = CoordBuilder.build(); 814 815 StringBuilder builder = new StringBuilder("retrieveCapabilitiesForRemote: "); 816 builder.append("requestCoordinatorId ").append(requestCoordinator.getCoordinatorId()) 817 .append(", taskId={") 818 .append(requestCoordinator.getActivatedRequestTaskIds().stream() 819 .map(Object::toString).collect(Collectors.joining(","))).append("}"); 820 logd(builder.toString()); 821 822 // Add this RequestCoordinator to the UceRequestRepository. 823 addRequestCoordinatorAndDispatch(requestCoordinator); 824 } 825 826 private static class UceRequestHandler extends Handler { 827 private static final int EVENT_EXECUTE_REQUEST = 1; 828 private static final int EVENT_REQUEST_UPDATED = 2; 829 private static final int EVENT_REQUEST_TIMEOUT = 3; 830 private static final int EVENT_REQUEST_FINISHED = 4; 831 private static final int EVENT_COORDINATOR_FINISHED = 5; 832 private final Map<Long, SomeArgs> mRequestTimeoutTimers; 833 private final WeakReference<UceRequestManager> mUceRequestMgrRef; 834 UceRequestHandler(UceRequestManager requestManager, Looper looper)835 public UceRequestHandler(UceRequestManager requestManager, Looper looper) { 836 super(looper); 837 mRequestTimeoutTimers = new HashMap<>(); 838 mUceRequestMgrRef = new WeakReference<>(requestManager); 839 } 840 841 /** 842 * Send the capabilities request message. 843 */ sendRequestMessage(Long coordinatorId, Long taskId, long delayTimeMs)844 public void sendRequestMessage(Long coordinatorId, Long taskId, long delayTimeMs) { 845 SomeArgs args = SomeArgs.obtain(); 846 args.arg1 = coordinatorId; 847 args.arg2 = taskId; 848 849 Message message = obtainMessage(); 850 message.what = EVENT_EXECUTE_REQUEST; 851 message.obj = args; 852 sendMessageDelayed(message, delayTimeMs); 853 } 854 855 /** 856 * Send the Uce request updated message. 857 */ sendRequestUpdatedMessage(Long coordinatorId, Long taskId, @UceRequestUpdate int requestEvent)858 public void sendRequestUpdatedMessage(Long coordinatorId, Long taskId, 859 @UceRequestUpdate int requestEvent) { 860 SomeArgs args = SomeArgs.obtain(); 861 args.arg1 = coordinatorId; 862 args.arg2 = taskId; 863 args.argi1 = requestEvent; 864 865 Message message = obtainMessage(); 866 message.what = EVENT_REQUEST_UPDATED; 867 message.obj = args; 868 sendMessage(message); 869 } 870 871 /** 872 * Set the timeout timer to cancel the capabilities request. 873 */ sendRequestTimeoutTimerMessage(Long coordId, Long taskId, Long timeoutAfterMs)874 public void sendRequestTimeoutTimerMessage(Long coordId, Long taskId, Long timeoutAfterMs) { 875 synchronized (mRequestTimeoutTimers) { 876 SomeArgs args = SomeArgs.obtain(); 877 args.arg1 = coordId; 878 args.arg2 = taskId; 879 880 // Add the message object to the collection. It can be used to find this message 881 // when the request is completed and remove the timeout timer. 882 mRequestTimeoutTimers.put(taskId, args); 883 884 Message message = obtainMessage(); 885 message.what = EVENT_REQUEST_TIMEOUT; 886 message.obj = args; 887 sendMessageDelayed(message, timeoutAfterMs); 888 } 889 } 890 891 /** 892 * Remove the timeout timer because the capabilities request is finished. 893 */ removeRequestTimeoutTimer(Long taskId)894 public void removeRequestTimeoutTimer(Long taskId) { 895 synchronized (mRequestTimeoutTimers) { 896 SomeArgs args = mRequestTimeoutTimers.remove(taskId); 897 if (args == null) { 898 return; 899 } 900 Log.d(LOG_TAG, "removeRequestTimeoutTimer: taskId=" + taskId); 901 removeMessages(EVENT_REQUEST_TIMEOUT, args); 902 args.recycle(); 903 } 904 } 905 sendRequestFinishedMessage(Long coordinatorId, Long taskId)906 public void sendRequestFinishedMessage(Long coordinatorId, Long taskId) { 907 SomeArgs args = SomeArgs.obtain(); 908 args.arg1 = coordinatorId; 909 args.arg2 = taskId; 910 911 Message message = obtainMessage(); 912 message.what = EVENT_REQUEST_FINISHED; 913 message.obj = args; 914 sendMessage(message); 915 } 916 917 /** 918 * Finish the UceRequestCoordinator associated with the given id. 919 */ sendRequestCoordinatorFinishedMessage(Long coordinatorId)920 public void sendRequestCoordinatorFinishedMessage(Long coordinatorId) { 921 SomeArgs args = SomeArgs.obtain(); 922 args.arg1 = coordinatorId; 923 924 Message message = obtainMessage(); 925 message.what = EVENT_COORDINATOR_FINISHED; 926 message.obj = args; 927 sendMessage(message); 928 } 929 930 /** 931 * Remove all the messages from the handler 932 */ onDestroy()933 public void onDestroy() { 934 removeCallbacksAndMessages(null); 935 // Recycle all the arguments in the mRequestTimeoutTimers 936 synchronized (mRequestTimeoutTimers) { 937 mRequestTimeoutTimers.forEach((taskId, args) -> { 938 try { 939 args.recycle(); 940 } catch (Exception e) {} 941 }); 942 mRequestTimeoutTimers.clear(); 943 } 944 } 945 946 @Override handleMessage(Message msg)947 public void handleMessage(Message msg) { 948 UceRequestManager requestManager = mUceRequestMgrRef.get(); 949 if (requestManager == null) { 950 return; 951 } 952 SomeArgs args = (SomeArgs) msg.obj; 953 final Long coordinatorId = (Long) args.arg1; 954 final Long taskId = (Long) Optional.ofNullable(args.arg2).orElse(-1L); 955 final Integer requestEvent = Optional.ofNullable(args.argi1).orElse(-1); 956 args.recycle(); 957 958 requestManager.logd("handleMessage: " + EVENT_DESCRIPTION.get(msg.what) 959 + ", coordinatorId=" + coordinatorId + ", taskId=" + taskId); 960 switch (msg.what) { 961 case EVENT_EXECUTE_REQUEST: { 962 UceRequest request = requestManager.getUceRequest(taskId); 963 if (request == null) { 964 requestManager.logw("handleMessage: cannot find request, taskId=" + taskId); 965 return; 966 } 967 request.executeRequest(); 968 break; 969 } 970 case EVENT_REQUEST_UPDATED: { 971 UceRequestCoordinator requestCoordinator = 972 requestManager.getRequestCoordinator(coordinatorId); 973 if (requestCoordinator == null) { 974 requestManager.logw("handleMessage: cannot find UceRequestCoordinator"); 975 return; 976 } 977 requestCoordinator.onRequestUpdated(taskId, requestEvent); 978 break; 979 } 980 case EVENT_REQUEST_TIMEOUT: { 981 UceRequestCoordinator requestCoordinator = 982 requestManager.getRequestCoordinator(coordinatorId); 983 if (requestCoordinator == null) { 984 requestManager.logw("handleMessage: cannot find UceRequestCoordinator"); 985 return; 986 } 987 // The timeout timer is triggered, remove this record from the collection. 988 synchronized (mRequestTimeoutTimers) { 989 mRequestTimeoutTimers.remove(taskId); 990 } 991 // Notify that the request is timeout. 992 requestCoordinator.onRequestUpdated(taskId, 993 UceRequestCoordinator.REQUEST_UPDATE_TIMEOUT); 994 break; 995 } 996 case EVENT_REQUEST_FINISHED: { 997 // Notify the repository that the request is finished. 998 requestManager.notifyRepositoryRequestFinished(taskId); 999 break; 1000 } 1001 case EVENT_COORDINATOR_FINISHED: { 1002 UceRequestCoordinator requestCoordinator = 1003 requestManager.removeRequestCoordinator(coordinatorId); 1004 if (requestCoordinator != null) { 1005 requestCoordinator.onFinish(); 1006 } 1007 break; 1008 } 1009 default: { 1010 break; 1011 } 1012 } 1013 } 1014 1015 private static Map<Integer, String> EVENT_DESCRIPTION = new HashMap<>(); 1016 static { EVENT_DESCRIPTION.put(EVENT_EXECUTE_REQUEST, "EXECUTE_REQUEST")1017 EVENT_DESCRIPTION.put(EVENT_EXECUTE_REQUEST, "EXECUTE_REQUEST"); EVENT_DESCRIPTION.put(EVENT_REQUEST_UPDATED, "REQUEST_UPDATE")1018 EVENT_DESCRIPTION.put(EVENT_REQUEST_UPDATED, "REQUEST_UPDATE"); EVENT_DESCRIPTION.put(EVENT_REQUEST_TIMEOUT, "REQUEST_TIMEOUT")1019 EVENT_DESCRIPTION.put(EVENT_REQUEST_TIMEOUT, "REQUEST_TIMEOUT"); EVENT_DESCRIPTION.put(EVENT_REQUEST_FINISHED, "REQUEST_FINISHED")1020 EVENT_DESCRIPTION.put(EVENT_REQUEST_FINISHED, "REQUEST_FINISHED"); EVENT_DESCRIPTION.put(EVENT_COORDINATOR_FINISHED, "REMOVE_COORDINATOR")1021 EVENT_DESCRIPTION.put(EVENT_COORDINATOR_FINISHED, "REMOVE_COORDINATOR"); 1022 } 1023 } 1024 addRequestCoordinatorAndDispatch(UceRequestCoordinator coordinator)1025 private void addRequestCoordinatorAndDispatch(UceRequestCoordinator coordinator) { 1026 mRequestRepository.addRequestCoordinatorAndDispatch(coordinator); 1027 } 1028 removeRequestCoordinator(Long coordinatorId)1029 private UceRequestCoordinator removeRequestCoordinator(Long coordinatorId) { 1030 return mRequestRepository.removeRequestCoordinator(coordinatorId); 1031 } 1032 addRequestCoordinator(UceRequestCoordinator coordinator)1033 private void addRequestCoordinator(UceRequestCoordinator coordinator) { 1034 mRequestRepository.addRequestCoordinator(coordinator); 1035 } 1036 getRequestCoordinator(Long coordinatorId)1037 private UceRequestCoordinator getRequestCoordinator(Long coordinatorId) { 1038 return mRequestRepository.getRequestCoordinator(coordinatorId); 1039 } 1040 getUceRequest(Long taskId)1041 private UceRequest getUceRequest(Long taskId) { 1042 return mRequestRepository.getUceRequest(taskId); 1043 } 1044 notifyRepositoryRequestFinished(Long taskId)1045 private void notifyRepositoryRequestFinished(Long taskId) { 1046 mRequestRepository.notifyRequestFinished(taskId); 1047 } 1048 getSipUriFromUri(Uri uri)1049 private Uri getSipUriFromUri(Uri uri) { 1050 Uri convertedUri = uri; 1051 String number = convertedUri.getSchemeSpecificPart(); 1052 String[] numberParts = number.split("[@;:]"); 1053 number = numberParts[0]; 1054 1055 TelephonyManager manager = mContext.getSystemService(TelephonyManager.class); 1056 if (manager.getIsimDomain() == null) { 1057 return convertedUri; 1058 } 1059 String simCountryIso = manager.getSimCountryIso(); 1060 if (TextUtils.isEmpty(simCountryIso)) { 1061 return convertedUri; 1062 } 1063 simCountryIso = simCountryIso.toUpperCase(); 1064 PhoneNumberUtil util = PhoneNumberUtil.getInstance(); 1065 try { 1066 Phonenumber.PhoneNumber phoneNumber = util.parse(number, simCountryIso); 1067 number = util.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164); 1068 String sipUri = "sip:" + number + "@" + manager.getIsimDomain(); 1069 convertedUri = Uri.parse(sipUri); 1070 } catch (NumberParseException e) { 1071 Log.w(LOG_TAG, "formatNumber: could not format " + number + ", error: " + e); 1072 } 1073 return convertedUri; 1074 } 1075 1076 @VisibleForTesting getUceRequestHandler()1077 public UceRequestHandler getUceRequestHandler() { 1078 return mHandler; 1079 } 1080 1081 @VisibleForTesting getRequestManagerCallback()1082 public RequestManagerCallback getRequestManagerCallback() { 1083 return mRequestMgrCallback; 1084 } 1085 logi(String log)1086 private void logi(String log) { 1087 Log.i(LOG_TAG, getLogPrefix().append(log).toString()); 1088 } 1089 logd(String log)1090 private void logd(String log) { 1091 Log.d(LOG_TAG, getLogPrefix().append(log).toString()); 1092 } 1093 logw(String log)1094 private void logw(String log) { 1095 Log.w(LOG_TAG, getLogPrefix().append(log).toString()); 1096 } 1097 getLogPrefix()1098 private StringBuilder getLogPrefix() { 1099 StringBuilder builder = new StringBuilder("["); 1100 builder.append(mSubId); 1101 builder.append("] "); 1102 return builder; 1103 } 1104 getNumberFromUri(Uri uri)1105 private String getNumberFromUri(Uri uri) { 1106 if (uri == null) return null; 1107 String number = uri.getSchemeSpecificPart(); 1108 String[] numberParts = number.split("[@;:]"); 1109 1110 if (numberParts.length == 0) { 1111 return null; 1112 } 1113 return numberParts[0]; 1114 } 1115 } 1116