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.SOURCE_TYPE_NETWORK; 20 21 import android.annotation.NonNull; 22 import android.net.Uri; 23 import android.os.RemoteException; 24 import android.telephony.ims.RcsContactUceCapability; 25 import android.telephony.ims.RcsUceAdapter; 26 import android.telephony.ims.aidl.IOptionsResponseCallback; 27 import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.CommandCode; 28 29 import com.android.ims.rcs.uce.options.OptionsController; 30 import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; 31 import com.android.ims.rcs.uce.util.NetworkSipCode; 32 import com.android.internal.annotations.VisibleForTesting; 33 34 import java.util.Collections; 35 import java.util.HashSet; 36 import java.util.List; 37 import java.util.Set; 38 39 /** 40 * The UceRequest to request the capabilities when the OPTIONS mechanism is supported by the 41 * network. 42 */ 43 public class OptionsRequest extends CapabilityRequest { 44 45 // The result callback of the capabilities request from the IMS service. 46 private IOptionsResponseCallback mResponseCallback = new IOptionsResponseCallback.Stub() { 47 @Override 48 public void onCommandError(int code) { 49 OptionsRequest.this.onCommandError(code); 50 } 51 52 @Override 53 public void onNetworkResponse(int sipCode, String reason, List<String> remoteCaps) { 54 OptionsRequest.this.onNetworkResponse(sipCode, reason, remoteCaps); 55 } 56 }; 57 58 private Uri mContactUri; 59 private OptionsController mOptionsController; 60 OptionsRequest(int subId, @UceRequestType int requestType, RequestManagerCallback taskMgrCallback, OptionsController optionsController)61 public OptionsRequest(int subId, @UceRequestType int requestType, 62 RequestManagerCallback taskMgrCallback, OptionsController optionsController) { 63 super(subId, requestType, taskMgrCallback); 64 mOptionsController = optionsController; 65 logd("OptionsRequest created"); 66 } 67 68 @VisibleForTesting OptionsRequest(int subId, @UceRequestType int requestType, RequestManagerCallback taskMgrCallback, OptionsController optionsController, CapabilityRequestResponse requestResponse)69 public OptionsRequest(int subId, @UceRequestType int requestType, 70 RequestManagerCallback taskMgrCallback, OptionsController optionsController, 71 CapabilityRequestResponse requestResponse) { 72 super(subId, requestType, taskMgrCallback, requestResponse); 73 mOptionsController = optionsController; 74 } 75 76 @Override onFinish()77 public void onFinish() { 78 mOptionsController = null; 79 super.onFinish(); 80 logd("OptionsRequest finish"); 81 } 82 83 @Override requestCapabilities(@onNull List<Uri> requestCapUris)84 public void requestCapabilities(@NonNull List<Uri> requestCapUris) { 85 OptionsController optionsController = mOptionsController; 86 if (optionsController == null) { 87 logw("requestCapabilities: request is finished"); 88 mRequestResponse.setRequestInternalError(RcsUceAdapter.ERROR_GENERIC_FAILURE); 89 mRequestManagerCallback.notifyRequestError(mCoordinatorId, mTaskId); 90 return; 91 } 92 93 // Get the device's capabilities to send to the remote client. 94 RcsContactUceCapability deviceCap = mRequestManagerCallback.getDeviceCapabilities( 95 RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS); 96 if (deviceCap == null) { 97 logw("requestCapabilities: Cannot get device capabilities"); 98 mRequestResponse.setRequestInternalError(RcsUceAdapter.ERROR_GENERIC_FAILURE); 99 mRequestManagerCallback.notifyRequestError(mCoordinatorId, mTaskId); 100 return; 101 } 102 103 mContactUri = requestCapUris.get(0); 104 Set<String> featureTags = deviceCap.getFeatureTags(); 105 106 logi("requestCapabilities: featureTag size=" + featureTags.size()); 107 try { 108 // Send the capabilities request. 109 optionsController.sendCapabilitiesRequest(mContactUri, featureTags, mResponseCallback); 110 // Setup the timeout timer. 111 setupRequestTimeoutTimer(); 112 } catch (RemoteException e) { 113 logw("requestCapabilities exception: " + e); 114 mRequestResponse.setRequestInternalError(RcsUceAdapter.ERROR_GENERIC_FAILURE); 115 mRequestManagerCallback.notifyRequestError(mCoordinatorId, mTaskId); 116 } 117 } 118 119 // Receive the command error callback which is triggered by IOptionsResponseCallback. onCommandError(@ommandCode int cmdError)120 private void onCommandError(@CommandCode int cmdError) { 121 logd("onCommandError: error code=" + cmdError); 122 if (mIsFinished) { 123 logw("onCommandError: The request is already finished"); 124 return; 125 } 126 mRequestResponse.setCommandError(cmdError); 127 mRequestManagerCallback.notifyCommandError(mCoordinatorId, mTaskId); 128 } 129 130 // Receive the network response callback which is triggered by IOptionsResponseCallback. onNetworkResponse(int sipCode, String reason, List<String> remoteCaps)131 private void onNetworkResponse(int sipCode, String reason, List<String> remoteCaps) { 132 logd("onNetworkResponse: sipCode=" + sipCode + ", reason=" + reason 133 + ", remoteCap size=" + ((remoteCaps == null) ? "null" : remoteCaps.size())); 134 if (mIsFinished) { 135 logw("onNetworkResponse: The request is already finished"); 136 return; 137 } 138 139 if (remoteCaps == null) { 140 remoteCaps = Collections.EMPTY_LIST; 141 } 142 143 // Set the all the results to the request response. 144 mRequestResponse.setNetworkResponseCode(sipCode, reason); 145 mRequestResponse.setRemoteCapabilities(new HashSet<>(remoteCaps)); 146 RcsContactUceCapability contactCapabilities = getContactCapabilities(mContactUri, sipCode, 147 new HashSet<>(remoteCaps)); 148 mRequestResponse.addUpdatedCapabilities(Collections.singletonList(contactCapabilities)); 149 150 // Notify that the network response is received. 151 mRequestManagerCallback.notifyNetworkResponse(mCoordinatorId, mTaskId); 152 } 153 154 /** 155 * Convert the remote capabilities from string list type to RcsContactUceCapability. 156 */ getContactCapabilities(Uri contact, int sipCode, Set<String> featureTags)157 private RcsContactUceCapability getContactCapabilities(Uri contact, int sipCode, 158 Set<String> featureTags) { 159 int requestResult = RcsContactUceCapability.REQUEST_RESULT_FOUND; 160 if (!mRequestResponse.isNetworkResponseOK()) { 161 switch (sipCode) { 162 case NetworkSipCode.SIP_CODE_REQUEST_TIMEOUT: 163 // Intentional fallthrough 164 case NetworkSipCode.SIP_CODE_TEMPORARILY_UNAVAILABLE: 165 requestResult = RcsContactUceCapability.REQUEST_RESULT_NOT_ONLINE; 166 break; 167 case NetworkSipCode.SIP_CODE_NOT_FOUND: 168 // Intentional fallthrough 169 case NetworkSipCode.SIP_CODE_DOES_NOT_EXIST_ANYWHERE: 170 requestResult = RcsContactUceCapability.REQUEST_RESULT_NOT_FOUND; 171 break; 172 default: 173 requestResult = RcsContactUceCapability.REQUEST_RESULT_NOT_FOUND; 174 break; 175 } 176 } 177 178 RcsContactUceCapability.OptionsBuilder optionsBuilder 179 = new RcsContactUceCapability.OptionsBuilder(contact, SOURCE_TYPE_NETWORK); 180 optionsBuilder.setRequestResult(requestResult); 181 optionsBuilder.addFeatureTags(featureTags); 182 return optionsBuilder.build(); 183 } 184 185 @VisibleForTesting getResponseCallback()186 public IOptionsResponseCallback getResponseCallback() { 187 return mResponseCallback; 188 } 189 } 190