• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.content.Context;
32 import android.content.Intent;
33 import android.os.IBinder;
34 import android.os.IBinder.DeathRecipient;
35 import android.os.RemoteException;
36 import android.os.ServiceManager;
37 import android.telephony.Rlog;
38 
39 import com.android.ims.internal.IRcsService;
40 import com.android.ims.internal.IRcsPresence;
41 
42 import java.util.HashMap;
43 
44 /**
45  * Provides APIs for Rcs services, currently it supports presence only.
46  * This class is the starting point for any RCS actions.
47  * You can acquire an instance of it with {@link #getInstance getInstance()}.
48  *
49  * @hide
50  */
51 public class RcsManager {
52     /**
53      * For accessing the RCS related service.
54      * Internal use only.
55      *
56      * @hide
57      */
58     private static final String RCS_SERVICE = "rcs";
59 
60     /**
61      * Part of the ACTION_RCS_SERVICE_AVAILABLE and ACTION_RCS_SERVICE_UNAVAILABLE intents.
62      * A long value; the subId corresponding to the RCS service. For MSIM implementation.
63      *
64      * @see #ACTION_RCS_SERVICE_AVAILABLE
65      * @see #ACTION_RCS_SERVICE_UNAVAILABLE
66      */
67     public static final String EXTRA_SUBID = "android:subid";
68 
69     /**
70      * Action to broadcast when RcsService is available.
71      *
72      * @see #EXTRA_SUBID
73      */
74     public static final String ACTION_RCS_SERVICE_AVAILABLE =
75             "com.android.ims.ACTION_RCS_SERVICE_AVAILABLE";
76 
77     /**
78      * Action to broadcast when RcsService is unavailable (such as ims is not registered).
79      *
80      * @see #EXTRA_SUBID
81      */
82     public static final String ACTION_RCS_SERVICE_UNAVAILABLE =
83             "com.android.ims.ACTION_RCS_SERVICE_UNAVAILABLE";
84 
85     /**
86      * Action to broadcast when RcsService is died.
87      * The caller can listen to the intent to clean the pending request.
88      *
89      * It takes the extra parameter subid as well since it depends on OEM implementation for
90      * RcsService. It will not send broadcast for ACTION_RCS_SERVICE_UNAVAILABLE under the case.
91      *
92      * @see #EXTRA_SUBID
93      */
94     public static final String ACTION_RCS_SERVICE_DIED =
95             "com.android.ims.ACTION_RCS_SERVICE_DIED";
96 
97     public static class ResultCode {
98         /**
99          * The code is used when the request is success.
100          */
101         public static final int SUCCESS =0;
102 
103         /**
104          * Return this code if the service doesn't be enabled on the phone.
105          * As per the requirement the feature can be enabled/disabled by DM.
106          */
107         public static final int ERROR_SERVICE_NOT_ENABLED = -1;
108 
109         /**
110          * Return this code if the service didn't publish yet.
111          */
112         public static final int ERROR_SERVICE_NOT_PUBLISHED = -2;
113 
114         /**
115          * The service is not available, for example it is 1x only
116          */
117         public static final int ERROR_SERVICE_NOT_AVAILABLE = -3;
118 
119         /**
120          *  SUBSCRIBE Error base
121          */
122         public static final int SUBSCRIBER_ERROR_CODE_START = ERROR_SERVICE_NOT_AVAILABLE;
123 
124         /**
125          * Temporary error and need retry later.
126          * such as:
127          * 503 Service Unavailable
128          * Device shall retry with exponential back-off
129          *
130          * 408 Request Timeout
131          * Device shall retry with exponential back-off
132          *
133          * 423 Interval Too Short. Requested expiry interval too short and server rejects it
134          * Device shall re-attempt subscription after changing the expiration interval in
135          * the Expires header field to be equal to or greater than the expiration interval
136          * within the Min-Expires header field of the 423 response
137          */
138         public static final int SUBSCRIBE_TEMPORARY_ERROR = SUBSCRIBER_ERROR_CODE_START - 1;
139 
140         /**
141          * receives 403 (reason="User Not Registered").
142          * Re-Register to IMS then retry the single resource subscription if capability polling.
143          * availability fetch: no retry.
144          */
145          public static final int SUBSCRIBE_NOT_REGISTERED = SUBSCRIBER_ERROR_CODE_START - 2;
146 
147         /**
148          * Responding for 403 - not authorized (Requestor)
149          * No retry.
150          */
151         public static final int SUBSCRIBE_NOT_AUTHORIZED_FOR_PRESENCE =
152                 SUBSCRIBER_ERROR_CODE_START - 3;
153 
154         /**
155          * Responding for "403 Forbidden" or "403"
156          * Handle it as same as 404 Not found.
157          * No retry.
158          */
159         public static final int SUBSCRIBE_FORBIDDEN = SUBSCRIBER_ERROR_CODE_START - 4;
160 
161         /**
162          * Responding for 404 (target number)
163          * No retry.
164          */
165         public static final int SUBSCRIBE_NOT_FOUND = SUBSCRIBER_ERROR_CODE_START - 5;
166 
167         /**
168          *  Responding for 413 - Too Large. Top app need shrink the size
169          *  of request contact list and resend the request
170          */
171         public static final int SUBSCRIBE_TOO_LARGE = SUBSCRIBER_ERROR_CODE_START - 6;
172 
173         /**
174          * All subscribe errors not covered by specific errors
175          * Other 4xx/5xx/6xx
176          *
177          * Device shall not retry
178          */
179         public static final int SUBSCRIBE_GENIRIC_FAILURE = SUBSCRIBER_ERROR_CODE_START - 7;
180 
181         /**
182          * Invalid parameter - The caller should check the parameter.
183          */
184         public static final int SUBSCRIBE_INVALID_PARAM = SUBSCRIBER_ERROR_CODE_START - 8;
185 
186         /**
187          * Fetch error - The RCS statck failed to fetch the presence information.
188          */
189         public static final int SUBSCRIBE_FETCH_ERROR = SUBSCRIBER_ERROR_CODE_START - 9;
190 
191         /**
192          * Request timeout - The RCS statck returns timeout error.
193          */
194         public static final int SUBSCRIBE_REQUEST_TIMEOUT = SUBSCRIBER_ERROR_CODE_START - 10;
195 
196         /**
197          * Insufficient memory - The RCS statck returns the insufficient memory error.
198          */
199         public static final int SUBSCRIBE_INSUFFICIENT_MEMORY = SUBSCRIBER_ERROR_CODE_START - 11;
200 
201         /**
202          * Lost network error - The RCS statck returns the lost network error.
203          */
204         public static final int SUBSCRIBE_LOST_NETWORK = SUBSCRIBER_ERROR_CODE_START - 12;
205 
206         /**
207          * Not supported error - The RCS statck returns the not supported error.
208          */
209         public static final int SUBSCRIBE_NOT_SUPPORTED = SUBSCRIBER_ERROR_CODE_START - 13;
210 
211         /**
212          * Generic error - RCS Presence stack returns generic error
213          */
214         public static final int SUBSCRIBE_GENERIC = SUBSCRIBER_ERROR_CODE_START - 14;
215 
216         /**
217          * There is a request for the same number in queue.
218          */
219         public static final int SUBSCRIBE_ALREADY_IN_QUEUE = SUBSCRIBER_ERROR_CODE_START - 16;
220 
221         /**
222          * Request too frequently.
223          */
224         public static final int SUBSCRIBE_TOO_FREQUENTLY = SUBSCRIBER_ERROR_CODE_START - 17;
225 
226         /**
227          *  The last Subscriber error code
228          */
229         public static final int SUBSCRIBER_ERROR_CODE_END = SUBSCRIBER_ERROR_CODE_START - 17;
230     };
231 
232     private static final String TAG = "RcsManager";
233     private static final boolean DBG = true;
234 
235     private static HashMap<Integer, RcsManager> sRcsManagerInstances =
236             new HashMap<Integer, RcsManager>();
237 
238     private Context mContext;
239     private int mSubId;
240     private IRcsService mRcsService = null;
241     private RcsServiceDeathRecipient mDeathRecipient = new RcsServiceDeathRecipient();
242 
243     // Interface for presence
244     // TODO: Could add other RCS service such RcsChat, RcsFt later.
245     private RcsPresence  mRcsPresence = null;
246 
247     /**
248      * Gets a manager instance.
249      *
250      * @param context application context for creating the manager object
251      * @param subId the subscription ID for the RCS Service
252      * @return the manager instance corresponding to the subId
253      */
getInstance(Context context, int subId)254     public static RcsManager getInstance(Context context, int subId) {
255         synchronized (sRcsManagerInstances) {
256             if (sRcsManagerInstances.containsKey(subId)){
257                 return sRcsManagerInstances.get(subId);
258             }
259 
260             RcsManager mgr = new RcsManager(context, subId);
261             sRcsManagerInstances.put(subId, mgr);
262 
263             return mgr;
264         }
265     }
266 
RcsManager(Context context, int subId)267     private RcsManager(Context context, int subId) {
268         mContext = context;
269         mSubId = subId;
270         createRcsService(true);
271     }
272 
273     /**
274      * return true if the rcs service is ready for use.
275      */
isRcsServiceAvailable()276     public boolean isRcsServiceAvailable() {
277         if (DBG) Rlog.d(TAG, "call isRcsServiceAvailable ...");
278 
279         boolean ret = false;
280 
281         try {
282             checkAndThrowExceptionIfServiceUnavailable();
283 
284             ret = mRcsService.isRcsServiceAvailable();
285         }  catch (RemoteException e) {
286             // return false under the case.
287             Rlog.e(TAG, "isRcsServiceAvailable RemoteException", e);
288         }catch (RcsException e){
289             // return false under the case.
290             Rlog.e(TAG, "isRcsServiceAvailable RcsException", e);
291         }
292 
293         if (DBG) Rlog.d(TAG, "isRcsServiceAvailable ret =" + ret);
294         return ret;
295     }
296 
297     /**
298      * Gets the presence interface
299      *
300      * @return the RcsPresence instance.
301      * @throws  if getting the RcsPresence interface results in an error.
302      */
getRcsPresenceInterface()303     public RcsPresence getRcsPresenceInterface() throws RcsException {
304 
305         if (mRcsPresence == null) {
306             checkAndThrowExceptionIfServiceUnavailable();
307 
308             try {
309                 IRcsPresence rcsPresence = mRcsService.getRcsPresenceInterface();
310                 if (rcsPresence == null) {
311                     throw new RcsException("getRcsPresenceInterface()",
312                             ResultCode.ERROR_SERVICE_NOT_AVAILABLE);
313                 }
314                 mRcsPresence = new RcsPresence(rcsPresence);
315             } catch (RemoteException e) {
316                 throw new RcsException("getRcsPresenceInterface()", e,
317                         ResultCode.ERROR_SERVICE_NOT_AVAILABLE);
318             }
319         }
320         if (DBG) Rlog.d(TAG, "getRcsPresenceInterface(), mRcsPresence= " + mRcsPresence);
321         return mRcsPresence;
322     }
323 
324     /**
325      * Binds the RCS service only if the service is not created.
326      */
checkAndThrowExceptionIfServiceUnavailable()327     private void checkAndThrowExceptionIfServiceUnavailable()
328             throws  RcsException {
329         if (mRcsService == null) {
330             createRcsService(true);
331 
332             if (mRcsService == null) {
333                 throw new RcsException("Service is unavailable",
334                         ResultCode.ERROR_SERVICE_NOT_AVAILABLE);
335             }
336         }
337     }
338 
getRcsServiceName(int subId)339     private static String getRcsServiceName(int subId) {
340         // use the same mechanism as IMS_SERVICE?
341         return RCS_SERVICE;
342     }
343 
344     /**
345      * Binds the RCS service.
346      */
createRcsService(boolean checkService)347     private void createRcsService(boolean checkService) {
348         if (checkService) {
349             IBinder binder = ServiceManager.checkService(getRcsServiceName(mSubId));
350 
351             if (binder == null) {
352                 return;
353             }
354         }
355 
356         IBinder b = ServiceManager.getService(getRcsServiceName(mSubId));
357 
358         if (b != null) {
359             try {
360                 b.linkToDeath(mDeathRecipient, 0);
361             } catch (RemoteException e) {
362             }
363         }
364 
365         mRcsService = IRcsService.Stub.asInterface(b);
366     }
367 
368     /**
369      * Death recipient class for monitoring RCS service.
370      */
371     private class RcsServiceDeathRecipient implements IBinder.DeathRecipient {
372         @Override
binderDied()373         public void binderDied() {
374             mRcsService = null;
375             mRcsPresence = null;
376 
377             if (mContext != null) {
378                 Intent intent = new Intent(ACTION_RCS_SERVICE_DIED);
379                 intent.putExtra(EXTRA_SUBID, mSubId);
380                 mContext.sendBroadcast(new Intent(intent));
381             }
382         }
383     }
384 }
385