• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ims.rcs.uce.request;
18 
19 import android.annotation.NonNull;
20 import android.net.Uri;
21 import android.os.RemoteException;
22 import android.telephony.CarrierConfigManager;
23 import android.telephony.ims.RcsContactTerminatedReason;
24 import android.telephony.ims.RcsContactUceCapability;
25 import android.telephony.ims.RcsUceAdapter;
26 import android.telephony.ims.SipDetails;
27 import android.telephony.ims.aidl.ISubscribeResponseCallback;
28 import android.telephony.ims.stub.RcsCapabilityExchangeImplBase;
29 import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.CommandCode;
30 
31 import com.android.ims.rcs.uce.eab.EabCapabilityResult;
32 import com.android.ims.rcs.uce.presence.pidfparser.PidfParser;
33 import com.android.ims.rcs.uce.presence.pidfparser.PidfParserUtils;
34 import com.android.ims.rcs.uce.presence.pidfparser.RcsContactUceCapabilityWrapper;
35 import com.android.ims.rcs.uce.presence.subscribe.SubscribeController;
36 import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
37 import com.android.internal.annotations.VisibleForTesting;
38 import com.android.internal.telephony.flags.FeatureFlags;
39 
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.List;
43 import java.util.Objects;
44 import java.util.stream.Collectors;
45 
46 /**
47  * The UceRequest to request the capabilities when the presence mechanism is supported by the
48  * network.
49  */
50 public class SubscribeRequest extends CapabilityRequest {
51     public static final int MAX_RETRY_COUNT = 1;
52 
53     // The result callback of the capabilities request from IMS service.
54     private final ISubscribeResponseCallback mResponseCallback =
55             new ISubscribeResponseCallback.Stub() {
56                 @Override
57                 public void onCommandError(int code) {
58                     SubscribeRequest.this.onCommandError(code);
59                 }
60                 @Override
61                 public void onNetworkResponse(@NonNull SipDetails details) {
62                     SubscribeRequest.this.onNetworkResponse(details);
63                 }
64                 @Override
65                 public void onNotifyCapabilitiesUpdate(List<String> pidfXmls) {
66                     SubscribeRequest.this.onCapabilitiesUpdate(pidfXmls);
67                 }
68                 @Override
69                 public void onResourceTerminated(List<RcsContactTerminatedReason> terminatedList) {
70                     SubscribeRequest.this.onResourceTerminated(terminatedList);
71                 }
72                 @Override
73                 public void onTerminated(String reason, long retryAfterMillis) {
74                     SubscribeRequest.this.onTerminated(reason, retryAfterMillis);
75                 }
76             };
77 
78     private SubscribeController mSubscribeController;
79     private final FeatureFlags mFeatureFlags;
80 
SubscribeRequest(int subId, @UceRequestType int requestType, RequestManagerCallback taskMgrCallback, SubscribeController subscribeController, FeatureFlags featureFlags)81     public SubscribeRequest(int subId, @UceRequestType int requestType,
82             RequestManagerCallback taskMgrCallback, SubscribeController subscribeController,
83             FeatureFlags featureFlags) {
84         super(subId, requestType, taskMgrCallback);
85         mSubscribeController = subscribeController;
86         mFeatureFlags = featureFlags;
87         logd("SubscribeRequest created");
88     }
89 
90     @VisibleForTesting
SubscribeRequest(int subId, @UceRequestType int requestType, RequestManagerCallback taskMgrCallback, SubscribeController subscribeController, CapabilityRequestResponse requestResponse, FeatureFlags featureFlags)91     public SubscribeRequest(int subId, @UceRequestType int requestType,
92             RequestManagerCallback taskMgrCallback, SubscribeController subscribeController,
93             CapabilityRequestResponse requestResponse, FeatureFlags featureFlags) {
94         super(subId, requestType, taskMgrCallback, requestResponse);
95         mSubscribeController = subscribeController;
96         mFeatureFlags = featureFlags;
97     }
98 
99     @Override
onFinish()100     public void onFinish() {
101         mSubscribeController = null;
102         super.onFinish();
103         logd("SubscribeRequest finish");
104     }
105 
106     @Override
requestCapabilities(@onNull List<Uri> requestCapUris)107     public void requestCapabilities(@NonNull List<Uri> requestCapUris) {
108         SubscribeController subscribeController = mSubscribeController;
109         if (subscribeController == null) {
110             logw("requestCapabilities: request is finished");
111             mRequestResponse.setRequestInternalError(RcsUceAdapter.ERROR_GENERIC_FAILURE);
112             mRequestManagerCallback.notifyRequestError(mCoordinatorId, mTaskId);
113             return;
114         }
115 
116         logi("requestCapabilities: size=" + requestCapUris.size());
117         try {
118             // Send the capabilities request.
119             subscribeController.requestCapabilities(requestCapUris, mResponseCallback);
120             // Setup the timeout timer.
121             setupRequestTimeoutTimer();
122         } catch (RemoteException e) {
123             logw("requestCapabilities exception: " + e);
124             mRequestResponse.setRequestInternalError(RcsUceAdapter.ERROR_GENERIC_FAILURE);
125             mRequestManagerCallback.notifyRequestError(mCoordinatorId, mTaskId);
126         }
127     }
128 
129     // Receive the command error callback which is triggered by ISubscribeResponseCallback.
onCommandError(@ommandCode int cmdError)130     private void onCommandError(@CommandCode int cmdError) {
131         logd("onCommandError: error code=" + cmdError);
132         if (mIsFinished) {
133             logw("onCommandError: request is already finished");
134             return;
135         }
136 
137         if (mFeatureFlags.enableSipSubscribeRetry()
138                 && cmdError == RcsCapabilityExchangeImplBase.COMMAND_CODE_REQUEST_TIMEOUT
139                 && isRetryEnabled()) {
140             int retryCount = getRetryCount();
141             if (retryCount < MAX_RETRY_COUNT) {
142                 CapabilityRequest request = new SubscribeRequest(mSubId, mRequestType,
143                         mRequestManagerCallback, mSubscribeController, mFeatureFlags);
144                 request.setContactUri(getContactUri());
145                 request.setRetryCount(retryCount + 1);
146                 // Do not use the cached capability to retry
147                 request.setSkipGettingFromCache(true);
148 
149                 mRequestManagerCallback.sendSubscribeRetryRequest(request);
150                 logd("onCommandError: Retry subscribe request");
151             } else {
152                 logd("onCommandError: Reached max retry");
153             }
154         }
155 
156         mRequestResponse.setCommandError(cmdError);
157         mRequestManagerCallback.notifyCommandError(mCoordinatorId, mTaskId);
158     }
159 
160     // Receive the network response callback which is triggered by ISubscribeResponseCallback.
onNetworkResponse(@onNull SipDetails details)161     private void onNetworkResponse(@NonNull SipDetails details) {
162         logd("onNetworkResponse: sip details=" + details.toString());
163 
164         if (mIsFinished) {
165             logw("onNetworkResponse: request is already finished");
166             return;
167         }
168         mRequestResponse.setSipDetails(details);
169         mRequestManagerCallback.notifyNetworkResponse(mCoordinatorId, mTaskId);
170     }
171 
172     // Receive the resource terminated callback which is triggered by ISubscribeResponseCallback.
onResourceTerminated(List<RcsContactTerminatedReason> terminatedResource)173     private void onResourceTerminated(List<RcsContactTerminatedReason> terminatedResource) {
174         if (mIsFinished) {
175             logw("onResourceTerminated: request is already finished");
176             return;
177         }
178 
179         if (terminatedResource == null) {
180             logw("onResourceTerminated: the parameter is null");
181             terminatedResource = Collections.emptyList();
182         }
183 
184         logd("onResourceTerminated: size=" + terminatedResource.size());
185 
186         // Add the terminated resource into the RequestResponse and notify the RequestManager
187         // to process the RcsContactUceCapabilities update.
188         mRequestResponse.addTerminatedResource(terminatedResource);
189         mRequestManagerCallback.notifyResourceTerminated(mCoordinatorId, mTaskId);
190     }
191 
192     // Receive the capabilities update callback which is triggered by ISubscribeResponseCallback.
onCapabilitiesUpdate(List<String> pidfXml)193     private void onCapabilitiesUpdate(List<String> pidfXml) {
194         if (mIsFinished) {
195             logw("onCapabilitiesUpdate: request is already finished");
196             return;
197         }
198 
199         if (pidfXml == null) {
200             logw("onCapabilitiesUpdate: The parameter is null");
201             pidfXml = Collections.EMPTY_LIST;
202         }
203 
204         // Convert from the pidf xml to the list of RcsContactUceCapabilityWrapper
205         List<RcsContactUceCapabilityWrapper> capabilityList = pidfXml.stream()
206                 .map(pidf -> PidfParser.getRcsContactUceCapabilityWrapper(pidf))
207                 .filter(Objects::nonNull)
208                 .collect(Collectors.toList());
209 
210         // When the given PIDF xml is empty, set the contacts who have not received the
211         // capabilities updated as non-RCS user.
212         List<RcsContactUceCapability> notReceivedCapabilityList = new ArrayList<>();
213         if (capabilityList.isEmpty()) {
214             logd("onCapabilitiesUpdate: The capabilities list is empty, Set to non-RCS user.");
215             List<Uri> notReceiveCapUpdatedContactList =
216                     mRequestResponse.getNotReceiveCapabilityUpdatedContact();
217             notReceivedCapabilityList = notReceiveCapUpdatedContactList.stream()
218                     .map(PidfParserUtils::getNotFoundContactCapabilities)
219                     .filter(Objects::nonNull)
220                     .collect(Collectors.toList());
221         }
222 
223         List<RcsContactUceCapability> updateCapabilityList = new ArrayList<>();
224         List<Uri> malformedListWithEntityURI = new ArrayList<>();
225         for (RcsContactUceCapabilityWrapper capability : capabilityList) {
226             if (!capability.isMalformed()) {
227                 updateCapabilityList.add(capability.toRcsContactUceCapability());
228             } else {
229                 logw("onCapabilitiesUpdate: malformed capability was found and not saved.");
230                 malformedListWithEntityURI.add(capability.getEntityUri());
231             }
232         }
233         logd("onCapabilitiesUpdate: PIDF size=" + pidfXml.size()
234                 + ", not received capability size=" + notReceivedCapabilityList.size()
235                 + ", normal capability size=" + updateCapabilityList.size()
236                 + ", malformed but entity uri is valid capability size="
237                 + malformedListWithEntityURI.size());
238 
239         for (RcsContactUceCapability emptyCapability : notReceivedCapabilityList) {
240             updateCapabilityList.add(emptyCapability);
241         }
242 
243         // All tuples in received xml are malformed but entity uri is valid.
244         // The capability should be get from the DB and report it to callback.
245         List<EabCapabilityResult> cachedCapabilityList =
246                 mRequestManagerCallback.getCapabilitiesFromCache(malformedListWithEntityURI);
247         for (EabCapabilityResult cacheEabCapability : cachedCapabilityList) {
248             RcsContactUceCapability cachedCapability = cacheEabCapability.getContactCapabilities();
249             if (cachedCapability != null) {
250                 updateCapabilityList.add(cachedCapability);
251             }
252         }
253         // Add these updated RcsContactUceCapability into the RequestResponse and notify
254         // the RequestManager to process the RcsContactUceCapabilities updated.
255         logd("onCapabilitiesUpdate: updatedCapability size=" + updateCapabilityList.size());
256         mRequestResponse.addUpdatedCapabilities(updateCapabilityList);
257         mRequestManagerCallback.notifyCapabilitiesUpdated(mCoordinatorId, mTaskId);
258     }
259 
260     // Receive the terminated callback which is triggered by ISubscribeResponseCallback.
onTerminated(String reason, long retryAfterMillis)261     private void onTerminated(String reason, long retryAfterMillis) {
262         logd("onTerminated: reason=" + reason + ", retryAfter=" + retryAfterMillis);
263         if (mIsFinished) {
264             logd("onTerminated: This request is already finished");
265             return;
266         }
267         mRequestResponse.setTerminated(reason, retryAfterMillis);
268         mRequestManagerCallback.notifyTerminated(mCoordinatorId, mTaskId);
269     }
270 
271     @VisibleForTesting
getResponseCallback()272     public ISubscribeResponseCallback getResponseCallback() {
273         return mResponseCallback;
274     }
275 }
276