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