aboutsummaryrefslogtreecommitdiff
path: root/src/java
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2022-02-14 17:30:10 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2022-02-14 17:30:10 +0000
commitcbb96fc72698261a266666f4a4b095a829a88cdc (patch)
tree712d07ff3e82431c00ee8be5ac46d04e45ad447c /src/java
parentae616d71740aecc332d7241507821b7bfb37834d (diff)
parent866199c06013f19860a1e0adbd0d24726d41ba56 (diff)
downloadims-cbb96fc72698261a266666f4a4b095a829a88cdc.tar.gz
Merge "Merge sc-v2-dev-plus-aosp-without-vendor@8084891" into stage-aosp-master
Diffstat (limited to 'src/java')
-rw-r--r--src/java/com/android/ims/rcs/uce/UceController.java23
-rw-r--r--src/java/com/android/ims/rcs/uce/UceDeviceState.java12
-rw-r--r--src/java/com/android/ims/rcs/uce/eab/EabController.java12
-rw-r--r--src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java87
-rw-r--r--src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java105
-rw-r--r--src/java/com/android/ims/rcs/uce/request/ContactThrottlingList.java119
-rw-r--r--src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java81
-rw-r--r--src/java/com/android/ims/rcs/uce/request/UceRequestManager.java54
-rw-r--r--src/java/com/android/ims/rcs/uce/util/UceUtils.java25
9 files changed, 494 insertions, 24 deletions
diff --git a/src/java/com/android/ims/rcs/uce/UceController.java b/src/java/com/android/ims/rcs/uce/UceController.java
index 60c80e65..6fb27b06 100644
--- a/src/java/com/android/ims/rcs/uce/UceController.java
+++ b/src/java/com/android/ims/rcs/uce/UceController.java
@@ -80,11 +80,23 @@ public class UceController {
List<EabCapabilityResult> getCapabilitiesFromCache(@NonNull List<Uri> uris);
/**
+ * Retrieve the capabilities associated with the given uris from the cache including
+ * expired capabilities.
+ */
+ List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(@NonNull List<Uri> uris);
+
+ /**
* Retrieve the contact's capabilities from the availability cache.
*/
EabCapabilityResult getAvailabilityFromCache(@NonNull Uri uri);
/**
+ * Retrieve the contact's capabilities from the availability cache including expired
+ * capabilities
+ */
+ EabCapabilityResult getAvailabilityFromCacheIncludingExpired(@NonNull Uri uri);
+
+ /**
* Store the given capabilities to the cache.
*/
void saveCapabilities(List<RcsContactUceCapability> contactCapabilities);
@@ -507,11 +519,21 @@ public class UceController {
}
@Override
+ public List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(List<Uri> uris) {
+ return mEabController.getCapabilitiesIncludingExpired(uris);
+ }
+
+ @Override
public EabCapabilityResult getAvailabilityFromCache(Uri contactUri) {
return mEabController.getAvailability(contactUri);
}
@Override
+ public EabCapabilityResult getAvailabilityFromCacheIncludingExpired(Uri contactUri) {
+ return mEabController.getAvailabilityIncludingExpired(contactUri);
+ }
+
+ @Override
public void saveCapabilities(List<RcsContactUceCapability> contactCapabilities) {
mEabController.saveCapabilities(contactCapabilities);
}
@@ -810,6 +832,7 @@ public class UceController {
public void removeRequestDisallowedStatus() {
logd("removeRequestDisallowedStatus");
mDeviceState.resetDeviceState();
+ mRequestManager.resetThrottlingList();
}
/**
diff --git a/src/java/com/android/ims/rcs/uce/UceDeviceState.java b/src/java/com/android/ims/rcs/uce/UceDeviceState.java
index 0d8842fa..857e25c8 100644
--- a/src/java/com/android/ims/rcs/uce/UceDeviceState.java
+++ b/src/java/com/android/ims/rcs/uce/UceDeviceState.java
@@ -258,14 +258,12 @@ public class UceDeviceState {
if (requestType == UceController.REQUEST_TYPE_PUBLISH) {
// Provisioning error for publish request.
setDeviceState(DEVICE_STATE_PROVISION_ERROR);
- } else {
- setDeviceState(DEVICE_STATE_FORBIDDEN);
+ updateErrorCode(sipCode, reason, requestType);
+ // There is no request retry time for SIP code 403
+ removeRequestRetryTime();
+ // No timer to exit the forbidden state.
+ removeExitStateTimer();
}
- updateErrorCode(sipCode, reason, requestType);
- // There is no request retry time for SIP code 403
- removeRequestRetryTime();
- // No timer to exit the forbidden state.
- removeExitStateTimer();
break;
case NetworkSipCode.SIP_CODE_NOT_FOUND: // sip 404
diff --git a/src/java/com/android/ims/rcs/uce/eab/EabController.java b/src/java/com/android/ims/rcs/uce/eab/EabController.java
index 903a19df..b03e4659 100644
--- a/src/java/com/android/ims/rcs/uce/eab/EabController.java
+++ b/src/java/com/android/ims/rcs/uce/eab/EabController.java
@@ -35,11 +35,23 @@ public interface EabController extends ControllerBase {
@NonNull List<EabCapabilityResult> getCapabilities(@NonNull List<Uri> uris);
/**
+ * Get contact capabilities from cache including expired capabilities.
+ * @param uris the uri list to get contact capabilities from cache.
+ * @return The contact capabilities of the given uri list.
+ */
+ @NonNull List<EabCapabilityResult> getCapabilitiesIncludingExpired(@NonNull List<Uri> uris);
+
+ /**
* Retrieve the contact's capabilities from the availability cache.
*/
@NonNull EabCapabilityResult getAvailability(@NonNull Uri contactUri);
/**
+ * Retrieve the contact's capabilities from the availability cache.
+ */
+ @NonNull EabCapabilityResult getAvailabilityIncludingExpired(@NonNull Uri contactUri);
+
+ /**
* Save the capabilities to the EAB database.
*/
void saveCapabilities(@NonNull List<RcsContactUceCapability> contactCapabilities);
diff --git a/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java b/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java
index d3e8063e..7563f641 100644
--- a/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java
+++ b/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java
@@ -56,6 +56,7 @@ import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.function.Predicate;
/**
@@ -166,6 +167,29 @@ public class EabControllerImpl implements EabController {
}
/**
+ * Retrieve the contacts' capabilities from the EAB database including expired capabilities.
+ */
+ @Override
+ public @NonNull List<EabCapabilityResult> getCapabilitiesIncludingExpired(
+ @NonNull List<Uri> uris) {
+ Objects.requireNonNull(uris);
+ if (mIsSetDestroyedFlag) {
+ Log.d(TAG, "EabController destroyed.");
+ return generateDestroyedResult(uris);
+ }
+
+ Log.d(TAG, "getCapabilitiesIncludingExpired uri size=" + uris.size());
+ List<EabCapabilityResult> capabilityResultList = new ArrayList();
+
+ for (Uri uri : uris) {
+ EabCapabilityResult result = generateEabResultIncludingExpired(uri,
+ this::isCapabilityExpired);
+ capabilityResultList.add(result);
+ }
+ return capabilityResultList;
+ }
+
+ /**
* Retrieve the contact's capabilities from the availability cache.
*/
@Override
@@ -182,6 +206,23 @@ public class EabControllerImpl implements EabController {
}
/**
+ * Retrieve the contact's capabilities from the availability cache including expired
+ * capabilities.
+ */
+ @Override
+ public @NonNull EabCapabilityResult getAvailabilityIncludingExpired(@NonNull Uri contactUri) {
+ Objects.requireNonNull(contactUri);
+ if (mIsSetDestroyedFlag) {
+ Log.d(TAG, "EabController destroyed.");
+ return new EabCapabilityResult(
+ contactUri,
+ EabCapabilityResult.EAB_CONTROLLER_DESTROYED_FAILURE,
+ null);
+ }
+ return generateEabResultIncludingExpired(contactUri, this::isAvailabilityExpired);
+ }
+
+ /**
* Update the availability catch and save the capabilities to the EAB database.
*/
@Override
@@ -299,6 +340,52 @@ public class EabControllerImpl implements EabController {
return result;
}
+ private EabCapabilityResult generateEabResultIncludingExpired(Uri contactUri,
+ Predicate<Cursor> isExpiredMethod) {
+ RcsUceCapabilityBuilderWrapper builder = null;
+ EabCapabilityResult result;
+ Optional<Boolean> isExpired = Optional.empty();
+
+ // query EAB provider
+ Uri queryUri = Uri.withAppendedPath(
+ Uri.withAppendedPath(EabProvider.ALL_DATA_URI, String.valueOf(mSubId)),
+ getNumberFromUri(mContext, contactUri));
+ Cursor cursor = mContext.getContentResolver().query(queryUri, null, null, null, null);
+
+ if (cursor != null && cursor.getCount() != 0) {
+ while (cursor.moveToNext()) {
+ // Record whether it has expired.
+ if (!isExpired.isPresent()) {
+ isExpired = Optional.of(isExpiredMethod.test(cursor));
+ }
+ if (builder == null) {
+ builder = createNewBuilder(contactUri, cursor);
+ } else {
+ updateCapability(contactUri, cursor, builder);
+ }
+ }
+ cursor.close();
+
+ // Determine the query result
+ int eabResult = EabCapabilityResult.EAB_QUERY_SUCCESSFUL;
+ if (isExpired.orElse(false)) {
+ eabResult = EabCapabilityResult.EAB_CONTACT_EXPIRED_FAILURE;
+ }
+
+ if (builder.getMechanism() == CAPABILITY_MECHANISM_PRESENCE) {
+ PresenceBuilder presenceBuilder = builder.getPresenceBuilder();
+ result = new EabCapabilityResult(contactUri, eabResult, presenceBuilder.build());
+ } else {
+ OptionsBuilder optionsBuilder = builder.getOptionsBuilder();
+ result = new EabCapabilityResult(contactUri, eabResult, optionsBuilder.build());
+ }
+ } else {
+ result = new EabCapabilityResult(contactUri,
+ EabCapabilityResult.EAB_CONTACT_NOT_FOUND_FAILURE, null);
+ }
+ return result;
+ }
+
private void updateCapability(Uri contactUri, Cursor cursor,
RcsUceCapabilityBuilderWrapper builderWrapper) {
if (builderWrapper.getMechanism() == CAPABILITY_MECHANISM_PRESENCE) {
diff --git a/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java b/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java
index f7a4acc6..17cec90b 100644
--- a/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java
+++ b/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java
@@ -23,6 +23,7 @@ import android.util.Log;
import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult;
import com.android.ims.rcs.uce.eab.EabCapabilityResult;
+import com.android.ims.rcs.uce.presence.pidfparser.PidfParserUtils;
import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
import com.android.ims.rcs.uce.util.UceUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -140,20 +141,36 @@ public abstract class CapabilityRequest implements UceRequest {
return;
}
- // Get the capabilities from the cache.
- final List<RcsContactUceCapability> cachedCapList
- = isSkipGettingFromCache() ? Collections.EMPTY_LIST : getCapabilitiesFromCache();
+ // Get the contact capabilities from the cache including the expired capabilities.
+ final List<EabCapabilityResult> eabResultList = getCapabilitiesFromCache();
+
+ // Get all the unexpired capabilities from the EAB result list and add to the response.
+ final List<RcsContactUceCapability> cachedCapList = isSkipGettingFromCache() ?
+ Collections.EMPTY_LIST : getUnexpiredCapabilities(eabResultList);
mRequestResponse.addCachedCapabilities(cachedCapList);
logd("executeRequest: cached capabilities size=" + cachedCapList.size());
+ // Get the rest contacts which are not in the cache or has expired.
+ final List<Uri> expiredUris = getRequestingFromNetworkUris(cachedCapList);
+
+ // For those uris that are not in the cache or have expired, we should request their
+ // capabilities from the network. However, we still need to check whether these contacts
+ // are in the throttling list. If the contact is in the throttling list, even if it has
+ // expired, we will get the cached capabilities.
+ final List<RcsContactUceCapability> throttlingUris =
+ getFromThrottlingList(expiredUris, eabResultList);
+ mRequestResponse.addCachedCapabilities(throttlingUris);
+
+ logd("executeRequest: contacts in throttling list size=" + throttlingUris.size());
+
// Notify that the cached capabilities are updated.
- if (!cachedCapList.isEmpty()) {
+ if (!cachedCapList.isEmpty() || !throttlingUris.isEmpty()) {
mRequestManagerCallback.notifyCachedCapabilitiesUpdated(mCoordinatorId, mTaskId);
}
// Get the rest contacts which need to request capabilities from the network.
- final List<Uri> requestCapUris = getRequestingFromNetworkUris(cachedCapList);
+ List<Uri> requestCapUris = getRequestingFromNetworkUris(cachedCapList, throttlingUris);
logd("executeRequest: requestCapUris size=" + requestCapUris.size());
@@ -193,21 +210,30 @@ public abstract class CapabilityRequest implements UceRequest {
}
// Get the cached capabilities by the given request type.
- private List<RcsContactUceCapability> getCapabilitiesFromCache() {
+ private List<EabCapabilityResult> getCapabilitiesFromCache() {
List<EabCapabilityResult> resultList = null;
if (mRequestType == REQUEST_TYPE_CAPABILITY) {
- resultList = mRequestManagerCallback.getCapabilitiesFromCache(mUriList);
+ resultList = mRequestManagerCallback.getCapabilitiesFromCacheIncludingExpired(mUriList);
} else if (mRequestType == REQUEST_TYPE_AVAILABILITY) {
// Always get the first element if the request type is availability.
Uri uri = mUriList.get(0);
- EabCapabilityResult eabResult = mRequestManagerCallback.getAvailabilityFromCache(uri);
+ EabCapabilityResult eabResult =
+ mRequestManagerCallback.getAvailabilityFromCacheIncludingExpired(uri);
resultList = new ArrayList<>();
resultList.add(eabResult);
}
if (resultList == null) {
return Collections.emptyList();
}
- return resultList.stream()
+ return resultList;
+ }
+
+ /**
+ * Get the unexpired contact capabilities from the given EAB result list.
+ * @param list the query result from the EAB
+ */
+ private List<RcsContactUceCapability> getUnexpiredCapabilities(List<EabCapabilityResult> list) {
+ return list.stream()
.filter(Objects::nonNull)
.filter(result -> result.getStatus() == EabCapabilityResult.EAB_QUERY_SUCCESSFUL)
.map(EabCapabilityResult::getContactCapabilities)
@@ -227,6 +253,67 @@ public abstract class CapabilityRequest implements UceRequest {
}
/**
+ * Get the contact uris which cannot retrieve capabilities from the cache.
+ * @param cachedCapList The capabilities which are already stored in the cache.
+ * @param throttlingUris The capabilities which are in the throttling list.
+ */
+ private List<Uri> getRequestingFromNetworkUris(List<RcsContactUceCapability> cachedCapList,
+ List<RcsContactUceCapability> throttlingUris) {
+ // We won't request the network query for those contacts in the cache and in the
+ // throttling list. Merging the two list and get the rest contact uris.
+ List<RcsContactUceCapability> notNetworkQueryList = new ArrayList<>(cachedCapList);
+ notNetworkQueryList.addAll(throttlingUris);
+ return getRequestingFromNetworkUris(notNetworkQueryList);
+ }
+
+ /**
+ * Get the contact capabilities for those uri are in the throttling list. If the contact uri is
+ * in the throttling list, the capabilities will be retrieved from cache even if it has expired.
+ * If the capabilities cannot be found, return the non-RCS contact capabilities instead.
+ * @param expiredUris the expired/unknown uris to check whether are in the throttling list
+ * @return the contact capabilities for the uris are in the throttling list
+ */
+ private List<RcsContactUceCapability> getFromThrottlingList(final List<Uri> expiredUris,
+ final List<EabCapabilityResult> eabResultList) {
+ List<RcsContactUceCapability> resultList = new ArrayList<>();
+ List<RcsContactUceCapability> notFoundFromCacheList = new ArrayList<>();
+
+ // Retrieve the uris put in the throttling list from the expired/unknown contacts.
+ List<Uri> throttlingUris = mRequestManagerCallback.getInThrottlingListUris(expiredUris);
+
+ // For these uris in the throttling list, check whether their capabilities are in the cache.
+ List<EabCapabilityResult> throttlingUriFoundInEab = new ArrayList<>();
+ for (Uri uri : throttlingUris) {
+ for (EabCapabilityResult eabResult : eabResultList) {
+ if (eabResult.getContact().equals(uri)) {
+ throttlingUriFoundInEab.add(eabResult);
+ break;
+ }
+ }
+ }
+
+ throttlingUriFoundInEab.forEach(eabResult -> {
+ if (eabResult.getStatus() == EabCapabilityResult.EAB_QUERY_SUCCESSFUL ||
+ eabResult.getStatus() == EabCapabilityResult.EAB_CONTACT_EXPIRED_FAILURE) {
+ // The capabilities are found, add to the result list
+ resultList.add(eabResult.getContactCapabilities());
+ } else {
+ // Cannot get the capabilities from cache, create the non-RCS capabilities instead.
+ notFoundFromCacheList.add(PidfParserUtils.getNotFoundContactCapabilities(
+ eabResult.getContact()));
+ }
+ });
+
+ if (!notFoundFromCacheList.isEmpty()) {
+ resultList.addAll(notFoundFromCacheList);
+ }
+
+ logd("getFromThrottlingList: requesting uris in the list size=" + throttlingUris.size() +
+ ", generate non-RCS size=" + notFoundFromCacheList.size());
+ return resultList;
+ }
+
+ /**
* Set the timeout timer of this request.
*/
protected void setupRequestTimeoutTimer() {
diff --git a/src/java/com/android/ims/rcs/uce/request/ContactThrottlingList.java b/src/java/com/android/ims/rcs/uce/request/ContactThrottlingList.java
new file mode 100644
index 00000000..da67f6c9
--- /dev/null
+++ b/src/java/com/android/ims/rcs/uce/request/ContactThrottlingList.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.rcs.uce.request;
+
+import android.net.Uri;
+import android.util.Log;
+
+import com.android.ims.rcs.uce.util.UceUtils;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * The class is used to store when the contact's capabilities request result is inconclusive.
+ */
+public class ContactThrottlingList {
+ private static final String LOG_TAG = UceUtils.getLogPrefix() + "ThrottlingList";
+
+ private static class ContactInfo {
+ Uri mContactUri;
+ int mSipCode;
+ Instant mThrottleEndTimestamp;
+
+ public ContactInfo(Uri contactUri, int sipCode, Instant timestamp) {
+ mContactUri = contactUri;
+ mSipCode = sipCode;
+ mThrottleEndTimestamp = timestamp;
+ }
+ }
+
+ private final int mSubId;
+ private final List<ContactInfo> mThrottlingList = new ArrayList<>();
+
+ public ContactThrottlingList(int subId) {
+ mSubId = subId;
+ }
+
+ public synchronized void reset() {
+ mThrottlingList.clear();
+ }
+
+ public synchronized void addToThrottlingList(List<Uri> uriList, int sipCode) {
+ // Clean up the expired contacts before starting.
+ cleanUpExpiredContacts();
+
+ List<Uri> addToThrottlingList = getNotInThrottlingListUris(uriList);
+ long expiration = UceUtils.getAvailabilityCacheExpiration(mSubId);
+ Instant timestamp = Instant.now().plusSeconds(expiration);
+
+ List<ContactInfo> list = addToThrottlingList.stream().map(uri ->
+ new ContactInfo(uri, sipCode, timestamp)).collect(Collectors.toList());
+
+ int previousSize = mThrottlingList.size();
+ mThrottlingList.addAll(list);
+
+ logd("addToThrottlingList: previous size=" + previousSize +
+ ", current size=" + mThrottlingList.size() + ", expired time=" + timestamp);
+ }
+
+ private synchronized List<Uri> getNotInThrottlingListUris(List<Uri> uriList) {
+ List<Uri> throttlingUris = mThrottlingList.stream().map(contactInfo ->
+ contactInfo.mContactUri).collect(Collectors.toList());
+ List<Uri> addToThrottlingUris = new ArrayList<>(uriList);
+ addToThrottlingUris.removeAll(throttlingUris);
+ return addToThrottlingUris;
+ }
+
+ public synchronized List<Uri> getInThrottlingListUris(List<Uri> uriList) {
+ // Clean up the expired contacts before starting.
+ cleanUpExpiredContacts();
+
+ return uriList.stream()
+ .filter(uri -> mThrottlingList.stream()
+ .anyMatch(contactInfo -> contactInfo.mContactUri.equals(uri)))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Clean up the expired contacts from the throttling list.
+ */
+ private synchronized void cleanUpExpiredContacts() {
+ final int previousSize = mThrottlingList.size();
+ List<ContactInfo> expiredContacts = mThrottlingList.stream()
+ .filter(contactInfo -> Instant.now()
+ .isAfter(contactInfo.mThrottleEndTimestamp))
+ .collect(Collectors.toList());
+ mThrottlingList.removeAll(expiredContacts);
+
+ logd("cleanUpExpiredContacts: previous size=" + previousSize +
+ ", current size=" + mThrottlingList.size());
+ }
+
+ private void logd(String log) {
+ Log.d(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private StringBuilder getLogPrefix() {
+ StringBuilder builder = new StringBuilder("[");
+ builder.append(mSubId);
+ builder.append("] ");
+ return builder;
+ }
+}
diff --git a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java
index 8913340b..f44686ac 100644
--- a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java
+++ b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java
@@ -25,12 +25,14 @@ import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult;
+import com.android.ims.rcs.uce.eab.EabCapabilityResult;
import com.android.ims.rcs.uce.presence.pidfparser.PidfParserUtils;
import com.android.ims.rcs.uce.request.SubscriptionTerminatedHelper.TerminatedResult;
import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
import com.android.ims.rcs.uce.UceStatsWriter;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
@@ -311,6 +313,7 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator {
private RequestResult handleNetworkResponseFailed(SubscribeRequest request) {
final long taskId = request.getTaskId();
final CapabilityRequestResponse response = request.getRequestResponse();
+ final List<Uri> requestUris = response.getNotReceiveCapabilityUpdatedContact();
RequestResult requestResult = null;
if (response.isNotFound()) {
@@ -318,8 +321,7 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator {
// updated callback from the ImsService afterward. Therefore, we create the capabilities
// with the result REQUEST_RESULT_NOT_FOUND by ourself and will trigger the
// capabilities received callback to the clients later.
- List<Uri> uriList = request.getContactUri();
- List<RcsContactUceCapability> capabilityList = uriList.stream().map(uri ->
+ List<RcsContactUceCapability> capabilityList = requestUris.stream().map(uri ->
PidfParserUtils.getNotFoundContactCapabilities(uri))
.collect(Collectors.toList());
response.addUpdatedCapabilities(capabilityList);
@@ -327,9 +329,18 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator {
// We treat the NOT FOUND is a successful result.
requestResult = sNetworkRespSuccessfulCreator.createRequestResult(taskId, response,
mRequestManagerCallback);
- }
+ } else {
+ // The request result is unsuccessful and it's not the NOT FOUND error. we need to get
+ // the capabilities from the cache.
+ List<RcsContactUceCapability> capabilitiesList =
+ getCapabilitiesFromCacheIncludingExpired(requestUris);
+ response.addUpdatedCapabilities(capabilitiesList);
+
+ // Add to the throttling list for the inconclusive result of the contacts.
+ mRequestManagerCallback.addToThrottlingList(requestUris,
+ response.getResponseSipCode().orElse(
+ com.android.ims.rcs.uce.util.NetworkSipCode.SIP_CODE_REQUEST_TIMEOUT));
- if (requestResult == null) {
requestResult = sNetworkRespErrorCreator.createRequestResult(taskId, response,
mRequestManagerCallback);
}
@@ -337,6 +348,41 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator {
}
/**
+ * Get the contact capabilities from the cache even if the capabilities have expired. If the
+ * capabilities doesn't exist, create the non-RCS capabilities instead.
+ * @param uris the uris to get the capabilities from cache.
+ * @return The contact capabilities for the given uris.
+ */
+ private List<RcsContactUceCapability> getCapabilitiesFromCacheIncludingExpired(List<Uri> uris) {
+ List<RcsContactUceCapability> resultList = new ArrayList<>();
+ List<RcsContactUceCapability> notFoundFromCacheList = new ArrayList<>();
+
+ // Get the capabilities from the cache.
+ List<EabCapabilityResult> eabResultList =
+ mRequestManagerCallback.getCapabilitiesFromCacheIncludingExpired(uris);
+
+ eabResultList.forEach(eabResult -> {
+ if (eabResult.getStatus() == EabCapabilityResult.EAB_QUERY_SUCCESSFUL ||
+ eabResult.getStatus() == EabCapabilityResult.EAB_CONTACT_EXPIRED_FAILURE) {
+ // The capabilities are found, add to the result list
+ resultList.add(eabResult.getContactCapabilities());
+ } else {
+ // Cannot get the capabilities from cache, create the non-RCS capabilities instead.
+ notFoundFromCacheList.add(PidfParserUtils.getNotFoundContactCapabilities(
+ eabResult.getContact()));
+ }
+ });
+
+ if (!notFoundFromCacheList.isEmpty()) {
+ resultList.addAll(notFoundFromCacheList);
+ }
+
+ logd("getCapabilitiesFromCacheIncludingExpired: requesting uris size=" + uris.size() +
+ ", capabilities not found from cache size=" + notFoundFromCacheList.size());
+ return resultList;
+ }
+
+ /**
* This method is called when the given SubscribeRequest received the onNotifyCapabilitiesUpdate
* callback from the ImsService.
*/
@@ -441,20 +487,39 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator {
}
/**
- * This method is called when the framework does not receive receive the result for
- * capabilities request.
+ * This method is called when the framework did not receive the capabilities request result.
*/
private void handleRequestTimeout(SubscribeRequest request) {
CapabilityRequestResponse response = request.getRequestResponse();
+ List<Uri> requestUris = response.getNotReceiveCapabilityUpdatedContact();
logd("handleRequestTimeout: " + response);
+ logd("handleRequestTimeout: not received updated uri size=" + requestUris.size());
- // Finish this request
- request.onFinish();
+ // Add to the throttling list for the inconclusive result of the contacts.
+ mRequestManagerCallback.addToThrottlingList(requestUris,
+ com.android.ims.rcs.uce.util.NetworkSipCode.SIP_CODE_REQUEST_TIMEOUT);
+
+ // Get the capabilities from the cache instead and add to the response.
+ List<RcsContactUceCapability> capabilitiesList =
+ getCapabilitiesFromCacheIncludingExpired(requestUris);
+ response.addUpdatedCapabilities(capabilitiesList);
+
+ // Trigger capabilities updated callback if there is any.
+ List<RcsContactUceCapability> updatedCapList = response.getUpdatedContactCapability();
+ if (!updatedCapList.isEmpty()) {
+ triggerCapabilitiesReceivedCallback(updatedCapList);
+ response.removeUpdatedCapabilities(updatedCapList);
+ }
// Remove this request from the activated collection and notify RequestManager.
long taskId = request.getTaskId();
RequestResult requestResult = sRequestTimeoutCreator.createRequestResult(taskId,
response, mRequestManagerCallback);
+
+ // Finish this request
+ request.onFinish();
+
+ // Remove this request from the activated collection and notify RequestManager.
moveRequestToFinishedCollection(taskId, requestResult);
}
diff --git a/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java b/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java
index f921ba2e..a18d8d60 100644
--- a/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java
+++ b/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java
@@ -157,11 +157,21 @@ public class UceRequestManager {
List<EabCapabilityResult> getCapabilitiesFromCache(List<Uri> uriList);
/**
+ * Retrieve the contact capabilities from the cache including the expired capabilities.
+ */
+ List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(List<Uri> uriList);
+
+ /**
* Retrieve the contact availability from the cache.
*/
EabCapabilityResult getAvailabilityFromCache(Uri uri);
/**
+ * Retrieve the contact availability from the cache including the expired capabilities.
+ */
+ EabCapabilityResult getAvailabilityFromCacheIncludingExpired(Uri uri);
+
+ /**
* Store the given contact capabilities to the cache.
*/
void saveCapabilities(List<RcsContactUceCapability> contactCapabilities);
@@ -250,6 +260,19 @@ public class UceRequestManager {
* to remove the coordinator from the UceRequestRepository.
*/
void notifyRequestCoordinatorFinished(long requestCoordinatorId);
+
+ /**
+ * Check whether the given uris are in the throttling list.
+ * @param uriList the uris to check if it is in the throttling list
+ * @return the uris in the throttling list
+ */
+ List<Uri> getInThrottlingListUris(List<Uri> uriList);
+
+ /**
+ * Add the given uris to the throttling list because the capabilities request result
+ * is inconclusive.
+ */
+ void addToThrottlingList(List<Uri> uriList, int sipCode);
}
private RequestManagerCallback mRequestMgrCallback = new RequestManagerCallback() {
@@ -264,11 +287,21 @@ public class UceRequestManager {
}
@Override
+ public List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(List<Uri> uris) {
+ return mControllerCallback.getCapabilitiesFromCacheIncludingExpired(uris);
+ }
+
+ @Override
public EabCapabilityResult getAvailabilityFromCache(Uri uri) {
return mControllerCallback.getAvailabilityFromCache(uri);
}
@Override
+ public EabCapabilityResult getAvailabilityFromCacheIncludingExpired(Uri uri) {
+ return mControllerCallback.getAvailabilityFromCacheIncludingExpired(uri);
+ }
+
+ @Override
public void saveCapabilities(List<RcsContactUceCapability> contactCapabilities) {
mControllerCallback.saveCapabilities(contactCapabilities);
}
@@ -359,12 +392,23 @@ public class UceRequestManager {
public void notifyRequestCoordinatorFinished(long requestCoordinatorId) {
mHandler.sendRequestCoordinatorFinishedMessage(requestCoordinatorId);
}
+
+ @Override
+ public List<Uri> getInThrottlingListUris(List<Uri> uriList) {
+ return mThrottlingList.getInThrottlingListUris(uriList);
+ }
+
+ @Override
+ public void addToThrottlingList(List<Uri> uriList, int sipCode) {
+ mThrottlingList.addToThrottlingList(uriList, sipCode);
+ }
};
private final int mSubId;
private final Context mContext;
private final UceRequestHandler mHandler;
private final UceRequestRepository mRequestRepository;
+ private final ContactThrottlingList mThrottlingList;
private volatile boolean mIsDestroyed;
private OptionsController mOptionsCtrl;
@@ -376,6 +420,7 @@ public class UceRequestManager {
mContext = context;
mControllerCallback = c;
mHandler = new UceRequestHandler(this, looper);
+ mThrottlingList = new ContactThrottlingList(mSubId);
mRequestRepository = new UceRequestRepository(subId, mRequestMgrCallback);
logi("create");
}
@@ -388,6 +433,7 @@ public class UceRequestManager {
mControllerCallback = c;
mHandler = new UceRequestHandler(this, looper);
mRequestRepository = requestRepository;
+ mThrottlingList = new ContactThrottlingList(mSubId);
}
/**
@@ -411,10 +457,18 @@ public class UceRequestManager {
logi("onDestroy");
mIsDestroyed = true;
mHandler.onDestroy();
+ mThrottlingList.reset();
mRequestRepository.onDestroy();
}
/**
+ * Clear the throttling list.
+ */
+ public void resetThrottlingList() {
+ mThrottlingList.reset();
+ }
+
+ /**
* Send a new capability request. It is called by UceController.
*/
public void sendCapabilityRequest(List<Uri> uriList, boolean skipFromCache,
diff --git a/src/java/com/android/ims/rcs/uce/util/UceUtils.java b/src/java/com/android/ims/rcs/uce/util/UceUtils.java
index c88de0b3..d93f2a00 100644
--- a/src/java/com/android/ims/rcs/uce/util/UceUtils.java
+++ b/src/java/com/android/ims/rcs/uce/util/UceUtils.java
@@ -53,6 +53,9 @@ public class UceUtils {
private static final long DEFAULT_CAP_REQUEST_TIMEOUT_AFTER_MS = TimeUnit.MINUTES.toMillis(3);
private static Optional<Long> OVERRIDE_CAP_REQUEST_TIMEOUT_AFTER_MS = Optional.empty();
+ // The default value of the availability cache expiration.
+ private static final long DEFAULT_AVAILABILITY_CACHE_EXPIRATION_SEC = 60L; // 60 seconds
+
// The task ID of the UCE request
private static long TASK_ID = 0L;
@@ -400,4 +403,26 @@ public class UceUtils {
}
return numberParts[0];
}
+
+ /**
+ * Get the availability expiration from provisioning manager.
+ * @param subId The subscription ID
+ * @return the number of seconds for the availability cache expiration.
+ */
+ public static long getAvailabilityCacheExpiration(int subId) {
+ long value = -1;
+ try {
+ ProvisioningManager pm = ProvisioningManager.createForSubscriptionId(subId);
+ value = pm.getProvisioningIntValue(
+ ProvisioningManager.KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC);
+ } catch (Exception e) {
+ Log.w(LOG_TAG, "Exception in getAvailabilityCacheExpiration: " + e);
+ }
+
+ if (value <= 0) {
+ Log.w(LOG_TAG, "The availability expiration cannot be less than 0.");
+ value = DEFAULT_AVAILABILITY_CACHE_EXPIRATION_SEC;
+ }
+ return value;
+ }
}