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