1 /*
2  * Copyright (c) 2015, Motorola Mobility LLC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     - Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     - Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     - Neither the name of Motorola Mobility nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26  * DAMAGE.
27  */
28 
29 package com.android.ims;
30 
31 import java.util.List;
32 import android.os.RemoteException;
33 import android.util.Log;
34 
35 import com.android.ims.internal.IRcsPresence;
36 
37 /**
38  *
39  * @hide
40  */
41 public class RcsPresence {
42     static final String TAG = "RcsPresence";
43     private boolean DBG = true;
44     private IRcsPresence mIRcsPresence = null;
45 
46     /**
47      * Key to retrieve the RcsPresenceInfo list from intent ACTION_PRESENCE_CHANGED
48      * The RcsPresenceInfo list can be got by the following function call:
49      * ArrayList<RcsPresenceInfo> rcsPresenceInfoList = intent.getParcelableArrayListExtra(
50      *           RcsPresence.EXTRA_PRESENCE_INFO_LIST);
51      *
52      * @see RcsPresenceInfo
53      */
54     public static final String EXTRA_PRESENCE_INFO_LIST = "presence_info_list";
55 
56     /**
57      * Key to retrieve the subscription ID. This is for muliti-SIM implementation.
58      */
59     public static final String EXTRA_SUBID = "android:subid";
60 
61     /**
62      * The intent will be broadcasted when the presence changed.
63      * It happens on the following cases:
64      *   1. When the phone gets a NOTIFY from network.
65      *   2. When the phone gets some SUBSCRIBE error from network for some case (such as 404).
66      * It takes two extra parameters:
67      *   1. EXTRA_PRESENCE_INFO_LIST
68      *     need to get it by the following statement:
69      *     ArrayList<RcsPresenceInfo> rcsPresenceInfoList = intent.getParcelableArrayListExtra(
70      *             RcsPresence.EXTRA_PRESENCE_INFO_LIST);
71      *   2. EXTRA_SUBID
72      *
73      * @see RcsPresenceInfO
74      * @see EXTRA_PRESENCE_INFO_LIST
75      * @see EXTRA_SUBID
76      */
77     public static final String ACTION_PRESENCE_CHANGED = "com.android.ims.ACTION_PRESENCE_CHANGED";
78 
79     /**
80      * Key to retrieve "publish_state" for
81      * intent ACTION_PUBLISH_STATE_CHANGED.
82      *
83      * @See PublishState.
84      * @see ACTION_PUBLISH_STATE_CHANGED
85      */
86     public static final String EXTRA_PUBLISH_STATE = "publish_state";
87 
88     /**
89      * The intent will be broadcasted when latest publish status changed
90      * It takes two extra parameters:
91      * 1. EXTRA_PUBLISH_STATE
92      * 2. EXTRA_SUBID
93      *
94      * @see #EXTRA_PUBLISH_STATE
95      * @see #EXTRA_SUBID
96      * @see PublishState
97      */
98     public static final String ACTION_PUBLISH_STATE_CHANGED =
99             "com.android.ims.ACTION_PUBLISH_STATUS_CHANGED";
100 
101     /**
102      *  The last publish state
103      */
104     public static class PublishState {
105         /**
106          * The phone is PUBLISH_STATE_200_OK when
107          * the response of the last publish is "200 OK"
108          */
109         public static final int PUBLISH_STATE_200_OK = 0;
110 
111         /**
112          * The phone didn't publish after power on.
113          * the phone didn't get any publish response yet.
114          */
115         public static final int PUBLISH_STATE_NOT_PUBLISHED = 1;
116 
117         /**
118          * The phone is PUBLISH_STATE_VOLTE_PROVISION_ERROR when the response is one of items
119           * in config_volte_provision_error_on_publish_response for PUBLISH or
120           * in config_volte_provision_error_on_subscribe_response for SUBSCRIBE.
121          */
122         public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 2;
123 
124         /**
125          * The phone is PUBLISH_STATE_RCS_PROVISION_ERROR when the response is one of items
126           * in config_rcs_provision_error_on_publish_response for PUBLISH or
127           * in config_rcs_provision_error_on_subscribe_response for SUBSCRIBE.
128          */
129         public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 3;
130 
131         /**
132          * The phone is PUBLISH_STATE_REQUEST_TIMEOUT when
133          * The response of the last publish is "408 Request Timeout".
134          */
135         public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 4;
136 
137         /**
138          * The phone is PUBLISH_STATE_OTHER_ERROR when
139          * the response of the last publish is other temp error. Such as
140          * 503 Service Unavailable
141          * Device shall retry with exponential back-off
142          *
143          * 423 Interval Too Short. Requested expiry interval too short and server rejects it
144          * Device shall re-attempt subscription after changing the expiration interval in
145          * the Expires header field to be equal to or greater than the expiration interval
146          * within the Min-Expires header field of the 423 response
147          *
148          * ...
149          */
150         public static final int PUBLISH_STATE_OTHER_ERROR = 5;
151     };
152 
153     /**
154      * Constructor.
155      * @param presenceService the IRcsPresence which get by RcsManager.getRcsPresenceInterface.
156      *
157      * @see RcsManager#getRcsPresenceInterface
158      */
RcsPresence(IRcsPresence presenceService)159     public RcsPresence(IRcsPresence presenceService) {
160         if (DBG) Log.d(TAG, "IRcsPresence creates");
161 
162         mIRcsPresence = presenceService;
163     }
164 
165     /**
166      * Send the request to the server to get the capability.
167      *   1. If the presence service sent the request to network successfully
168      * then it will return the request ID (>0). It will not wait for the response from
169      * network. The response from network will be returned by callback onSuccess() or onError().
170      *   2. If the presence service failed to send the request to network then it will return error
171      *  code which is defined by RcsManager.ResultCode (<0).
172      *   3. If the network returns "200 OK" for a request then the listener.onSuccess() will be
173      * called by presence service.
174      *   4. If the network resturns "404" for a single target number then it means the target
175      * number is not VoLte capable, so the listener.onSuccess() will be called and intent
176      * ACTION_PRESENCE_CHANGED will be broadcasted by presence service.
177      *   5. If the network returns other error then the listener.onError() will be called by
178      * presence service.
179      *   6. If the network returns "200 OK" then we can expect the presence service receives notify
180      * from network. If the presence service receives notify then it will broadcast the
181      * intent ACTION_PRESENCE_CHANGED. If the notify state is "terminated" then the
182      * listener.onFinish() will be called by presence service as well.
183      *   7. If the presence service doesn't get response after "Subscribe Expiration + T1" then the
184      * listener.onTimeout() will be called by presence service.
185      *
186      * @param contactsNumber the contact number list which will be requested.
187      * @param listener the IRcsPresenceListener which will return the status and response.
188      *
189      * @return the request ID if it is >0. Or it is RcsManager.ResultCode for error.
190      *
191      * @see IRcsPresenceListener
192      * @see ResultCode
193      */
requestCapability(List<String> contactsNumber, IRcsPresenceListener listener)194     public int requestCapability(List<String> contactsNumber,
195             IRcsPresenceListener listener) throws RcsException {
196         if (DBG) Log.d(TAG, "call requestCapability, contactsNumber=" + contactsNumber);
197         int ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
198 
199         try {
200             ret = mIRcsPresence.requestCapability(contactsNumber, listener);
201         }  catch (RemoteException e) {
202             throw new RcsException("requestCapability", e,
203                     ResultCode.ERROR_SERVICE_NOT_AVAILABLE);
204         }
205 
206         if (DBG) Log.d(TAG, "requestCapability ret =" + ret);
207         return ret;
208     }
209 
210     /**
211      * Send the request to the server to get the availability.
212      *   1. If the presence service sent the request to network successfully then it will return
213      * the request ID (>0).
214      *   2. If the presence serive failed to send the request to network then it will return error
215      * code which is defined by RcsManager.ResultCode (<0).
216      *   3. If the network returns "200 OK" for a request then the listener.onSuccess() will be
217      * called by presence service.
218      *   4. If the network resturns "404" then it means the target number is not VoLte capable,
219      * so the listener.onSuccess() will be called and intent ACTION_PRESENCE_CHANGED will be
220      * broadcasted by presence service.
221      *   5. If the network returns other error code then the listener.onError() will be called by
222      * presence service.
223      *   6. If the network returns "200 OK" then we can expect the presence service receives notify
224      * from network. If the presence service receives notify then it will broadcast the intent
225      * ACTION_PRESENCE_CHANGED. If the notify state is "terminated" then the listener.onFinish()
226      * will be called by presence service as well.
227      *   7. If the presence service doesn't get response after "Subscribe Expiration + T1" then it
228      * will call listener.onTimeout().
229      *
230      * @param contactNumber the contact which will request the availability.
231      *     Only support phone number at present.
232      * @param listener the IRcsPresenceListener to get the response.
233      *
234      * @return the request ID if it is >0. Or it is RcsManager.ResultCode for error.
235      *
236      * @see IRcsPresenceListener
237      * @see ResultCode
238      * @see RcsPresence.ACTION_PRESENCE_CHANGED
239      */
requestAvailability(String contactNumber, IRcsPresenceListener listener)240     public int requestAvailability(String contactNumber, IRcsPresenceListener listener)
241              throws RcsException {
242         if (DBG) Log.d(TAG, "call requestAvailability, contactNumber=" + contactNumber);
243         int ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
244 
245         try {
246             ret = mIRcsPresence.requestAvailability(contactNumber, listener);
247         }  catch (RemoteException e) {
248             throw new RcsException("requestAvailability", e,
249                     ResultCode.ERROR_SERVICE_NOT_AVAILABLE);
250         }
251 
252         if (DBG) Log.d(TAG, "requestAvailability ret =" + ret);
253         return ret;
254     }
255 
256     /**
257      * Same as requestAvailability. but requestAvailability will consider throttle to avoid too
258      * fast call. Which means it will not send the request to network in next 60s for the same
259      * request.
260      * The error code SUBSCRIBE_TOO_FREQUENTLY will be returned under the case.
261      * But for this funcation it will always send the request to network.
262      *
263      * @see IRcsPresenceListener
264      * @see ResultCode
265      * @see RcsPresence.ACTION_PRESENCE_CHANGED
266      * @see ResultCode.SUBSCRIBE_TOO_FREQUENTLY
267      */
requestAvailabilityNoThrottle(String contactNumber, IRcsPresenceListener listener)268     public int requestAvailabilityNoThrottle(String contactNumber, IRcsPresenceListener listener)
269              throws RcsException {
270         if (DBG) Log.d(TAG, "call requestAvailabilityNoThrottle, contactNumber=" + contactNumber);
271         int ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
272 
273         try {
274             ret = mIRcsPresence.requestAvailabilityNoThrottle(contactNumber, listener);
275         }  catch (RemoteException e) {
276             throw new RcsException("requestAvailabilityNoThrottle", e,
277                     ResultCode.ERROR_SERVICE_NOT_AVAILABLE);
278         }
279 
280         if (DBG) Log.d(TAG, "requestAvailabilityNoThrottle ret =" + ret);
281         return ret;
282     }
283 
284     /**
285      * Get the latest publish state.
286      *
287      * @see PublishState
288      */
getPublishState()289     public int getPublishState() throws RcsException {
290         int ret = PublishState.PUBLISH_STATE_NOT_PUBLISHED;
291         try {
292             ret = mIRcsPresence.getPublishState();
293         }  catch (RemoteException e) {
294             throw new RcsException("getPublishState", e,
295                     ResultCode.ERROR_SERVICE_NOT_AVAILABLE);
296         }
297 
298         if (DBG) Log.d(TAG, "getPublishState ret =" + ret);
299         return ret;
300     }
301 }
302 
303