• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.telephony.ims.RcsUceAdapter;
23 import android.util.Log;
24 
25 import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
26 import com.android.ims.rcs.uce.util.UceUtils;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Optional;
35 import java.util.stream.Collectors;
36 
37 /**
38  * The base class that is responsible for the communication and interaction between the UceRequests.
39  */
40 public abstract class UceRequestCoordinator {
41 
42     private static final String LOG_TAG = UceUtils.getLogPrefix() + "ReqCoordinator";
43 
44     /**
45      * The UceRequest encountered error.
46      */
47     public static final int REQUEST_UPDATE_ERROR = 0;
48 
49     /**
50      * The UceRequest received the onCommandError callback.
51      */
52     public static final int REQUEST_UPDATE_COMMAND_ERROR = 1;
53 
54     /**
55      * The UceRequest received the onNetworkResponse callback.
56      */
57     public static final int REQUEST_UPDATE_NETWORK_RESPONSE = 2;
58 
59     /**
60      * The UceRequest received the onNotifyCapabilitiesUpdate callback.
61      */
62     public static final int REQUEST_UPDATE_CAPABILITY_UPDATE = 3;
63 
64     /**
65      * The UceRequest received the onResourceTerminated callback.
66      */
67     public static final int REQUEST_UPDATE_RESOURCE_TERMINATED = 4;
68 
69     /**
70      * The UceRequest retrieve the valid capabilities from the cache.
71      */
72     public static final int REQUEST_UPDATE_CACHED_CAPABILITY_UPDATE = 5;
73 
74     /**
75      * The UceRequest receive the onTerminated callback.
76      */
77     public static final int REQUEST_UPDATE_TERMINATED = 6;
78 
79     /**
80      * The UceRequest does not need to request capabilities to network because all the capabilities
81      * can be retrieved from the cache.
82      */
83     public static final int REQUEST_UPDATE_NO_NEED_REQUEST_FROM_NETWORK = 7;
84 
85     /**
86      * The remote options request is done.
87      */
88     public static final int REQUEST_UPDATE_REMOTE_REQUEST_DONE = 8;
89 
90     /**
91      * The capabilities request is timeout.
92      */
93     public static final int REQUEST_UPDATE_TIMEOUT = 9;
94 
95     @IntDef(value = {
96             REQUEST_UPDATE_ERROR,
97             REQUEST_UPDATE_COMMAND_ERROR,
98             REQUEST_UPDATE_NETWORK_RESPONSE,
99             REQUEST_UPDATE_TERMINATED,
100             REQUEST_UPDATE_RESOURCE_TERMINATED,
101             REQUEST_UPDATE_CAPABILITY_UPDATE,
102             REQUEST_UPDATE_CACHED_CAPABILITY_UPDATE,
103             REQUEST_UPDATE_NO_NEED_REQUEST_FROM_NETWORK,
104             REQUEST_UPDATE_REMOTE_REQUEST_DONE,
105             REQUEST_UPDATE_TIMEOUT,
106     }, prefix="REQUEST_UPDATE_")
107     @Retention(RetentionPolicy.SOURCE)
108     @interface UceRequestUpdate {}
109 
110     protected static Map<Integer, String> REQUEST_EVENT_DESC = new HashMap<>();
111     static {
REQUEST_EVENT_DESC.put(REQUEST_UPDATE_ERROR, "REQUEST_ERROR")112         REQUEST_EVENT_DESC.put(REQUEST_UPDATE_ERROR, "REQUEST_ERROR");
REQUEST_EVENT_DESC.put(REQUEST_UPDATE_COMMAND_ERROR, "RETRIEVE_COMMAND_ERROR")113         REQUEST_EVENT_DESC.put(REQUEST_UPDATE_COMMAND_ERROR, "RETRIEVE_COMMAND_ERROR");
REQUEST_EVENT_DESC.put(REQUEST_UPDATE_NETWORK_RESPONSE, "REQUEST_NETWORK_RESPONSE")114         REQUEST_EVENT_DESC.put(REQUEST_UPDATE_NETWORK_RESPONSE, "REQUEST_NETWORK_RESPONSE");
REQUEST_EVENT_DESC.put(REQUEST_UPDATE_TERMINATED, "REQUEST_TERMINATED")115         REQUEST_EVENT_DESC.put(REQUEST_UPDATE_TERMINATED, "REQUEST_TERMINATED");
REQUEST_EVENT_DESC.put(REQUEST_UPDATE_RESOURCE_TERMINATED, "REQUEST_RESOURCE_TERMINATED")116         REQUEST_EVENT_DESC.put(REQUEST_UPDATE_RESOURCE_TERMINATED, "REQUEST_RESOURCE_TERMINATED");
REQUEST_EVENT_DESC.put(REQUEST_UPDATE_CAPABILITY_UPDATE, "REQUEST_CAPABILITY_UPDATE")117         REQUEST_EVENT_DESC.put(REQUEST_UPDATE_CAPABILITY_UPDATE, "REQUEST_CAPABILITY_UPDATE");
REQUEST_EVENT_DESC.put(REQUEST_UPDATE_CACHED_CAPABILITY_UPDATE, "REQUEST_CACHE_CAP_UPDATE")118         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")119         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")120         REQUEST_EVENT_DESC.put(REQUEST_UPDATE_REMOTE_REQUEST_DONE, "REMOTE_REQUEST_DONE");
REQUEST_EVENT_DESC.put(REQUEST_UPDATE_TIMEOUT, "REQUEST_TIMEOUT")121         REQUEST_EVENT_DESC.put(REQUEST_UPDATE_TIMEOUT, "REQUEST_TIMEOUT");
122     }
123 
124     /**
125      * The result of the UceRequest. This is the used by the RequestCoordinator to record the
126      * result of each sub-requests.
127      */
128     static class RequestResult {
129         /**
130          * Create a RequestResult that successfully completes the request.
131          * @param taskId the task id of the UceRequest
132          */
createSuccessResult(long taskId)133         public static RequestResult createSuccessResult(long taskId) {
134             return new RequestResult(taskId);
135         }
136 
137         /**
138          * Create a RequestResult for the failed request.
139          * @param taskId the task id of the UceRequest
140          * @param errorCode the error code of the failed request
141          * @param retry When the request can be retried.
142          */
createFailedResult(long taskId, int errorCode, long retry)143         public static RequestResult createFailedResult(long taskId, int errorCode, long retry) {
144             return new RequestResult(taskId, errorCode, retry);
145         }
146 
147         private final Long mTaskId;
148         private final Boolean mIsSuccess;
149         private final Optional<Integer> mErrorCode;
150         private final Optional<Long> mRetryMillis;
151 
152         /**
153          * The private constructor for the successful request.
154          */
RequestResult(long taskId)155         private RequestResult(long taskId) {
156             mTaskId = taskId;
157             mIsSuccess = true;
158             mErrorCode = Optional.empty();
159             mRetryMillis = Optional.empty();
160         }
161 
162         /**
163          * The private constructor for the failed request.
164          */
RequestResult(long taskId, int errorCode, long retryMillis)165         private RequestResult(long taskId, int errorCode, long retryMillis) {
166             mTaskId = taskId;
167             mIsSuccess = false;
168             mErrorCode = Optional.of(errorCode);
169             mRetryMillis = Optional.of(retryMillis);
170         }
171 
getTaskId()172         public long getTaskId() {
173             return mTaskId;
174         }
175 
isRequestSuccess()176         public boolean isRequestSuccess() {
177             return mIsSuccess;
178         }
179 
getErrorCode()180         public Optional<Integer> getErrorCode() {
181             return mErrorCode;
182         }
183 
getRetryMillis()184         public Optional<Long> getRetryMillis() {
185             return mRetryMillis;
186         }
187     }
188 
189     // The default capability error code.
190     protected static final int DEFAULT_ERROR_CODE = RcsUceAdapter.ERROR_GENERIC_FAILURE;
191 
192     protected final int mSubId;
193     protected final long mCoordinatorId;
194     protected volatile boolean mIsFinished;
195 
196     // The collection of activated requests.
197     protected final Map<Long, UceRequest> mActivatedRequests;
198     // The collection of the finished requests.
199     protected final Map<Long, RequestResult> mFinishedRequests;
200     // The lock of the activated and finished collection.
201     protected final Object mCollectionLock = new Object();
202 
203     // The callback to communicate with UceRequestManager
204     protected final RequestManagerCallback mRequestManagerCallback;
205 
UceRequestCoordinator(int subId, Collection<UceRequest> requests, RequestManagerCallback requestMgrCallback)206     public UceRequestCoordinator(int subId, Collection<UceRequest> requests,
207             RequestManagerCallback requestMgrCallback) {
208         mSubId = subId;
209         mCoordinatorId = UceUtils.generateRequestCoordinatorId();
210         mRequestManagerCallback = requestMgrCallback;
211 
212         // Set the coordinatorId to all the given UceRequests
213         requests.forEach(request -> request.setRequestCoordinatorId(mCoordinatorId));
214 
215         // All the given requests are put in the activated request at the beginning.
216         mFinishedRequests = new HashMap<>();
217         mActivatedRequests = requests.stream().collect(
218                 Collectors.toMap(UceRequest::getTaskId, request -> request));
219     }
220 
221     /**
222      * @return Get the request coordinator ID.
223      */
getCoordinatorId()224     public long getCoordinatorId() {
225         return mCoordinatorId;
226     }
227 
228     /**
229      * @return Get the collection of task ID of all the activated requests.
230      */
getActivatedRequestTaskIds()231     public @NonNull List<Long> getActivatedRequestTaskIds() {
232         synchronized (mCollectionLock) {
233             return mActivatedRequests.values().stream()
234                     .map(request -> request.getTaskId())
235                     .collect(Collectors.toList());
236         }
237     }
238 
239     /**
240      * @return Get the UceRequest associated with the given taskId from the activated requests.
241      */
getUceRequest(Long taskId)242     public @Nullable UceRequest getUceRequest(Long taskId) {
243         synchronized (mCollectionLock) {
244             return mActivatedRequests.get(taskId);
245         }
246     }
247 
248     /**
249      * Remove the UceRequest associated with the given taskId from the activated collection and
250      * add the {@link RequestResult} into the finished request collection. This method is called by
251      * the coordinator instance when it receives the request updated event and judges this request
252      * is finished.
253      */
moveRequestToFinishedCollection(Long taskId, RequestResult requestResult)254     protected void moveRequestToFinishedCollection(Long taskId, RequestResult requestResult) {
255         synchronized (mCollectionLock) {
256             mActivatedRequests.remove(taskId);
257             mFinishedRequests.put(taskId, requestResult);
258             mRequestManagerCallback.notifyUceRequestFinished(getCoordinatorId(), taskId);
259         }
260     }
261 
262     /**
263      * Notify this coordinator instance is finished. This method sets the finish flag and clear all
264      * the UceRequest collections and it can be used anymore after the method is called.
265      */
onFinish()266     public void onFinish() {
267         mIsFinished = true;
268         synchronized (mCollectionLock) {
269             mActivatedRequests.forEach((taskId, request) -> request.onFinish());
270             mActivatedRequests.clear();
271             mFinishedRequests.clear();
272         }
273     }
274 
275     /**
276      * Notify the UceRequest associated with the given taskId in the coordinator is updated.
277      */
onRequestUpdated(long taskId, @UceRequestUpdate int event)278     public abstract void onRequestUpdated(long taskId, @UceRequestUpdate int event);
279 
logd(String log)280     protected void logd(String log) {
281         Log.d(LOG_TAG, getLogPrefix().append(log).toString());
282     }
283 
logw(String log)284     protected void logw(String log) {
285         Log.w(LOG_TAG, getLogPrefix().append(log).toString());
286     }
287 
getLogPrefix()288     private StringBuilder getLogPrefix() {
289         StringBuilder builder = new StringBuilder("[");
290         builder.append(mSubId).append("][coordId=").append(mCoordinatorId).append("] ");
291         return builder;
292     }
293 }
294