1 /*
2  * Copyright (C) 2018 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 android.telephony.ims.stub;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.net.Uri;
23 import android.os.RemoteException;
24 import android.telephony.ims.ImsException;
25 import android.telephony.ims.RcsContactUceCapability;
26 import android.telephony.ims.feature.ImsFeature;
27 import android.telephony.ims.feature.RcsFeature;
28 import android.util.Log;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 
33 /**
34  * Base implementation for RCS User Capability Exchange using SIP OPTIONS.
35  *
36  * @hide
37  */
38 public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
39 
40     private static final String LOG_TAG = "RcsSipOptionsImplBase";
41 
42     /**
43      * Indicates a SIP response from the remote user other than 200, 480, 408, 404, or 604.
44      */
45     public static final int RESPONSE_GENERIC_FAILURE = -1;
46 
47     /**
48      * Indicates that the remote user responded with a 200 OK response.
49      */
50     public static final int RESPONSE_SUCCESS = 0;
51 
52     /**
53      * Indicates that the remote user responded with a 480 TEMPORARY UNAVAILABLE response.
54      */
55     public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1;
56 
57     /**
58      * Indicates that the remote user responded with a 408 REQUEST TIMEOUT response.
59      */
60     public static final int RESPONSE_REQUEST_TIMEOUT = 2;
61 
62     /**
63      * Indicates that the remote user responded with a 404 NOT FOUND response.
64      */
65     public static final int RESPONSE_NOT_FOUND = 3;
66 
67     /**
68      * Indicates that the remote user responded with a 604 DOES NOT EXIST ANYWHERE response.
69      */
70     public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4;
71 
72     /**
73      * Indicates that the remote user responded with a 400 BAD REQUEST response.
74      */
75     public static final int RESPONSE_BAD_REQUEST = 5;
76 
77     /** @hide*/
78     @Retention(RetentionPolicy.SOURCE)
79     @IntDef(prefix = "RESPONSE_", value = {
80             RESPONSE_GENERIC_FAILURE,
81             RESPONSE_SUCCESS,
82             RESPONSE_TEMPORARILY_UNAVAILABLE,
83             RESPONSE_REQUEST_TIMEOUT,
84             RESPONSE_NOT_FOUND,
85             RESPONSE_DOES_NOT_EXIST_ANYWHERE,
86             RESPONSE_BAD_REQUEST
87     })
88     public @interface SipResponseCode {}
89 
90     /**
91      * Send the response of a SIP OPTIONS capability exchange to the framework. If {@code code} is
92      * {@link #RESPONSE_SUCCESS}, info must be non-null.
93      * @param code The SIP response code that was sent by the network in response to the request
94      *        sent by {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
95      * @param reason The optional SIP response reason sent by the network. If none was sent, this
96      *        should be an empty string.
97      * @param info the contact's UCE capabilities associated with the capability request.
98      * @param operationToken The token associated with the original capability request, set by
99      *        {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
100      * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently
101      * connected to the framework. This can happen if the {@link RcsFeature} is not
102      * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
103      * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
104      * Telephony stack has crashed.
105      */
onCapabilityRequestResponse(@ipResponseCode int code, @NonNull String reason, @Nullable RcsContactUceCapability info, int operationToken)106     public final void onCapabilityRequestResponse(@SipResponseCode int code, @NonNull String reason,
107             @Nullable RcsContactUceCapability info, int operationToken) throws ImsException {
108         try {
109             getListener().onCapabilityRequestResponseOptions(code, reason, info, operationToken);
110         } catch (RemoteException e) {
111             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
112         }
113     }
114 
115     /**
116      * Inform the framework of a query for this device's UCE capabilities.
117      * <p>
118      * The framework will respond via the
119      * {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)} or
120      * {@link #respondToCapabilityRequestWithError(Uri, int, String, int)} method.
121      * @param contactUri The URI associated with the remote contact that is requesting capabilities.
122      * @param remoteInfo The remote contact's capability information.
123      * @param operationToken An unique operation token that you have generated that will be returned
124      *         by the framework in
125      *         {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)}.
126      * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently
127      * connected to the framework. This can happen if the {@link RcsFeature} is not
128      * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
129      * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
130      * Telephony stack has crashed.
131      */
onRemoteCapabilityRequest(@onNull Uri contactUri, @NonNull RcsContactUceCapability remoteInfo, int operationToken)132     public final void onRemoteCapabilityRequest(@NonNull Uri contactUri,
133             @NonNull RcsContactUceCapability remoteInfo, int operationToken) throws ImsException {
134         try {
135             getListener().onRemoteCapabilityRequest(contactUri, remoteInfo, operationToken);
136         } catch (RemoteException e) {
137             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
138         }
139     }
140 
141     /**
142      * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
143      * in order to receive the capabilities of the remote user in response.
144      * <p>
145      * The implementer must call
146      * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} to send the
147      * response of this query back to the framework.
148      * @param contactUri The URI of the remote user that we wish to get the capabilities of.
149      * @param capabilities The capabilities of this device to send to the remote user.
150      * @param operationToken A token generated by the framework that will be passed through
151      * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} when this
152      *         operation has succeeded.
153      */
sendCapabilityRequest(@onNull Uri contactUri, @NonNull RcsContactUceCapability capabilities, int operationToken)154     public void sendCapabilityRequest(@NonNull Uri contactUri,
155             @NonNull RcsContactUceCapability capabilities, int operationToken) {
156         // Stub - to be implemented by service
157         Log.w(LOG_TAG, "sendCapabilityRequest called with no implementation.");
158         try {
159             getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
160         } catch (RemoteException | ImsException e) {
161             // Do not do anything, this is a stub implementation.
162         }
163     }
164 
165     /**
166      * Respond to a remote capability request from the contact specified with the capabilities of
167      * this device.
168      * <p>
169      * The framework will use the same token and uri as what was passed in to
170      * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}.
171      * @param contactUri The URI of the remote contact.
172      * @param ownCapabilities The capabilities of this device.
173      * @param operationToken The token generated by the framework that this service obtained when
174      *         {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
175      */
respondToCapabilityRequest(@onNull String contactUri, @NonNull RcsContactUceCapability ownCapabilities, int operationToken)176     public void respondToCapabilityRequest(@NonNull String contactUri,
177             @NonNull RcsContactUceCapability ownCapabilities, int operationToken) {
178         // Stub - to be implemented by service
179         Log.w(LOG_TAG, "respondToCapabilityRequest called with no implementation.");
180         try {
181             getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
182         } catch (RemoteException | ImsException e) {
183             // Do not do anything, this is a stub implementation.
184         }
185     }
186 
187     /**
188      * Respond to a remote capability request from the contact specified with the specified error.
189      * <p>
190      * The framework will use the same token and uri as what was passed in to
191      * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}.
192      * @param contactUri A URI containing the remote contact.
193      * @param code The SIP response code to respond with.
194      * @param reason A non-null String containing the reason associated with the SIP code.
195      * @param operationToken The token provided by the framework when
196      *         {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
197      */
respondToCapabilityRequestWithError(@onNull Uri contactUri, @SipResponseCode int code, @NonNull String reason, int operationToken)198     public void respondToCapabilityRequestWithError(@NonNull Uri contactUri,
199             @SipResponseCode int code, @NonNull String reason, int operationToken) {
200         // Stub - to be implemented by service
201         Log.w(LOG_TAG, "respondToCapabiltyRequestWithError called with no implementation.");
202         try {
203             getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
204         } catch (RemoteException | ImsException e) {
205             // Do not do anything, this is a stub implementation.
206         }
207     }
208 }
209