• 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.ims.RcsContactTerminatedReason;
23 import android.telephony.ims.RcsContactUceCapability;
24 import android.telephony.ims.RcsUceAdapter;
25 import android.telephony.ims.aidl.ISubscribeResponseCallback;
26 import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.CommandCode;
27 
28 import com.android.ims.rcs.uce.eab.EabCapabilityResult;
29 import com.android.ims.rcs.uce.presence.pidfparser.PidfParser;
30 import com.android.ims.rcs.uce.presence.pidfparser.PidfParserUtils;
31 import com.android.ims.rcs.uce.presence.pidfparser.RcsContactUceCapabilityWrapper;
32 import com.android.ims.rcs.uce.presence.subscribe.SubscribeController;
33 import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
34 import com.android.internal.annotations.VisibleForTesting;
35 
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.Objects;
40 import java.util.stream.Collectors;
41 
42 /**
43  * The UceRequest to request the capabilities when the presence mechanism is supported by the
44  * network.
45  */
46 public class SubscribeRequest extends CapabilityRequest {
47 
48     // The result callback of the capabilities request from IMS service.
49     private final ISubscribeResponseCallback mResponseCallback =
50             new ISubscribeResponseCallback.Stub() {
51                 @Override
52                 public void onCommandError(int code) {
53                     SubscribeRequest.this.onCommandError(code);
54                 }
55                 @Override
56                 public void onNetworkResponse(int code, String reason) {
57                     SubscribeRequest.this.onNetworkResponse(code, reason);
58                 }
59                 @Override
60                 public void onNetworkRespHeader(int code, String reasonPhrase,
61                         int reasonHeaderCause, String reasonHeaderText) {
62                     SubscribeRequest.this.onNetworkResponse(code, reasonPhrase, reasonHeaderCause,
63                             reasonHeaderText);
64                 }
65                 @Override
66                 public void onNotifyCapabilitiesUpdate(List<String> pidfXmls) {
67                     SubscribeRequest.this.onCapabilitiesUpdate(pidfXmls);
68                 }
69                 @Override
70                 public void onResourceTerminated(List<RcsContactTerminatedReason> terminatedList) {
71                     SubscribeRequest.this.onResourceTerminated(terminatedList);
72                 }
73                 @Override
74                 public void onTerminated(String reason, long retryAfterMillis) {
75                     SubscribeRequest.this.onTerminated(reason, retryAfterMillis);
76                 }
77             };
78 
79     private SubscribeController mSubscribeController;
80 
SubscribeRequest(int subId, @UceRequestType int requestType, RequestManagerCallback taskMgrCallback, SubscribeController subscribeController)81     public SubscribeRequest(int subId, @UceRequestType int requestType,
82             RequestManagerCallback taskMgrCallback, SubscribeController subscribeController) {
83         super(subId, requestType, taskMgrCallback);
84         mSubscribeController = subscribeController;
85         logd("SubscribeRequest created");
86     }
87 
88     @VisibleForTesting
SubscribeRequest(int subId, @UceRequestType int requestType, RequestManagerCallback taskMgrCallback, SubscribeController subscribeController, CapabilityRequestResponse requestResponse)89     public SubscribeRequest(int subId, @UceRequestType int requestType,
90             RequestManagerCallback taskMgrCallback, SubscribeController subscribeController,
91             CapabilityRequestResponse requestResponse) {
92         super(subId, requestType, taskMgrCallback, requestResponse);
93         mSubscribeController = subscribeController;
94     }
95 
96     @Override
onFinish()97     public void onFinish() {
98         mSubscribeController = null;
99         super.onFinish();
100         logd("SubscribeRequest finish");
101     }
102 
103     @Override
requestCapabilities(@onNull List<Uri> requestCapUris)104     public void requestCapabilities(@NonNull List<Uri> requestCapUris) {
105         SubscribeController subscribeController = mSubscribeController;
106         if (subscribeController == null) {
107             logw("requestCapabilities: request is finished");
108             mRequestResponse.setRequestInternalError(RcsUceAdapter.ERROR_GENERIC_FAILURE);
109             mRequestManagerCallback.notifyRequestError(mCoordinatorId, mTaskId);
110             return;
111         }
112 
113         logi("requestCapabilities: size=" + requestCapUris.size());
114         try {
115             // Send the capabilities request.
116             subscribeController.requestCapabilities(requestCapUris, mResponseCallback);
117             // Setup the timeout timer.
118             setupRequestTimeoutTimer();
119         } catch (RemoteException e) {
120             logw("requestCapabilities exception: " + e);
121             mRequestResponse.setRequestInternalError(RcsUceAdapter.ERROR_GENERIC_FAILURE);
122             mRequestManagerCallback.notifyRequestError(mCoordinatorId, mTaskId);
123         }
124     }
125 
126     // Receive the command error callback which is triggered by ISubscribeResponseCallback.
onCommandError(@ommandCode int cmdError)127     private void onCommandError(@CommandCode int cmdError) {
128         logd("onCommandError: error code=" + cmdError);
129         if (mIsFinished) {
130             logw("onCommandError: request is already finished");
131             return;
132         }
133         mRequestResponse.setCommandError(cmdError);
134         mRequestManagerCallback.notifyCommandError(mCoordinatorId, mTaskId);
135     }
136 
137     // Receive the network response callback which is triggered by ISubscribeResponseCallback.
onNetworkResponse(int sipCode, String reason)138     private void onNetworkResponse(int sipCode, String reason) {
139         logd("onNetworkResponse: code=" + sipCode + ", reason=" + reason);
140         if (mIsFinished) {
141             logw("onNetworkResponse: request is already finished");
142             return;
143         }
144         mRequestResponse.setNetworkResponseCode(sipCode, reason);
145         mRequestManagerCallback.notifyNetworkResponse(mCoordinatorId, mTaskId);
146     }
147 
148     // Receive the network response callback which is triggered by ISubscribeResponseCallback.
onNetworkResponse(int sipCode, String reasonPhrase, int reasonHeaderCause, String reasonHeaderText)149     private void onNetworkResponse(int sipCode, String reasonPhrase,
150         int reasonHeaderCause, String reasonHeaderText) {
151         logd("onNetworkResponse: code=" + sipCode + ", reasonPhrase=" + reasonPhrase +
152                 ", reasonHeaderCause=" + reasonHeaderCause +
153                 ", reasonHeaderText=" + reasonHeaderText);
154         if (mIsFinished) {
155             logw("onNetworkResponse: request is already finished");
156             return;
157         }
158         mRequestResponse.setNetworkResponseCode(sipCode, reasonPhrase, reasonHeaderCause,
159                 reasonHeaderText);
160         mRequestManagerCallback.notifyNetworkResponse(mCoordinatorId, mTaskId);
161     }
162 
163     // Receive the resource terminated callback which is triggered by ISubscribeResponseCallback.
onResourceTerminated(List<RcsContactTerminatedReason> terminatedResource)164     private void onResourceTerminated(List<RcsContactTerminatedReason> terminatedResource) {
165         if (mIsFinished) {
166             logw("onResourceTerminated: request is already finished");
167             return;
168         }
169 
170         if (terminatedResource == null) {
171             logw("onResourceTerminated: the parameter is null");
172             terminatedResource = Collections.emptyList();
173         }
174 
175         logd("onResourceTerminated: size=" + terminatedResource.size());
176 
177         // Add the terminated resource into the RequestResponse and notify the RequestManager
178         // to process the RcsContactUceCapabilities update.
179         mRequestResponse.addTerminatedResource(terminatedResource);
180         mRequestManagerCallback.notifyResourceTerminated(mCoordinatorId, mTaskId);
181     }
182 
183     // Receive the capabilities update callback which is triggered by ISubscribeResponseCallback.
onCapabilitiesUpdate(List<String> pidfXml)184     private void onCapabilitiesUpdate(List<String> pidfXml) {
185         if (mIsFinished) {
186             logw("onCapabilitiesUpdate: request is already finished");
187             return;
188         }
189 
190         if (pidfXml == null) {
191             logw("onCapabilitiesUpdate: The parameter is null");
192             pidfXml = Collections.EMPTY_LIST;
193         }
194 
195         // Convert from the pidf xml to the list of RcsContactUceCapabilityWrapper
196         List<RcsContactUceCapabilityWrapper> capabilityList = pidfXml.stream()
197                 .map(pidf -> PidfParser.getRcsContactUceCapabilityWrapper(pidf))
198                 .filter(Objects::nonNull)
199                 .collect(Collectors.toList());
200 
201         // When the given PIDF xml is empty, set the contacts who have not received the
202         // capabilities updated as non-RCS user.
203         List<RcsContactUceCapability> notReceivedCapabilityList = new ArrayList<>();
204         if (capabilityList.isEmpty()) {
205             logd("onCapabilitiesUpdate: The capabilities list is empty, Set to non-RCS user.");
206             List<Uri> notReceiveCapUpdatedContactList =
207                     mRequestResponse.getNotReceiveCapabilityUpdatedContact();
208             notReceivedCapabilityList = notReceiveCapUpdatedContactList.stream()
209                     .map(PidfParserUtils::getNotFoundContactCapabilities)
210                     .filter(Objects::nonNull)
211                     .collect(Collectors.toList());
212         }
213 
214         List<RcsContactUceCapability> updateCapabilityList = new ArrayList<>();
215         List<Uri> malformedListWithEntityURI = new ArrayList<>();
216         for (RcsContactUceCapabilityWrapper capability : capabilityList) {
217             if (!capability.isMalformed()) {
218                 updateCapabilityList.add(capability.toRcsContactUceCapability());
219             } else {
220                 logw("onCapabilitiesUpdate: malformed capability was found and not saved.");
221                 malformedListWithEntityURI.add(capability.getEntityUri());
222             }
223         }
224         logd("onCapabilitiesUpdate: PIDF size=" + pidfXml.size()
225                 + ", not received capability size=" + notReceivedCapabilityList.size()
226                 + ", normal capability size=" + updateCapabilityList.size()
227                 + ", malformed but entity uri is valid capability size="
228                 + malformedListWithEntityURI.size());
229 
230         for (RcsContactUceCapability emptyCapability : notReceivedCapabilityList) {
231             updateCapabilityList.add(emptyCapability);
232         }
233 
234         // All tuples in received xml are malformed but entity uri is valid.
235         // The capability should be get from the DB and report it to callback.
236         List<EabCapabilityResult> cachedCapabilityList =
237                 mRequestManagerCallback.getCapabilitiesFromCache(malformedListWithEntityURI);
238         for (EabCapabilityResult cacheEabCapability : cachedCapabilityList) {
239             RcsContactUceCapability cachedCapability = cacheEabCapability.getContactCapabilities();
240             if (cachedCapability != null) {
241                 updateCapabilityList.add(cachedCapability);
242             }
243         }
244         // Add these updated RcsContactUceCapability into the RequestResponse and notify
245         // the RequestManager to process the RcsContactUceCapabilities updated.
246         logd("onCapabilitiesUpdate: updatedCapability size=" + updateCapabilityList.size());
247         mRequestResponse.addUpdatedCapabilities(updateCapabilityList);
248         mRequestManagerCallback.notifyCapabilitiesUpdated(mCoordinatorId, mTaskId);
249     }
250 
251     // Receive the terminated callback which is triggered by ISubscribeResponseCallback.
onTerminated(String reason, long retryAfterMillis)252     private void onTerminated(String reason, long retryAfterMillis) {
253         logd("onTerminated: reason=" + reason + ", retryAfter=" + retryAfterMillis);
254         if (mIsFinished) {
255             logd("onTerminated: This request is already finished");
256             return;
257         }
258         mRequestResponse.setTerminated(reason, retryAfterMillis);
259         mRequestManagerCallback.notifyTerminated(mCoordinatorId, mTaskId);
260     }
261 
262     @VisibleForTesting
getResponseCallback()263     public ISubscribeResponseCallback getResponseCallback() {
264         return mResponseCallback;
265     }
266 }
267