aboutsummaryrefslogtreecommitdiff
path: root/src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java')
-rw-r--r--src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java b/src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java
new file mode 100644
index 00000000..eea4fbe3
--- /dev/null
+++ b/src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java
@@ -0,0 +1,293 @@
+/*
+ * 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.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.telephony.ims.RcsUceAdapter;
+import android.util.Log;
+
+import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
+import com.android.ims.rcs.uce.util.UceUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * The base class that is responsible for the communication and interaction between the UceRequests.
+ */
+public abstract class UceRequestCoordinator {
+
+ private static final String LOG_TAG = UceUtils.getLogPrefix() + "ReqCoordinator";
+
+ /**
+ * The UceRequest encountered error.
+ */
+ public static final int REQUEST_UPDATE_ERROR = 0;
+
+ /**
+ * The UceRequest received the onCommandError callback.
+ */
+ public static final int REQUEST_UPDATE_COMMAND_ERROR = 1;
+
+ /**
+ * The UceRequest received the onNetworkResponse callback.
+ */
+ public static final int REQUEST_UPDATE_NETWORK_RESPONSE = 2;
+
+ /**
+ * The UceRequest received the onNotifyCapabilitiesUpdate callback.
+ */
+ public static final int REQUEST_UPDATE_CAPABILITY_UPDATE = 3;
+
+ /**
+ * The UceRequest received the onResourceTerminated callback.
+ */
+ public static final int REQUEST_UPDATE_RESOURCE_TERMINATED = 4;
+
+ /**
+ * The UceRequest retrieve the valid capabilities from the cache.
+ */
+ public static final int REQUEST_UPDATE_CACHED_CAPABILITY_UPDATE = 5;
+
+ /**
+ * The UceRequest receive the onTerminated callback.
+ */
+ public static final int REQUEST_UPDATE_TERMINATED = 6;
+
+ /**
+ * The UceRequest does not need to request capabilities to network because all the capabilities
+ * can be retrieved from the cache.
+ */
+ public static final int REQUEST_UPDATE_NO_NEED_REQUEST_FROM_NETWORK = 7;
+
+ /**
+ * The remote options request is done.
+ */
+ public static final int REQUEST_UPDATE_REMOTE_REQUEST_DONE = 8;
+
+ /**
+ * The capabilities request is timeout.
+ */
+ public static final int REQUEST_UPDATE_TIMEOUT = 9;
+
+ @IntDef(value = {
+ REQUEST_UPDATE_ERROR,
+ REQUEST_UPDATE_COMMAND_ERROR,
+ REQUEST_UPDATE_NETWORK_RESPONSE,
+ REQUEST_UPDATE_TERMINATED,
+ REQUEST_UPDATE_RESOURCE_TERMINATED,
+ REQUEST_UPDATE_CAPABILITY_UPDATE,
+ REQUEST_UPDATE_CACHED_CAPABILITY_UPDATE,
+ REQUEST_UPDATE_NO_NEED_REQUEST_FROM_NETWORK,
+ REQUEST_UPDATE_REMOTE_REQUEST_DONE,
+ REQUEST_UPDATE_TIMEOUT,
+ }, prefix="REQUEST_UPDATE_")
+ @Retention(RetentionPolicy.SOURCE)
+ @interface UceRequestUpdate {}
+
+ protected static Map<Integer, String> REQUEST_EVENT_DESC = new HashMap<>();
+ static {
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_ERROR, "REQUEST_ERROR");
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_COMMAND_ERROR, "RETRIEVE_COMMAND_ERROR");
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_NETWORK_RESPONSE, "REQUEST_NETWORK_RESPONSE");
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_TERMINATED, "REQUEST_TERMINATED");
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_RESOURCE_TERMINATED, "REQUEST_RESOURCE_TERMINATED");
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_CAPABILITY_UPDATE, "REQUEST_CAPABILITY_UPDATE");
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_CACHED_CAPABILITY_UPDATE, "REQUEST_CACHE_CAP_UPDATE");
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_NO_NEED_REQUEST_FROM_NETWORK, "NO_NEED_REQUEST");
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_REMOTE_REQUEST_DONE, "REMOTE_REQUEST_DONE");
+ REQUEST_EVENT_DESC.put(REQUEST_UPDATE_TIMEOUT, "REQUEST_TIMEOUT");
+ }
+
+ /**
+ * The result of the UceRequest. This is the used by the RequestCoordinator to record the
+ * result of each sub-requests.
+ */
+ static class RequestResult {
+ /**
+ * Create a RequestResult that successfully completes the request.
+ * @param taskId the task id of the UceRequest
+ */
+ public static RequestResult createSuccessResult(long taskId) {
+ return new RequestResult(taskId);
+ }
+
+ /**
+ * Create a RequestResult for the failed request.
+ * @param taskId the task id of the UceRequest
+ * @param errorCode the error code of the failed request
+ * @param retry When the request can be retried.
+ */
+ public static RequestResult createFailedResult(long taskId, int errorCode, long retry) {
+ return new RequestResult(taskId, errorCode, retry);
+ }
+
+ private final Long mTaskId;
+ private final Boolean mIsSuccess;
+ private final Optional<Integer> mErrorCode;
+ private final Optional<Long> mRetryMillis;
+
+ /**
+ * The private constructor for the successful request.
+ */
+ private RequestResult(long taskId) {
+ mTaskId = taskId;
+ mIsSuccess = true;
+ mErrorCode = Optional.empty();
+ mRetryMillis = Optional.empty();
+ }
+
+ /**
+ * The private constructor for the failed request.
+ */
+ private RequestResult(long taskId, int errorCode, long retryMillis) {
+ mTaskId = taskId;
+ mIsSuccess = false;
+ mErrorCode = Optional.of(errorCode);
+ mRetryMillis = Optional.of(retryMillis);
+ }
+
+ public long getTaskId() {
+ return mTaskId;
+ }
+
+ public boolean isRequestSuccess() {
+ return mIsSuccess;
+ }
+
+ public Optional<Integer> getErrorCode() {
+ return mErrorCode;
+ }
+
+ public Optional<Long> getRetryMillis() {
+ return mRetryMillis;
+ }
+ }
+
+ // The default capability error code.
+ protected static final int DEFAULT_ERROR_CODE = RcsUceAdapter.ERROR_GENERIC_FAILURE;
+
+ protected final int mSubId;
+ protected final long mCoordinatorId;
+ protected volatile boolean mIsFinished;
+
+ // The collection of activated requests.
+ protected final Map<Long, UceRequest> mActivatedRequests;
+ // The collection of the finished requests.
+ protected final Map<Long, RequestResult> mFinishedRequests;
+ // The lock of the activated and finished collection.
+ protected final Object mCollectionLock = new Object();
+
+ // The callback to communicate with UceRequestManager
+ protected final RequestManagerCallback mRequestManagerCallback;
+
+ public UceRequestCoordinator(int subId, Collection<UceRequest> requests,
+ RequestManagerCallback requestMgrCallback) {
+ mSubId = subId;
+ mCoordinatorId = UceUtils.generateRequestCoordinatorId();
+ mRequestManagerCallback = requestMgrCallback;
+
+ // Set the coordinatorId to all the given UceRequests
+ requests.forEach(request -> request.setRequestCoordinatorId(mCoordinatorId));
+
+ // All the given requests are put in the activated request at the beginning.
+ mFinishedRequests = new HashMap<>();
+ mActivatedRequests = requests.stream().collect(
+ Collectors.toMap(UceRequest::getTaskId, request -> request));
+ }
+
+ /**
+ * @return Get the request coordinator ID.
+ */
+ public long getCoordinatorId() {
+ return mCoordinatorId;
+ }
+
+ /**
+ * @return Get the collection of task ID of all the activated requests.
+ */
+ public @NonNull List<Long> getActivatedRequestTaskIds() {
+ synchronized (mCollectionLock) {
+ return mActivatedRequests.values().stream()
+ .map(request -> request.getTaskId())
+ .collect(Collectors.toList());
+ }
+ }
+
+ /**
+ * @return Get the UceRequest associated with the given taskId from the activated requests.
+ */
+ public @Nullable UceRequest getUceRequest(Long taskId) {
+ synchronized (mCollectionLock) {
+ return mActivatedRequests.get(taskId);
+ }
+ }
+
+ /**
+ * Remove the UceRequest associated with the given taskId from the activated collection and
+ * add the {@link RequestResult} into the finished request collection. This method is called by
+ * the coordinator instance when it receives the request updated event and judges this request
+ * is finished.
+ */
+ protected void moveRequestToFinishedCollection(Long taskId, RequestResult requestResult) {
+ synchronized (mCollectionLock) {
+ mActivatedRequests.remove(taskId);
+ mFinishedRequests.put(taskId, requestResult);
+ mRequestManagerCallback.notifyUceRequestFinished(getCoordinatorId(), taskId);
+ }
+ }
+
+ /**
+ * Notify this coordinator instance is finished. This method sets the finish flag and clear all
+ * the UceRequest collections and it can be used anymore after the method is called.
+ */
+ public void onFinish() {
+ mIsFinished = true;
+ synchronized (mCollectionLock) {
+ mActivatedRequests.forEach((taskId, request) -> request.onFinish());
+ mActivatedRequests.clear();
+ mFinishedRequests.clear();
+ }
+ }
+
+ /**
+ * Notify the UceRequest associated with the given taskId in the coordinator is updated.
+ */
+ public abstract void onRequestUpdated(long taskId, @UceRequestUpdate int event);
+
+ protected void logd(String log) {
+ Log.d(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ protected void logw(String log) {
+ Log.w(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private StringBuilder getLogPrefix() {
+ StringBuilder builder = new StringBuilder("[");
+ builder.append(mSubId).append("][coordId=").append(mCoordinatorId).append("] ");
+ return builder;
+ }
+}