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 static android.telephony.ims.RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS;
20 import static android.telephony.ims.RcsContactUceCapability.SOURCE_TYPE_NETWORK;
21 
22 import android.net.Uri;
23 import android.telephony.ims.RcsContactUceCapability;
24 import android.util.Log;
25 
26 import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback;
27 import com.android.ims.rcs.uce.util.FeatureTags;
28 import com.android.ims.rcs.uce.util.NetworkSipCode;
29 import com.android.ims.rcs.uce.util.UceUtils;
30 
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.List;
34 import java.util.Optional;
35 
36 /**
37  * Handle the OPTIONS request from the network.
38  */
39 public class RemoteOptionsRequest implements UceRequest {
40 
41     private static final String LOG_TAG = UceUtils.getLogPrefix() + "RemoteOptRequest";
42 
43     /**
44      * The response of the remote capability request.
45      */
46     public static class RemoteOptResponse {
47         private boolean mIsNumberBlocked;
48         private RcsContactUceCapability mRcsContactCapability;
49         private Optional<Integer> mErrorSipCode;
50         private Optional<String> mErrorReason;
51 
RemoteOptResponse()52         public RemoteOptResponse() {
53             mErrorSipCode = Optional.empty();
54             mErrorReason = Optional.empty();
55         }
56 
setRespondToRequest(RcsContactUceCapability capability, boolean isBlocked)57         void setRespondToRequest(RcsContactUceCapability capability, boolean isBlocked) {
58             mIsNumberBlocked = isBlocked;
59             mRcsContactCapability = capability;
60         }
61 
setRespondToRequestWithError(int code, String reason)62         void setRespondToRequestWithError(int code, String reason) {
63             mErrorSipCode = Optional.of(code);
64             mErrorReason = Optional.of(reason);
65         }
66 
isNumberBlocked()67         public boolean isNumberBlocked() {
68             return mIsNumberBlocked;
69         }
70 
getRcsContactCapability()71         public RcsContactUceCapability getRcsContactCapability() {
72             return mRcsContactCapability;
73         }
74 
getErrorSipCode()75         public Optional<Integer> getErrorSipCode() {
76             return mErrorSipCode;
77         }
78 
getErrorReason()79         public Optional<String> getErrorReason() {
80             return mErrorReason;
81         }
82     }
83 
84     private final int mSubId;
85     private final long mTaskId;
86     private volatile long mCoordinatorId;
87     private volatile boolean mIsFinished;
88     private volatile boolean mIsRemoteNumberBlocked;
89 
90     private List<Uri> mUriList;
91     private final List<String> mRemoteFeatureTags;
92     private final RemoteOptResponse mRemoteOptResponse;
93     private final RequestManagerCallback mRequestManagerCallback;
94 
RemoteOptionsRequest(int subId, RequestManagerCallback requestMgrCallback)95     public RemoteOptionsRequest(int subId, RequestManagerCallback requestMgrCallback) {
96         mSubId = subId;
97         mTaskId = UceUtils.generateTaskId();
98         mRemoteFeatureTags = new ArrayList<>();
99         mRemoteOptResponse = new RemoteOptResponse();
100         mRequestManagerCallback = requestMgrCallback;
101         logd("created");
102     }
103 
104     @Override
setRequestCoordinatorId(long coordinatorId)105     public void setRequestCoordinatorId(long coordinatorId) {
106         mCoordinatorId = coordinatorId;
107     }
108 
109     @Override
getRequestCoordinatorId()110     public long getRequestCoordinatorId() {
111         return mCoordinatorId;
112     }
113 
114     @Override
getTaskId()115     public long getTaskId() {
116         return mTaskId;
117     }
118 
119     @Override
onFinish()120     public void onFinish() {
121         mIsFinished = true;
122     }
123 
124     @Override
setContactUri(List<Uri> uris)125     public void setContactUri(List<Uri> uris) {
126         mUriList = uris;
127     }
128 
setRemoteFeatureTags(List<String> remoteFeatureTags)129     public void setRemoteFeatureTags(List<String> remoteFeatureTags) {
130         remoteFeatureTags.forEach(mRemoteFeatureTags::add);
131     }
132 
setIsRemoteNumberBlocked(boolean isBlocked)133     public void setIsRemoteNumberBlocked(boolean isBlocked) {
134         mIsRemoteNumberBlocked = isBlocked;
135     }
136 
137     /**
138      * @return The response of this request.
139      */
getRemoteOptResponse()140     public RemoteOptResponse getRemoteOptResponse() {
141         return mRemoteOptResponse;
142     }
143 
144     @Override
executeRequest()145     public void executeRequest() {
146         logd("executeRequest");
147         try {
148             executeRequestInternal();
149         } catch (Exception e) {
150             logw("executeRequest: exception " + e);
151             setResponseWithError(NetworkSipCode.SIP_CODE_SERVER_INTERNAL_ERROR,
152                     NetworkSipCode.SIP_INTERNAL_SERVER_ERROR);
153         } finally {
154             mRequestManagerCallback.notifyRemoteRequestDone(mCoordinatorId, mTaskId);
155         }
156     }
157 
executeRequestInternal()158     private void executeRequestInternal() {
159         if (mUriList == null || mUriList.isEmpty()) {
160             logw("executeRequest: uri is empty");
161             setResponseWithError(NetworkSipCode.SIP_CODE_BAD_REQUEST,
162                     NetworkSipCode.SIP_BAD_REQUEST);
163             return;
164         }
165 
166         if (mIsFinished) {
167             logw("executeRequest: This request is finished");
168             setResponseWithError(NetworkSipCode.SIP_CODE_SERVICE_UNAVAILABLE,
169                     NetworkSipCode.SIP_SERVICE_UNAVAILABLE);
170             return;
171         }
172 
173         // Store the remote capabilities
174         Uri contactUri = mUriList.get(0);
175         RcsContactUceCapability remoteCaps = FeatureTags.getContactCapability(contactUri,
176                 SOURCE_TYPE_NETWORK, mRemoteFeatureTags);
177         mRequestManagerCallback.saveCapabilities(Collections.singletonList(remoteCaps));
178 
179         // Get the device's capabilities and trigger the request callback
180         RcsContactUceCapability deviceCaps = mRequestManagerCallback.getDeviceCapabilities(
181                 CAPABILITY_MECHANISM_OPTIONS);
182         if (deviceCaps == null) {
183             logw("executeRequest: The device's capabilities is empty");
184             setResponseWithError(NetworkSipCode.SIP_CODE_SERVER_INTERNAL_ERROR,
185                     NetworkSipCode.SIP_INTERNAL_SERVER_ERROR);
186         } else {
187             logd("executeRequest: Respond to capability request, blocked="
188                     + mIsRemoteNumberBlocked);
189             setResponse(deviceCaps, mIsRemoteNumberBlocked);
190         }
191     }
192 
setResponse(RcsContactUceCapability deviceCaps, boolean isRemoteNumberBlocked)193     private void setResponse(RcsContactUceCapability deviceCaps,
194             boolean isRemoteNumberBlocked) {
195         mRemoteOptResponse.setRespondToRequest(deviceCaps, isRemoteNumberBlocked);
196     }
197 
setResponseWithError(int errorCode, String reason)198     private void setResponseWithError(int errorCode, String reason) {
199         mRemoteOptResponse.setRespondToRequestWithError(errorCode, reason);
200     }
201 
logd(String log)202     private void logd(String log) {
203         Log.d(LOG_TAG, getLogPrefix().append(log).toString());
204     }
205 
logw(String log)206     private void logw(String log) {
207         Log.d(LOG_TAG, getLogPrefix().append(log).toString());
208     }
209 
getLogPrefix()210     private StringBuilder getLogPrefix() {
211         StringBuilder builder = new StringBuilder("[");
212         builder.append(mSubId).append("][taskId=").append(mTaskId).append("] ");
213         return builder;
214     }
215 }
216