[automerger skipped] Merge Android 24Q2 Release (ab/11526283) to aosp-main-future am: f586b15694 -s ours
am skip reason: Merged-In Ice37eea8315c33013963a0db5779b0d1849a1974 with SHA-1 ba68f46b16 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/opt/net/ims/+/27273868
Change-Id: Icf3b65d91f2875806cbf5af305793fcca5e72192
Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/src/java/com/android/ims/rcs/uce/UceController.java b/src/java/com/android/ims/rcs/uce/UceController.java
index aeab061..ecf924b 100644
--- a/src/java/com/android/ims/rcs/uce/UceController.java
+++ b/src/java/com/android/ims/rcs/uce/UceController.java
@@ -52,6 +52,7 @@
import com.android.ims.rcs.uce.util.UceUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
+import com.android.internal.telephony.flags.FeatureFlags;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -150,11 +151,12 @@
@VisibleForTesting
public interface RequestManagerFactory {
UceRequestManager createRequestManager(Context context, int subId, Looper looper,
- UceControllerCallback callback);
+ UceControllerCallback callback, FeatureFlags featureFlags);
}
- private RequestManagerFactory mRequestManagerFactory = (context, subId, looper, callback) ->
- new UceRequestManager(context, subId, looper, callback);
+ private RequestManagerFactory mRequestManagerFactory =
+ (context, subId, looper, callback, featureFlags) ->
+ new UceRequestManager(context, subId, looper, callback, featureFlags);
/**
* Used to inject Controller instances for testing.
@@ -345,12 +347,14 @@
private UceDeviceState mDeviceState;
// The cache of the capability request event triggered by ImsService
private final CachedCapabilityEvent mCachedCapabilityEvent;
+ private final FeatureFlags mFeatureFlags;
- public UceController(Context context, int subId) {
+ public UceController(Context context, int subId, FeatureFlags featureFlags) {
mSubId = subId;
mContext = context;
mCachedCapabilityEvent = new CachedCapabilityEvent();
mRcsConnectedState = RCS_STATE_DISCONNECTED;
+ mFeatureFlags = featureFlags;
logi("create");
initLooper();
@@ -361,7 +365,8 @@
@VisibleForTesting
public UceController(Context context, int subId, UceDeviceState deviceState,
- ControllerFactory controllerFactory, RequestManagerFactory requestManagerFactory) {
+ ControllerFactory controllerFactory, RequestManagerFactory requestManagerFactory,
+ FeatureFlags featureFlags) {
mSubId = subId;
mContext = context;
mDeviceState = deviceState;
@@ -369,6 +374,7 @@
mRequestManagerFactory = requestManagerFactory;
mCachedCapabilityEvent = new CachedCapabilityEvent();
mRcsConnectedState = RCS_STATE_DISCONNECTED;
+ mFeatureFlags = featureFlags;
initLooper();
initControllers();
initRequestManager();
@@ -392,7 +398,7 @@
private void initRequestManager() {
mRequestManager = mRequestManagerFactory.createRequestManager(mContext, mSubId, mLooper,
- mCtrlCallback);
+ mCtrlCallback, mFeatureFlags);
mRequestManager.setSubscribeController(mSubscribeController);
mRequestManager.setOptionsController(mOptionsController);
}
@@ -474,6 +480,7 @@
mPublishController.onCarrierConfigChanged();
mSubscribeController.onCarrierConfigChanged();
mOptionsController.onCarrierConfigChanged();
+ mRequestManager.onCarrierConfigChanged();
}
private void handleCachedCapabilityEvent() {
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 17cec90..248b079 100644
--- a/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java
+++ b/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java
@@ -51,6 +51,8 @@
protected volatile long mCoordinatorId;
protected volatile boolean mIsFinished;
protected volatile boolean mSkipGettingFromCache;
+ protected int mCurrentRetryCount;
+ protected boolean mRetryEnabled;
public CapabilityRequest(int subId, @UceRequestType int type, RequestManagerCallback callback) {
mSubId = subId;
@@ -59,6 +61,8 @@
mRequestManagerCallback = callback;
mRequestResponse = new CapabilityRequestResponse();
mTaskId = UceUtils.generateTaskId();
+ mCurrentRetryCount = 0;
+ mRetryEnabled = false;
}
@VisibleForTesting
@@ -70,6 +74,8 @@
mRequestManagerCallback = callback;
mRequestResponse = requestResponse;
mTaskId = UceUtils.generateTaskId();
+ mCurrentRetryCount = 0;
+ mRetryEnabled = false;
}
@Override
@@ -185,6 +191,22 @@
}
}
+ public int getRetryCount() {
+ return mCurrentRetryCount;
+ }
+
+ public void setRetryCount(int retryCount) {
+ mCurrentRetryCount = retryCount;
+ }
+
+ public boolean isRetryEnabled() {
+ return mRetryEnabled;
+ }
+
+ public void setRetryEnabled(boolean enabled) {
+ mRetryEnabled = enabled;
+ }
+
// Check whether this request is allowed to be executed or not.
private boolean isRequestAllowed() {
if (mUriList == null || mUriList.isEmpty()) {
diff --git a/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java b/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java
index a306eb4..b3b4d14 100644
--- a/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java
+++ b/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java
@@ -17,14 +17,15 @@
package com.android.ims.rcs.uce.request;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.Uri;
import android.os.RemoteException;
+import android.telephony.CarrierConfigManager;
import android.telephony.ims.RcsContactTerminatedReason;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.SipDetails;
import android.telephony.ims.aidl.ISubscribeResponseCallback;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase;
import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.CommandCode;
import com.android.ims.rcs.uce.eab.EabCapabilityResult;
@@ -34,6 +35,7 @@
import com.android.ims.rcs.uce.presence.subscribe.SubscribeController;
import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.FeatureFlags;
import java.util.ArrayList;
import java.util.Collections;
@@ -46,6 +48,7 @@
* network.
*/
public class SubscribeRequest extends CapabilityRequest {
+ public static final int MAX_RETRY_COUNT = 1;
// The result callback of the capabilities request from IMS service.
private final ISubscribeResponseCallback mResponseCallback =
@@ -73,20 +76,24 @@
};
private SubscribeController mSubscribeController;
+ private final FeatureFlags mFeatureFlags;
public SubscribeRequest(int subId, @UceRequestType int requestType,
- RequestManagerCallback taskMgrCallback, SubscribeController subscribeController) {
+ RequestManagerCallback taskMgrCallback, SubscribeController subscribeController,
+ FeatureFlags featureFlags) {
super(subId, requestType, taskMgrCallback);
mSubscribeController = subscribeController;
+ mFeatureFlags = featureFlags;
logd("SubscribeRequest created");
}
@VisibleForTesting
public SubscribeRequest(int subId, @UceRequestType int requestType,
RequestManagerCallback taskMgrCallback, SubscribeController subscribeController,
- CapabilityRequestResponse requestResponse) {
+ CapabilityRequestResponse requestResponse, FeatureFlags featureFlags) {
super(subId, requestType, taskMgrCallback, requestResponse);
mSubscribeController = subscribeController;
+ mFeatureFlags = featureFlags;
}
@Override
@@ -126,6 +133,26 @@
logw("onCommandError: request is already finished");
return;
}
+
+ if (mFeatureFlags.enableSipSubscribeRetry()
+ && cmdError == RcsCapabilityExchangeImplBase.COMMAND_CODE_REQUEST_TIMEOUT
+ && isRetryEnabled()) {
+ int retryCount = getRetryCount();
+ if (retryCount < MAX_RETRY_COUNT) {
+ CapabilityRequest request = new SubscribeRequest(mSubId, mRequestType,
+ mRequestManagerCallback, mSubscribeController, mFeatureFlags);
+ request.setContactUri(getContactUri());
+ request.setRetryCount(retryCount + 1);
+ // Do not use the cached capability to retry
+ request.setSkipGettingFromCache(true);
+
+ mRequestManagerCallback.sendSubscribeRetryRequest(request);
+ logd("onCommandError: Retry subscribe request");
+ } else {
+ logd("onCommandError: Reached max retry");
+ }
+ }
+
mRequestResponse.setCommandError(cmdError);
mRequestManagerCallback.notifyCommandError(mCoordinatorId, mTaskId);
}
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 26143f9..4232704 100644
--- a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java
+++ b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java
@@ -578,8 +578,10 @@
*/
private void triggerCapabilitiesReceivedCallback(List<RcsContactUceCapability> capList) {
try {
- logd("triggerCapabilitiesCallback: size=" + capList.size());
- mCapabilitiesCallback.onCapabilitiesReceived(capList);
+ if (mCapabilitiesCallback != null) {
+ logd("triggerCapabilitiesCallback: size=" + capList.size());
+ mCapabilitiesCallback.onCapabilitiesReceived(capList);
+ }
} catch (RemoteException e) {
logw("triggerCapabilitiesCallback exception: " + e);
} finally {
@@ -592,8 +594,10 @@
*/
private void triggerCompletedCallback(@Nullable SipDetails details) {
try {
- logd("triggerCompletedCallback");
- mCapabilitiesCallback.onComplete(details);
+ if (mCapabilitiesCallback != null) {
+ logd("triggerCompletedCallback");
+ mCapabilitiesCallback.onComplete(details);
+ }
} catch (RemoteException e) {
logw("triggerCompletedCallback exception: " + e);
} finally {
@@ -607,8 +611,11 @@
private void triggerErrorCallback(int errorCode, long retryAfterMillis,
@Nullable SipDetails details) {
try {
- logd("triggerErrorCallback: errorCode=" + errorCode + ", retry=" + retryAfterMillis);
- mCapabilitiesCallback.onError(errorCode, retryAfterMillis, details);
+ if (mCapabilitiesCallback != null) {
+ logd("triggerErrorCallback: errorCode=" + errorCode
+ + ", retry=" + retryAfterMillis);
+ mCapabilitiesCallback.onError(errorCode, retryAfterMillis, details);
+ }
} catch (RemoteException e) {
logw("triggerErrorCallback exception: " + e);
} finally {
diff --git a/src/java/com/android/ims/rcs/uce/request/UceRequest.java b/src/java/com/android/ims/rcs/uce/request/UceRequest.java
index 197f4ba..c2b0160 100644
--- a/src/java/com/android/ims/rcs/uce/request/UceRequest.java
+++ b/src/java/com/android/ims/rcs/uce/request/UceRequest.java
@@ -70,4 +70,30 @@
* Execute the request.
*/
void executeRequest();
+
+ /**
+ * @return The number of retries for the current request.
+ */
+ default int getRetryCount() {
+ return 0;
+ };
+
+ /**
+ * Set the number of retries for the current request.
+ */
+ default void setRetryCount(int retries) {
+ };
+
+ /**
+ * @return The whether to allow request retry.
+ */
+ default boolean isRetryEnabled() {
+ return false;
+ };
+
+ /**
+ * Set whether to allow request retry.
+ */
+ default void setRetryEnabled(boolean enabled) {
+ };
}
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 8ff39c1..8955ec4 100644
--- a/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java
+++ b/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java
@@ -16,12 +16,16 @@
package com.android.ims.rcs.uce.request;
+import static com.android.ims.rcs.uce.request.UceRequest.REQUEST_TYPE_CAPABILITY;
+
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.RemoteException;
+import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.RcsContactUceCapability.CapabilityMechanism;
@@ -46,6 +50,7 @@
import com.android.ims.rcs.uce.util.UceUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
+import com.android.internal.telephony.flags.FeatureFlags;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -107,6 +112,11 @@
* @return true if the given phone number is blocked by the network.
*/
boolean isNumberBlocked(Context context, String phoneNumber);
+
+ /**
+ * @return subscribe retry duration in milliseconds.
+ */
+ long getSubscribeRetryDuration(Context context, int subId);
}
private static UceUtilsProxy sUceUtilsProxy = new UceUtilsProxy() {
@@ -139,11 +149,20 @@
public boolean isNumberBlocked(Context context, String phoneNumber) {
return UceUtils.isNumberBlocked(context, phoneNumber);
}
+
+ @Override
+ public long getSubscribeRetryDuration(Context context, int subId) {
+ return UceUtils.getSubscribeRetryInterval(context, subId);
+ }
};
@VisibleForTesting
public void setsUceUtilsProxy(UceUtilsProxy uceUtilsProxy) {
sUceUtilsProxy = uceUtilsProxy;
+
+ // Update values for testing
+ mRetryDuration = sUceUtilsProxy.getSubscribeRetryDuration(mContext, mSubId);
+ mRetryEnabled = mRetryDuration >= 0L;
}
/**
@@ -277,6 +296,11 @@
* is inconclusive.
*/
void addToThrottlingList(List<Uri> uriList, int sipCode);
+
+ /**
+ * Send subscribe request to retry.
+ */
+ void sendSubscribeRetryRequest(UceRequest request);
}
private RequestManagerCallback mRequestMgrCallback = new RequestManagerCallback() {
@@ -406,6 +430,11 @@
public void addToThrottlingList(List<Uri> uriList, int sipCode) {
mThrottlingList.addToThrottlingList(uriList, sipCode);
}
+
+ @Override
+ public void sendSubscribeRetryRequest(UceRequest request) {
+ UceRequestManager.this.sendSubscribeRetryRequest(request);
+ }
};
private final int mSubId;
@@ -413,31 +442,39 @@
private final UceRequestHandler mHandler;
private final UceRequestRepository mRequestRepository;
private final ContactThrottlingList mThrottlingList;
+ private final FeatureFlags mFeatureFlags;
private volatile boolean mIsDestroyed;
private OptionsController mOptionsCtrl;
private SubscribeController mSubscribeCtrl;
private UceControllerCallback mControllerCallback;
+ private boolean mRetryEnabled;
+ private long mRetryDuration;
- public UceRequestManager(Context context, int subId, Looper looper, UceControllerCallback c) {
+ public UceRequestManager(Context context, int subId, Looper looper, UceControllerCallback c,
+ FeatureFlags featureFlags) {
mSubId = subId;
mContext = context;
mControllerCallback = c;
mHandler = new UceRequestHandler(this, looper);
mThrottlingList = new ContactThrottlingList(mSubId);
mRequestRepository = new UceRequestRepository(subId, mRequestMgrCallback);
+ mRetryDuration = sUceUtilsProxy.getSubscribeRetryDuration(mContext, mSubId);
+ mRetryEnabled = mRetryDuration >= 0L;
+ mFeatureFlags = featureFlags;
logi("create");
}
@VisibleForTesting
public UceRequestManager(Context context, int subId, Looper looper, UceControllerCallback c,
- UceRequestRepository requestRepository) {
+ UceRequestRepository requestRepository, FeatureFlags featureFlags) {
mSubId = subId;
mContext = context;
mControllerCallback = c;
mHandler = new UceRequestHandler(this, looper);
mRequestRepository = requestRepository;
mThrottlingList = new ContactThrottlingList(mSubId);
+ mFeatureFlags = featureFlags;
}
/**
@@ -473,6 +510,16 @@
}
/**
+ * Notify carrier config changed and update cached value.
+ */
+ public void onCarrierConfigChanged() {
+ mRetryDuration = sUceUtilsProxy.getSubscribeRetryDuration(mContext, mSubId);
+ mRetryEnabled = mRetryDuration >= 0L;
+
+ logd("carrier config changed : retry duration = " + mRetryDuration);
+ }
+
+ /**
* Send a new capability request. It is called by UceController.
*/
public void sendCapabilityRequest(List<Uri> uriList, boolean skipFromCache,
@@ -481,7 +528,7 @@
callback.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null);
return;
}
- sendRequestInternal(UceRequest.REQUEST_TYPE_CAPABILITY, uriList, skipFromCache, callback);
+ sendRequestInternal(REQUEST_TYPE_CAPABILITY, uriList, skipFromCache, callback);
}
/**
@@ -497,6 +544,35 @@
Collections.singletonList(uri), false /* skipFromCache */, callback);
}
+ private void sendSubscribeRetryRequest(UceRequest request) {
+ if (!mFeatureFlags.enableSipSubscribeRetry()) {
+ logw("Retry subscribe is not allowed");
+ return;
+ }
+
+ if (request == null || !SubscribeRequest.class.isInstance(request)) {
+ logw("parameter is not available for retry");
+ return;
+ }
+
+ // Handle subscribe retry in background, don't need to consider the cached capabilities
+ // and the callback to notify the result of operation.
+ UceRequestCoordinator requestCoordinator =
+ createSubscribeRequestCoordinatorForRetry(request);
+
+ if (requestCoordinator == null) {
+ logw("createSubscribeRequestCoordinator failed for retry");
+ return;
+ }
+ addRequestCoordinator(requestCoordinator);
+
+ // Send delay message to retry.
+ Long coordinatorId = requestCoordinator.getCoordinatorId();
+ Long taskId = request.getTaskId();
+ mHandler.sendRequestMessage(coordinatorId, taskId, mRetryDuration);
+ logd("sent message for retry " + coordinatorId + " " + taskId + " " + mRetryDuration);
+ }
+
private void sendRequestInternal(@UceRequestType int type, List<Uri> uriList,
boolean skipFromCache, IRcsUceControllerCallback callback) throws RemoteException {
UceRequestCoordinator requestCoordinator = null;
@@ -538,7 +614,7 @@
logd(builder.toString());
// Add this RequestCoordinator to the UceRequestRepository.
- addRequestCoordinator(requestCoordinator);
+ addRequestCoordinatorAndDispatch(requestCoordinator);
}
/**
@@ -584,7 +660,7 @@
private List<RcsContactUceCapability> getCapabilitiesFromCache(int requestType,
List<Uri> uriList) {
List<EabCapabilityResult> resultList = Collections.emptyList();
- if (requestType == UceRequest.REQUEST_TYPE_CAPABILITY) {
+ if (requestType == REQUEST_TYPE_CAPABILITY) {
resultList = mRequestMgrCallback.getCapabilitiesFromCache(uriList);
} else if (requestType == UceRequest.REQUEST_TYPE_AVAILABILITY) {
// Always get the first element if the request type is availability.
@@ -602,7 +678,6 @@
private UceRequestCoordinator createSubscribeRequestCoordinator(final @UceRequestType int type,
final List<Uri> uriList, boolean skipFromCache, IRcsUceControllerCallback callback) {
SubscribeRequestCoordinator.Builder builder;
-
if (!sUceUtilsProxy.isPresenceGroupSubscribeEnabled(mContext, mSubId)) {
// When the group subscribe is disabled, each contact is required to be encapsulated
// into individual UceRequest.
@@ -628,7 +703,10 @@
individualUri = Collections.singletonList(getSipUriFromUri(uri));
}
}
+
UceRequest request = createSubscribeRequest(type, individualUri, skipFromCache);
+ // Set whether retry is allowed
+ request.setRetryEnabled(mRetryEnabled);
requestList.add(request);
});
builder = new SubscribeRequestCoordinator.Builder(mSubId, requestList,
@@ -645,14 +723,22 @@
for (int index = 0; index < rclMaxNumber; index++) {
subUriList.add(uriList.get(count * rclMaxNumber + index));
}
- requestList.add(createSubscribeRequest(type, subUriList, skipFromCache));
+
+ UceRequest request = createSubscribeRequest(type, subUriList, skipFromCache);
+ // Set whether retry is allowed
+ request.setRetryEnabled(mRetryEnabled);
+ requestList.add(request);
}
List<Uri> subUriList = new ArrayList<>();
for (int i = numRequestCoordinators * rclMaxNumber; i < uriList.size(); i++) {
subUriList.add(uriList.get(i));
}
- requestList.add(createSubscribeRequest(type, subUriList, skipFromCache));
+
+ UceRequest request = createSubscribeRequest(type, subUriList, skipFromCache);
+ // Set whether retry is allowed
+ request.setRetryEnabled(mRetryEnabled);
+ requestList.add(request);
builder = new SubscribeRequestCoordinator.Builder(mSubId, requestList,
mRequestMgrCallback);
@@ -661,6 +747,17 @@
return builder.build();
}
+ private UceRequestCoordinator createSubscribeRequestCoordinatorForRetry(UceRequest request) {
+ SubscribeRequestCoordinator.Builder builder;
+
+ List<UceRequest> requestList = new ArrayList<>();
+ requestList.add(request);
+ builder = new SubscribeRequestCoordinator.Builder(mSubId, requestList,
+ mRequestMgrCallback);
+ builder.setCapabilitiesCallback(null);
+ return builder.build();
+ }
+
private UceRequestCoordinator createOptionsRequestCoordinator(@UceRequestType int type,
List<Uri> uriList, IRcsUceControllerCallback callback) {
OptionsRequestCoordinator.Builder builder;
@@ -678,7 +775,7 @@
private CapabilityRequest createSubscribeRequest(int type, List<Uri> uriList,
boolean skipFromCache) {
CapabilityRequest request = new SubscribeRequest(mSubId, type, mRequestMgrCallback,
- mSubscribeCtrl);
+ mSubscribeCtrl, mFeatureFlags);
request.setContactUri(uriList);
request.setSkipGettingFromCache(skipFromCache);
return request;
@@ -723,7 +820,7 @@
logd(builder.toString());
// Add this RequestCoordinator to the UceRequestRepository.
- addRequestCoordinator(requestCoordinator);
+ addRequestCoordinatorAndDispatch(requestCoordinator);
}
private static class UceRequestHandler extends Handler {
@@ -732,7 +829,6 @@
private static final int EVENT_REQUEST_TIMEOUT = 3;
private static final int EVENT_REQUEST_FINISHED = 4;
private static final int EVENT_COORDINATOR_FINISHED = 5;
-
private final Map<Long, SomeArgs> mRequestTimeoutTimers;
private final WeakReference<UceRequestManager> mUceRequestMgrRef;
@@ -926,14 +1022,18 @@
}
}
- private void addRequestCoordinator(UceRequestCoordinator coordinator) {
- mRequestRepository.addRequestCoordinator(coordinator);
+ private void addRequestCoordinatorAndDispatch(UceRequestCoordinator coordinator) {
+ mRequestRepository.addRequestCoordinatorAndDispatch(coordinator);
}
private UceRequestCoordinator removeRequestCoordinator(Long coordinatorId) {
return mRequestRepository.removeRequestCoordinator(coordinatorId);
}
+ private void addRequestCoordinator(UceRequestCoordinator coordinator) {
+ mRequestRepository.addRequestCoordinator(coordinator);
+ }
+
private UceRequestCoordinator getRequestCoordinator(Long coordinatorId) {
return mRequestRepository.getRequestCoordinator(coordinatorId);
}
diff --git a/src/java/com/android/ims/rcs/uce/request/UceRequestRepository.java b/src/java/com/android/ims/rcs/uce/request/UceRequestRepository.java
index 1d2c1e8..f50c5e4 100644
--- a/src/java/com/android/ims/rcs/uce/request/UceRequestRepository.java
+++ b/src/java/com/android/ims/rcs/uce/request/UceRequestRepository.java
@@ -53,7 +53,7 @@
* Add new UceRequestCoordinator and notify the RequestDispatcher to check whether the given
* requests can be executed or not.
*/
- public synchronized void addRequestCoordinator(UceRequestCoordinator coordinator) {
+ public synchronized void addRequestCoordinatorAndDispatch(UceRequestCoordinator coordinator) {
if (mDestroyed) return;
mRequestCoordinators.put(coordinator.getCoordinatorId(), coordinator);
mDispatcher.addRequest(coordinator.getCoordinatorId(),
@@ -69,6 +69,14 @@
}
/**
+ * Add new UceRequestCoordinator for retry only and not execute the given request.
+ */
+ public synchronized void addRequestCoordinator(UceRequestCoordinator coordinator) {
+ if (mDestroyed) return;
+ mRequestCoordinators.put(coordinator.getCoordinatorId(), coordinator);
+ }
+
+ /**
* Retrieve the RequestCoordinator associated with the given coordinatorId.
*/
public synchronized UceRequestCoordinator getRequestCoordinator(Long coordinatorId) {
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 c5f2b12..dadf582 100644
--- a/src/java/com/android/ims/rcs/uce/util/UceUtils.java
+++ b/src/java/com/android/ims/rcs/uce/util/UceUtils.java
@@ -459,4 +459,23 @@
}
return value;
}
+
+ /**
+ * The time interval of milliseconds for the subscribe retry.
+ *
+ * @return The time interval of milliseconds for the subscribe retry.
+ */
+ public static long getSubscribeRetryInterval(Context context, int subId) {
+ CarrierConfigManager configManager = context.getSystemService(CarrierConfigManager.class);
+ if (configManager == null) {
+ return -1L;
+ }
+ PersistableBundle config = configManager.getConfigForSubId(subId);
+ if (config == null) {
+ return -1L;
+ }
+
+ return config.getLong(
+ CarrierConfigManager.Ims.KEY_SUBSCRIBE_RETRY_DURATION_MILLIS_LONG, -1L);
+ }
}
diff --git a/tests/src/com/android/ims/rcs/uce/UceControllerTest.java b/tests/src/com/android/ims/rcs/uce/UceControllerTest.java
index 79702ed..6f7104b 100644
--- a/tests/src/com/android/ims/rcs/uce/UceControllerTest.java
+++ b/tests/src/com/android/ims/rcs/uce/UceControllerTest.java
@@ -42,6 +42,7 @@
import com.android.ims.rcs.uce.presence.subscribe.SubscribeController;
import com.android.ims.rcs.uce.request.UceRequestManager;
import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult;
+import com.android.internal.telephony.flags.FeatureFlags;
import java.util.ArrayList;
import java.util.List;
@@ -71,6 +72,7 @@
@Mock UceController.UceControllerCallback mCallback;
@Mock IRcsUceControllerCallback mCapabilitiesCallback;
@Mock IOptionsRequestCallback mOptionsRequestCallback;
+ @Mock FeatureFlags mFeatureFlags;
private int mSubId = 1;
@@ -86,7 +88,7 @@
doReturn(mOptionsController).when(mControllerFactory).createOptionsController(any(),
eq(mSubId));
doReturn(mTaskManager).when(mTaskManagerFactory).createRequestManager(any(), eq(mSubId),
- any(), any());
+ any(), any(), any());
doReturn(mDeviceStateResult).when(mDeviceState).getCurrentState();
}
@@ -280,7 +282,7 @@
private UceController createUceController() {
UceController uceController = new UceController(mContext, mSubId, mDeviceState,
- mControllerFactory, mTaskManagerFactory);
+ mControllerFactory, mTaskManagerFactory, mFeatureFlags);
uceController.setUceControllerCallback(mCallback);
return uceController;
}
diff --git a/tests/src/com/android/ims/rcs/uce/request/SubscribeRequestTest.java b/tests/src/com/android/ims/rcs/uce/request/SubscribeRequestTest.java
index 543ad6d..ee0f7be 100644
--- a/tests/src/com/android/ims/rcs/uce/request/SubscribeRequestTest.java
+++ b/tests/src/com/android/ims/rcs/uce/request/SubscribeRequestTest.java
@@ -18,6 +18,7 @@
import static android.telephony.ims.stub.RcsCapabilityExchangeImplBase.COMMAND_CODE_NOT_SUPPORTED;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -25,6 +26,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.net.Uri;
@@ -32,6 +34,7 @@
import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.SipDetails;
import android.telephony.ims.aidl.ISubscribeResponseCallback;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -39,11 +42,13 @@
import com.android.ims.ImsTestBase;
import com.android.ims.rcs.uce.presence.subscribe.SubscribeController;
import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
+import com.android.internal.telephony.flags.FeatureFlags;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.util.ArrayList;
@@ -51,10 +56,13 @@
@RunWith(AndroidJUnit4.class)
public class SubscribeRequestTest extends ImsTestBase {
+ private static final Uri CONTACT1 = Uri.fromParts("sip", "test1", null);
+ private static final Uri CONTACT2 = Uri.fromParts("sip", "test2", null);
@Mock SubscribeController mSubscribeController;
@Mock CapabilityRequestResponse mRequestResponse;
@Mock RequestManagerCallback mRequestManagerCallback;
+ @Mock FeatureFlags mFeatureFlags;
private int mSubId = 1;
private long mCoordId = 1;
@@ -62,6 +70,7 @@
@Before
public void setUp() throws Exception {
super.setUp();
+ doReturn(false).when(mFeatureFlags).enableSipSubscribeRetry();
}
@After
@@ -173,9 +182,88 @@
verify(mRequestManagerCallback).notifyTerminated(eq(mCoordId), anyLong());
}
+ @Test
+ @SmallTest
+ public void testSipSubscribeRetryWithDisabledFeatureFlag() throws Exception {
+ doReturn(false).when(mFeatureFlags).enableSipSubscribeRetry();
+
+ SubscribeRequest subscribeRequest = getSubscribeRequest();
+ List<Uri> uriList = new ArrayList<>();
+ uriList.add(CONTACT1);
+ uriList.add(CONTACT2);
+ subscribeRequest.setContactUri(uriList);
+ subscribeRequest.setRetryEnabled(true);
+ subscribeRequest.setRetryCount(0);
+ ISubscribeResponseCallback callback = subscribeRequest.getResponseCallback();
+ int errorCommand = RcsCapabilityExchangeImplBase.COMMAND_CODE_REQUEST_TIMEOUT;
+ callback.onCommandError(errorCommand);
+
+ verify(mRequestResponse).setCommandError(eq(errorCommand));
+ verify(mRequestResponse, never()).setSipDetails(any(SipDetails.class));
+ verify(mRequestManagerCallback).notifyCommandError(eq(mCoordId), anyLong());
+
+ // Verify that subscribe request is not retried
+ verify(mRequestManagerCallback, never()).sendSubscribeRetryRequest(any());
+ }
+
+ @Test
+ @SmallTest
+ public void testSipSubscribeRetry() throws Exception {
+ doReturn(true).when(mFeatureFlags).enableSipSubscribeRetry();
+
+ SubscribeRequest subscribeRequest = getSubscribeRequest();
+ List<Uri> uriList = new ArrayList<>();
+ uriList.add(CONTACT1);
+ uriList.add(CONTACT2);
+ subscribeRequest.setContactUri(uriList);
+ subscribeRequest.setRetryEnabled(true);
+ subscribeRequest.setRetryCount(0);
+ ISubscribeResponseCallback callback = subscribeRequest.getResponseCallback();
+ int errorCommand = RcsCapabilityExchangeImplBase.COMMAND_CODE_REQUEST_TIMEOUT;
+ callback.onCommandError(errorCommand);
+
+ verify(mRequestResponse).setCommandError(eq(errorCommand));
+ verify(mRequestResponse, never()).setSipDetails(any(SipDetails.class));
+ verify(mRequestManagerCallback).notifyCommandError(eq(mCoordId), anyLong());
+
+ ArgumentCaptor<CapabilityRequest> captor =
+ ArgumentCaptor.forClass(CapabilityRequest.class);
+ verify(mRequestManagerCallback, times(1)).sendSubscribeRetryRequest(captor.capture());
+ CapabilityRequest retrySubscribeRequest = captor.getValue();
+
+ // The number of contacts is the same, but the retryCount is greater than 1.
+ assertEquals(subscribeRequest.getContactUri().size(),
+ retrySubscribeRequest.getContactUri().size());
+ assertEquals(subscribeRequest.getRetryCount() + 1, retrySubscribeRequest.getRetryCount());
+ }
+
+ @Test
+ @SmallTest
+ public void testSipSubscribeReachMaxRetry() throws Exception {
+ doReturn(true).when(mFeatureFlags).enableSipSubscribeRetry();
+
+ // Reach max retry request and received onCommandError with COMMAND_CODE_REQUEST_TIMEOUT.
+ SubscribeRequest subscribeRetryRequest = getSubscribeRequest();
+ List<Uri> uriList = new ArrayList<>();
+ uriList.add(CONTACT1);
+ uriList.add(CONTACT2);
+ subscribeRetryRequest.setContactUri(uriList);
+ subscribeRetryRequest.setRetryEnabled(true);
+ subscribeRetryRequest.setRetryCount(SubscribeRequest.MAX_RETRY_COUNT);
+ ISubscribeResponseCallback callback = subscribeRetryRequest.getResponseCallback();
+ int errorCommand = RcsCapabilityExchangeImplBase.COMMAND_CODE_REQUEST_TIMEOUT;
+ callback.onCommandError(errorCommand);
+
+ verify(mRequestResponse).setCommandError(eq(errorCommand));
+ verify(mRequestResponse, never()).setSipDetails(any(SipDetails.class));
+ verify(mRequestManagerCallback).notifyCommandError(eq(mCoordId), anyLong());
+ // Verify that retry method was not called.
+ verify(mRequestManagerCallback, never()).sendSubscribeRetryRequest(any());
+ }
+
private SubscribeRequest getSubscribeRequest() {
SubscribeRequest request = new SubscribeRequest(mSubId, UceRequest.REQUEST_TYPE_CAPABILITY,
- mRequestManagerCallback, mSubscribeController, mRequestResponse);
+ mRequestManagerCallback, mSubscribeController, mRequestResponse, mFeatureFlags);
request.setRequestCoordinatorId(mCoordId);
return request;
}
diff --git a/tests/src/com/android/ims/rcs/uce/request/UceRequestManagerTest.java b/tests/src/com/android/ims/rcs/uce/request/UceRequestManagerTest.java
index fa8214e..a3dc588 100644
--- a/tests/src/com/android/ims/rcs/uce/request/UceRequestManagerTest.java
+++ b/tests/src/com/android/ims/rcs/uce/request/UceRequestManagerTest.java
@@ -34,6 +34,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -52,21 +53,24 @@
import com.android.ims.rcs.uce.UceController;
import com.android.ims.rcs.uce.UceController.UceControllerCallback;
import com.android.ims.rcs.uce.eab.EabCapabilityResult;
+import com.android.ims.rcs.uce.presence.subscribe.SubscribeController;
import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
import com.android.ims.rcs.uce.request.UceRequestManager.UceUtilsProxy;
import com.android.ims.rcs.uce.util.FeatureTags;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
+import com.android.internal.telephony.flags.FeatureFlags;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
@RunWith(AndroidJUnit4.class)
public class UceRequestManagerTest extends ImsTestBase {
@@ -76,6 +80,9 @@
@Mock UceRequestRepository mRequestRepository;
@Mock IRcsUceControllerCallback mCapabilitiesCallback;
@Mock IOptionsRequestCallback mOptionsReqCallback;
+ @Mock SubscribeController mSubscribeController;
+ @Mock CapabilityRequestResponse mRequestResponse;
+ @Mock FeatureFlags mFeatureFlags;
private int mSubId = 1;
private long mTaskId = 1L;
@@ -98,32 +105,35 @@
@SmallTest
public void testSendCapabilityRequest() throws Exception {
UceRequestManager requestManager = getUceRequestManager();
- requestManager.setsUceUtilsProxy(getUceUtilsProxy(true, true, false, false, true, 10));
+ requestManager.setsUceUtilsProxy(getUceUtilsProxy(
+ true, true, false, false, true, 10, false, 0));
List<Uri> uriList = new ArrayList<>();
uriList.add(Uri.fromParts("sip", "test", null));
requestManager.sendCapabilityRequest(uriList, false, mCapabilitiesCallback);
- verify(mRequestRepository).addRequestCoordinator(any());
+ verify(mRequestRepository).addRequestCoordinatorAndDispatch(any());
}
@Test
@SmallTest
public void testSendAvailabilityRequest() throws Exception {
UceRequestManager requestManager = getUceRequestManager();
- requestManager.setsUceUtilsProxy(getUceUtilsProxy(true, true, false, false, true, 10));
+ requestManager.setsUceUtilsProxy(getUceUtilsProxy(
+ true, true, false, false, true, 10, false, 0));
Uri uri = Uri.fromParts("sip", "test", null);
requestManager.sendAvailabilityRequest(uri, mCapabilitiesCallback);
- verify(mRequestRepository).addRequestCoordinator(any());
+ verify(mRequestRepository).addRequestCoordinatorAndDispatch(any());
}
@Test
@SmallTest
public void testRequestDestroyed() throws Exception {
UceRequestManager requestManager = getUceRequestManager();
- requestManager.setsUceUtilsProxy(getUceUtilsProxy(true, true, true, false, true, 10));
+ requestManager.setsUceUtilsProxy(getUceUtilsProxy(
+ true, true, true, false, true, 10, false, 0));
requestManager.onDestroy();
@@ -145,7 +155,9 @@
@SmallTest
public void testCacheHitShortcut() throws Exception {
UceRequestManager requestManager = getUceRequestManager();
- requestManager.setsUceUtilsProxy(getUceUtilsProxy(true, true, true, false, true, 10));
+ requestManager.setsUceUtilsProxy(getUceUtilsProxy(
+ true, true, true, false, true, 10, false, 0));
+
Handler handler = requestManager.getUceRequestHandler();
List<Uri> uriList = new ArrayList<>();
@@ -167,7 +179,7 @@
Collectors.toList()));
verify(mCapabilitiesCallback).onComplete(eq(null));
// The cache should have been hit, so no network requests should have been generated.
- verify(mRequestRepository, never()).addRequestCoordinator(any());
+ verify(mRequestRepository, never()).addRequestCoordinatorAndDispatch(any());
}
/**
@@ -178,7 +190,9 @@
@SmallTest
public void testCacheExpiredShortcut() throws Exception {
UceRequestManager requestManager = getUceRequestManager();
- requestManager.setsUceUtilsProxy(getUceUtilsProxy(true, true, true, false, true, 10));
+ requestManager.setsUceUtilsProxy(getUceUtilsProxy(
+ true, true, true, false, true, 10, false, 0));
+
Handler handler = requestManager.getUceRequestHandler();
List<Uri> uriList = new ArrayList<>();
@@ -199,7 +213,7 @@
verify(mCapabilitiesCallback, never()).onCapabilitiesReceived(any());
verify(mCapabilitiesCallback, never()).onComplete(any());
// A network request should have been generated for the expired contact.
- verify(mRequestRepository).addRequestCoordinator(any());
+ verify(mRequestRepository).addRequestCoordinatorAndDispatch(any());
}
/**
@@ -212,7 +226,9 @@
@SmallTest
public void testCacheHitShortcutForSubsetOfCaps() throws Exception {
UceRequestManager requestManager = getUceRequestManager();
- requestManager.setsUceUtilsProxy(getUceUtilsProxy(true, true, true, false, true, 10));
+ requestManager.setsUceUtilsProxy(getUceUtilsProxy(
+ true, true, true, false, true, 10, false, 0));
+
Handler handler = requestManager.getUceRequestHandler();
List<Uri> uriList = new ArrayList<>();
@@ -244,14 +260,16 @@
verify(mCapabilitiesCallback, never()).onComplete(any());
// The cache should have been hit, but there was also entry that was not in the cache, so
// ensure that is requested.
- verify(mRequestRepository).addRequestCoordinator(any());
+ verify(mRequestRepository).addRequestCoordinatorAndDispatch(any());
}
@Test
@SmallTest
public void testRequestManagerCallback() throws Exception {
UceRequestManager requestManager = getUceRequestManager();
- requestManager.setsUceUtilsProxy(getUceUtilsProxy(true, true, true, false, true, 10));
+ requestManager.setsUceUtilsProxy(getUceUtilsProxy(
+ true, true, true, false, true, 10, false, 0));
+
RequestManagerCallback requestMgrCallback = requestManager.getRequestManagerCallback();
Handler handler = requestManager.getUceRequestHandler();
@@ -331,7 +349,8 @@
@SmallTest
public void testRetrieveCapForRemote() throws Exception {
UceRequestManager requestManager = getUceRequestManager();
- requestManager.setsUceUtilsProxy(getUceUtilsProxy(true, true, true, false, true, 10));
+ requestManager.setsUceUtilsProxy(getUceUtilsProxy(
+ true, true, true, false, true, 10, false, 0));
Uri contact = Uri.fromParts("sip", "test", null);
List<String> remoteCapList = new ArrayList<>();
@@ -339,17 +358,39 @@
remoteCapList.add(FeatureTags.FEATURE_TAG_FILE_TRANSFER);
requestManager.retrieveCapabilitiesForRemote(contact, remoteCapList, mOptionsReqCallback);
+ verify(mRequestRepository).addRequestCoordinatorAndDispatch(any());
+ }
+
+ @Test
+ @SmallTest
+ public void testSendSubscribeRetryRequest() throws Exception {
+ doReturn(true).when(mFeatureFlags).enableSipSubscribeRetry();
+
+ UceRequestManager requestManager = getUceRequestManager();
+ requestManager.setsUceUtilsProxy(getUceUtilsProxy(
+ true, true, false, false, true, 10, true, 30000));
+
+ RequestManagerCallback requestManagerCallback = requestManager.getRequestManagerCallback();
+
+ SubscribeRequest subscribeRetryRequest = new SubscribeRequest(mSubId,
+ UceRequest.REQUEST_TYPE_CAPABILITY, requestManagerCallback, mSubscribeController,
+ mRequestResponse, mFeatureFlags);
+
+ requestManagerCallback.sendSubscribeRetryRequest(subscribeRetryRequest);
+
verify(mRequestRepository).addRequestCoordinator(any());
+ verify(mRequestRepository, never()).addRequestCoordinatorAndDispatch(any());
}
private UceRequestManager getUceRequestManager() {
UceRequestManager manager = new UceRequestManager(mContext, mSubId, Looper.getMainLooper(),
- mCallback, mRequestRepository);
+ mCallback, mRequestRepository, mFeatureFlags);
return manager;
}
private UceUtilsProxy getUceUtilsProxy(boolean presenceCapEnabled, boolean supportPresence,
- boolean supportOptions, boolean isBlocked, boolean groupSubscribe, int rclMaximum) {
+ boolean supportOptions, boolean isBlocked, boolean groupSubscribe, int rclMaximum,
+ boolean isRetryEnabled, long retryTime) {
return new UceUtilsProxy() {
@Override
public boolean isPresenceCapExchangeEnabled(Context context, int subId) {
@@ -380,6 +421,11 @@
public boolean isNumberBlocked(Context context, String phoneNumber) {
return isBlocked;
}
+
+ @Override
+ public long getSubscribeRetryDuration(Context context, int subId) {
+ return retryTime;
+ }
};
}
}