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;
18 
19 import android.Manifest;
20 import android.annotation.CallbackExecutor;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SystemApi;
26 import android.content.Context;
27 import android.net.Uri;
28 import android.os.Binder;
29 import android.os.IBinder;
30 import android.os.RemoteException;
31 import android.os.ServiceSpecificException;
32 import android.telephony.TelephonyFrameworkInitializer;
33 import android.telephony.ims.aidl.IImsRcsController;
34 import android.telephony.ims.aidl.IRcsUceControllerCallback;
35 import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
36 import android.util.Log;
37 
38 import java.lang.annotation.Retention;
39 import java.lang.annotation.RetentionPolicy;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.HashMap;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.concurrent.Executor;
46 
47 /**
48  * Manages RCS User Capability Exchange for the subscription specified.
49  *
50  * @see ImsRcsManager#getUceAdapter() for information on creating an instance of this class.
51  */
52 public class RcsUceAdapter {
53     private static final String TAG = "RcsUceAdapter";
54 
55     /**
56      * This carrier supports User Capability Exchange as, defined by the framework using
57      * SIP OPTIONS. If set, the RcsFeature should support capability exchange. If not set, this
58      * RcsFeature should not publish capabilities or service capability requests.
59      * @deprecated Use {@link ImsRcsManager#CAPABILITY_TYPE_OPTIONS_UCE} instead.
60      * @hide
61      */
62     @Deprecated
63     public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1 << 0;
64 
65     /**
66      * This carrier supports User Capability Exchange as, defined by the framework using a
67      * presence server. If set, the RcsFeature should support capability exchange. If not set, this
68      * RcsFeature should not publish capabilities or service capability requests.
69      * @deprecated Use {@link ImsRcsManager#CAPABILITY_TYPE_PRESENCE_UCE} instead.
70      * @hide
71      */
72     @Deprecated
73     @SystemApi
74     public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
75 
76     /**
77      * @deprecated Use {@link ImsRcsManager.RcsImsCapabilityFlag} instead.
78      * @hide
79      */
80     @Deprecated
81     @Retention(RetentionPolicy.SOURCE)
82     @IntDef(prefix = "CAPABILITY_TYPE_", value = {
83             CAPABILITY_TYPE_OPTIONS_UCE,
84             CAPABILITY_TYPE_PRESENCE_UCE
85     })
86     public @interface RcsImsCapabilityFlag {}
87 
88     /**
89      * An unknown error has caused the request to fail.
90      * @hide
91      */
92     @SystemApi
93     public static final int ERROR_GENERIC_FAILURE = 1;
94 
95     /**
96      * The carrier network does not have UCE support enabled for this subscriber.
97      * @hide
98      */
99     @SystemApi
100     public static final int ERROR_NOT_ENABLED = 2;
101 
102     /**
103      * The data network that the device is connected to does not support UCE currently (e.g. it is
104      * 1x only currently).
105      * @hide
106      */
107     @SystemApi
108     public static final int ERROR_NOT_AVAILABLE = 3;
109 
110     /**
111      * The network has responded with SIP 403 error and a reason "User not registered."
112      * @hide
113      */
114     @SystemApi
115     public static final int ERROR_NOT_REGISTERED = 4;
116 
117     /**
118      * The network has responded to this request with a SIP 403 error and reason "not authorized for
119      * presence" for this subscriber.
120      * @hide
121      */
122     @SystemApi
123     public static final int ERROR_NOT_AUTHORIZED = 5;
124 
125     /**
126      * The network has responded to this request with a SIP 403 error and no reason.
127      * @hide
128      */
129     @SystemApi
130     public static final int ERROR_FORBIDDEN = 6;
131 
132     /**
133      * The contact URI requested is not provisioned for voice or it is not known as an IMS
134      * subscriber to the carrier network.
135      * @hide
136      */
137     @SystemApi
138     public static final int ERROR_NOT_FOUND = 7;
139 
140     /**
141      * The capabilities request contained too many URIs for the carrier network to handle. Retry
142      * with a lower number of contact numbers. The number varies per carrier.
143      * @hide
144      */
145     @SystemApi
146     // TODO: Try to integrate this into the API so that the service will split based on carrier.
147     public static final int ERROR_REQUEST_TOO_LARGE = 8;
148 
149     /**
150      * The network did not respond to the capabilities request before the request timed out.
151      * @hide
152      */
153     @SystemApi
154     public static final int ERROR_REQUEST_TIMEOUT = 9;
155 
156     /**
157      * The request failed due to the service having insufficient memory.
158      * @hide
159      */
160     @SystemApi
161     public static final int ERROR_INSUFFICIENT_MEMORY = 10;
162 
163     /**
164      * The network was lost while trying to complete the request.
165      * @hide
166      */
167     @SystemApi
168     public static final int ERROR_LOST_NETWORK = 11;
169 
170     /**
171      * The network is temporarily unavailable or busy. Retries should only be done after the retry
172      * time returned in {@link CapabilitiesCallback#onError} has elapsed.
173      * @hide
174      */
175     @SystemApi
176     public static final int ERROR_SERVER_UNAVAILABLE = 12;
177 
178     /**@hide*/
179     @Retention(RetentionPolicy.SOURCE)
180     @IntDef(prefix = "ERROR_", value = {
181             ERROR_GENERIC_FAILURE,
182             ERROR_NOT_ENABLED,
183             ERROR_NOT_AVAILABLE,
184             ERROR_NOT_REGISTERED,
185             ERROR_NOT_AUTHORIZED,
186             ERROR_FORBIDDEN,
187             ERROR_NOT_FOUND,
188             ERROR_REQUEST_TOO_LARGE,
189             ERROR_REQUEST_TIMEOUT,
190             ERROR_INSUFFICIENT_MEMORY,
191             ERROR_LOST_NETWORK,
192             ERROR_SERVER_UNAVAILABLE
193     })
194     public @interface ErrorCode {}
195 
196     /**
197      * A capability update has been requested but the reason is unknown.
198      * @hide
199      */
200     @SystemApi
201     public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 0;
202 
203     /**
204      * A capability update has been requested due to the Entity Tag (ETag) expiring.
205      * @hide
206      */
207     @SystemApi
208     public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1;
209 
210     /**
211      * A capability update has been requested due to moving to LTE with VoPS disabled.
212      * @hide
213      */
214     @SystemApi
215     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 2;
216 
217     /**
218      * A capability update has been requested due to moving to LTE with VoPS enabled.
219      * @hide
220      */
221     @SystemApi
222     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 3;
223 
224     /**
225      * A capability update has been requested due to moving to eHRPD.
226      * @hide
227      */
228     @SystemApi
229     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 4;
230 
231     /**
232      * A capability update has been requested due to moving to HSPA+.
233      * @hide
234      */
235     @SystemApi
236     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 5;
237 
238     /**
239      * A capability update has been requested due to moving to 3G.
240      * @hide
241      */
242     @SystemApi
243     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6;
244 
245     /**
246      * A capability update has been requested due to moving to 2G.
247      * @hide
248      */
249     @SystemApi
250     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7;
251 
252     /**
253      * A capability update has been requested due to moving to WLAN
254      * @hide
255      */
256     @SystemApi
257     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 8;
258 
259     /**
260      * A capability update has been requested due to moving to IWLAN
261      * @hide
262      */
263     @SystemApi
264     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 9;
265 
266     /**
267      * A capability update has been requested due to moving to 5G NR with VoPS disabled.
268      * @hide
269      */
270     @SystemApi
271     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10;
272 
273     /**
274      * A capability update has been requested due to moving to 5G NR with VoPS enabled.
275      * @hide
276      */
277     @SystemApi
278     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11;
279 
280     /**
281      * A capability update has been requested due to IMS being registered over INTERNET PDN.
282      * @hide
283      */
284     @SystemApi
285     public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_INTERNET_PDN = 12;
286 
287     /**@hide*/
288     @Retention(RetentionPolicy.SOURCE)
289     @IntDef(prefix = "ERROR_", value = {
290             CAPABILITY_UPDATE_TRIGGER_UNKNOWN,
291             CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED,
292             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED,
293             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED,
294             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD,
295             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS,
296             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G,
297             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G,
298             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN,
299             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN,
300             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED,
301             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED,
302             CAPABILITY_UPDATE_TRIGGER_MOVE_TO_INTERNET_PDN
303     })
304     public @interface StackPublishTriggerType {}
305 
306     /**
307      * The last publish has resulted in a "200 OK" response or the device is using SIP OPTIONS for
308      * UCE.
309      * @hide
310      */
311     @SystemApi
312     public static final int PUBLISH_STATE_OK = 1;
313 
314     /**
315      * The hasn't published its capabilities since boot or hasn't gotten any publish response yet.
316      * @hide
317      */
318     @SystemApi
319     public static final int PUBLISH_STATE_NOT_PUBLISHED = 2;
320 
321     /**
322      * The device has tried to publish its capabilities, which has resulted in an error. This error
323      * is related to the fact that the device is not provisioned for voice.
324      * @hide
325      */
326     @SystemApi
327     public static final int PUBLISH_STATE_VOICE_PROVISION_ERROR = 3;
328 
329     /**
330      * The device has tried to publish its capabilities, which has resulted in an error. This error
331      * is related to the fact that the device is not RCS or UCE provisioned.
332      * @hide
333      */
334     @SystemApi
335     public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4;
336 
337     /**
338      * The last publish resulted in a "408 Request Timeout" response.
339      * @hide
340      */
341     @SystemApi
342     public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5;
343 
344     /**
345      * The last publish resulted in another unknown error, such as SIP 503 - "Service Unavailable"
346      * or SIP 423 - "Interval too short".
347      * <p>
348      * Device shall retry with exponential back-off.
349      * @hide
350      */
351     @SystemApi
352     public static final int PUBLISH_STATE_OTHER_ERROR = 6;
353 
354     /**
355      * The device is currently trying to publish its capabilities to the network.
356      * @hide
357      */
358     @SystemApi
359     public static final int PUBLISH_STATE_PUBLISHING = 7;
360 
361 
362     /**@hide*/
363     @Retention(RetentionPolicy.SOURCE)
364     @IntDef(prefix = "PUBLISH_STATE_", value = {
365             PUBLISH_STATE_OK,
366             PUBLISH_STATE_NOT_PUBLISHED,
367             PUBLISH_STATE_VOICE_PROVISION_ERROR,
368             PUBLISH_STATE_RCS_PROVISION_ERROR,
369             PUBLISH_STATE_REQUEST_TIMEOUT,
370             PUBLISH_STATE_OTHER_ERROR,
371             PUBLISH_STATE_PUBLISHING
372     })
373     public @interface PublishState {}
374 
375     /**
376      * An application can use {@link #addOnPublishStateChangedListener} to register a
377      * {@link OnPublishStateChangedListener ), which will notify the user when the publish state to
378      * the network changes.
379      * @hide
380      */
381     @SystemApi
382     public interface OnPublishStateChangedListener {
383         /**
384          * Notifies the callback when the publish state has changed.
385          * @param publishState The latest update to the publish state.
386          *
387          * @deprecated Replaced by {@link #onPublishStateChange}, deprecated for
388          * sip information.
389          */
390         @Deprecated
onPublishStateChange(@ublishState int publishState)391         void onPublishStateChange(@PublishState int publishState);
392 
393         /**
394          * Notifies the callback when the publish state has changed or the publish operation is
395          * done.
396          * @param attributes The latest information related to the publish.
397          */
onPublishStateChange(@onNull PublishAttributes attributes)398         default void onPublishStateChange(@NonNull PublishAttributes attributes) {
399             onPublishStateChange(attributes.getPublishState());
400         };
401     }
402 
403     /**
404      * An application can use {@link #addOnPublishStateChangedListener} to register a
405      * {@link OnPublishStateChangedListener ), which will notify the user when the publish state to
406      * the network changes.
407      * @hide
408      */
409     public static class PublishStateCallbackAdapter {
410 
411         private static class PublishStateBinder extends IRcsUcePublishStateCallback.Stub {
412             private final OnPublishStateChangedListener mPublishStateChangeListener;
413             private final Executor mExecutor;
414 
PublishStateBinder(Executor executor, OnPublishStateChangedListener listener)415             PublishStateBinder(Executor executor, OnPublishStateChangedListener listener) {
416                 mExecutor = executor;
417                 mPublishStateChangeListener = listener;
418             }
419 
420             @Override
onPublishUpdated(@onNull PublishAttributes attributes)421             public void onPublishUpdated(@NonNull PublishAttributes attributes) {
422                 if (mPublishStateChangeListener == null) return;
423 
424                 final long callingIdentity = Binder.clearCallingIdentity();
425                 try {
426                     mExecutor.execute(() ->
427                             mPublishStateChangeListener.onPublishStateChange(attributes));
428                 } finally {
429                     restoreCallingIdentity(callingIdentity);
430                 }
431             }
432         }
433 
434         private final PublishStateBinder mBinder;
435 
PublishStateCallbackAdapter(@onNull Executor executor, @NonNull OnPublishStateChangedListener listener)436         public PublishStateCallbackAdapter(@NonNull Executor executor,
437                 @NonNull OnPublishStateChangedListener listener) {
438             mBinder = new PublishStateBinder(executor, listener);
439         }
440 
441         /**@hide*/
getBinder()442         public final IRcsUcePublishStateCallback getBinder() {
443             return mBinder;
444         }
445     }
446 
447     /**
448      * A callback for the response to a UCE request. The method
449      * {@link CapabilitiesCallback#onCapabilitiesReceived} will be called zero or more times as the
450      * capabilities are fetched from multiple sources, both cached on the device and on the network.
451      * <p>
452      * This request will take a varying amount of time depending on if the contacts requested are
453      * cached or if it requires a network query. The timeout time of these requests can vary
454      * depending on the network, however in poor cases it could take up to a minute for a request
455      * to timeout. In that time, only a subset of capabilities may have been retrieved.
456      * <p>
457      * After {@link CapabilitiesCallback#onComplete} or {@link CapabilitiesCallback#onError} has
458      * been called, the reference to this callback will be discarded on the service side.
459      * @see #requestCapabilities(Collection, Executor, CapabilitiesCallback)
460      * @hide
461      */
462     @SystemApi
463     public interface CapabilitiesCallback {
464 
465         /**
466          * The pending capability request has completed successfully for one or more of the
467          * requested contacts.
468          * This may be called one or more times before the request is fully completed, as
469          * capabilities may need to be fetched from multiple sources both on device and on the
470          * network. Once the capabilities of all the requested contacts have been received,
471          * {@link #onComplete()} will be called. If there was an error during the capability
472          * exchange process, {@link #onError(int, long)} will be called instead.
473          * @param contactCapabilities List of capabilities associated with each contact requested.
474          */
onCapabilitiesReceived(@onNull List<RcsContactUceCapability> contactCapabilities)475         void onCapabilitiesReceived(@NonNull List<RcsContactUceCapability> contactCapabilities);
476 
477         /**
478          * Called when the pending request has completed successfully due to all requested contacts
479          * information being delivered. The callback {@link #onCapabilitiesReceived(List)} will be
480          * called one or more times and will contain the contacts in the request that the device has
481          * received capabilities for.
482          *
483          * @see #onComplete(SipDetails) onComplete(SipDetails) provides more information related to
484          * the underlying SIP transaction used to perform the capabilities exchange. Either this
485          * method or the alternate method should be implemented to determine when the request has
486          * completed successfully.
487          */
onComplete()488         default void onComplete() {}
489 
490         /**
491          * The pending request has resulted in an error and may need to be retried, depending on the
492          * error code.
493          * @param errorCode The reason for the framework being unable to process the request.
494          * @param retryIntervalMillis The time in milliseconds the requesting application should
495          * wait before retrying, if non-zero.
496          *
497          * @see #onError(int, long, SipDetails) onError(int, long, SipDetails) provides more
498          * information related to the underlying SIP transaction that resulted in an error. Either
499          * this method or the alternative method should be implemented to determine when the
500          * request has completed with an error.
501          */
onError(@rrorCode int errorCode, long retryIntervalMillis)502         default void onError(@ErrorCode int errorCode, long retryIntervalMillis) {}
503 
504         /**
505          * Called when the pending request has completed successfully due to all requested contacts
506          * information being delivered. The callback {@link #onCapabilitiesReceived(List)} will be
507          * called one or more times and will contain the contacts in the request that the device has
508          * received capabilities for.
509          *
510          * This method contains more information about the underlying SIP transaction if it exists.
511          * If this information is not needed, {@link #onComplete()} can be implemented
512          * instead.
513          *
514          * @param details The SIP information related to this request if the device supports
515          *                supplying this information. This parameter will be {@code null} if this
516          *                information is not available.
517          */
onComplete(@ullable SipDetails details)518         default void onComplete(@Nullable SipDetails details) {
519             onComplete();
520         };
521 
522         /**
523          * The pending request has resulted in an error and may need to be retried, depending on the
524          * error code.
525          *
526          * This method contains more information about the underlying SIP transaction if it exists.
527          * If this information is not needed, {@link #onError(int, long)} can be implemented
528          * instead.
529          * @param errorCode The reason for the framework being unable to process the request.
530          * @param retryIntervalMillis The time in milliseconds the requesting application should
531          * wait before retrying, if non-zero.
532          * @param details The SIP information related to this request if the device supports
533          *                supplying this information. This parameter will be {@code null} if this
534          *                information is not available.
535          */
onError(@rrorCode int errorCode, long retryIntervalMillis, @Nullable SipDetails details)536         default void onError(@ErrorCode int errorCode, long retryIntervalMillis,
537                 @Nullable SipDetails details) {
538             onError(errorCode, retryIntervalMillis);
539         };
540     }
541 
542     private final Context mContext;
543     private final int mSubId;
544     private final Map<OnPublishStateChangedListener, PublishStateCallbackAdapter>
545             mPublishStateCallbacks;
546 
547     /**
548      * Not to be instantiated directly, use {@link ImsRcsManager#getUceAdapter()} to instantiate
549      * this manager class.
550      * @hide
551      */
RcsUceAdapter(Context context, int subId)552     RcsUceAdapter(Context context, int subId) {
553         mContext = context;
554         mSubId = subId;
555         mPublishStateCallbacks = new HashMap<>();
556     }
557 
558     /**
559      * Request the RCS capabilities for one or more contacts using RCS User Capability Exchange.
560      * <p>
561      * This API will first check a local cache for the requested numbers and return the cached
562      * RCS capabilities of each number if the cache exists and is not stale. If the cache for a
563      * number is stale or there is no cached information about the requested number, the device will
564      * then perform a query to the carrier's network to request the RCS capabilities of the
565      * requested numbers.
566      * <p>
567      * Depending on the number of requests being sent, this API may throttled internally as the
568      * operations are queued to be executed by the carrier's network.
569      * <p>
570      * Be sure to check the availability of this feature using
571      * {@link ImsRcsManager#isAvailable(int, int)} and ensuring
572      * {@link
573      * android.telephony.ims.feature.RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or
574      * {@link
575      * android.telephony.ims.feature.RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is
576      * enabled or else this operation will fail with {@link #ERROR_NOT_AVAILABLE} or
577      * {@link #ERROR_NOT_ENABLED}.
578      *
579      * @param contactNumbers A list of numbers that the capabilities are being requested for.
580      * @param executor The executor that will be used when the request is completed and the
581      *         {@link CapabilitiesCallback} is called.
582      * @param c A one-time callback for when the request for capabilities completes or there is an
583      *         error processing the request.
584      * @throws ImsException if the subscription associated with this instance of
585      * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
586      * available. This can happen if the ImsService has crashed, for example, or if the subscription
587      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
588      * @hide
589      */
590     @SystemApi
591     @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
592             Manifest.permission.READ_CONTACTS})
requestCapabilities(@onNull Collection<Uri> contactNumbers, @NonNull @CallbackExecutor Executor executor, @NonNull CapabilitiesCallback c)593     public void requestCapabilities(@NonNull Collection<Uri> contactNumbers,
594             @NonNull @CallbackExecutor Executor executor,
595             @NonNull CapabilitiesCallback c) throws ImsException {
596         if (c == null) {
597             throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
598         }
599         if (executor == null) {
600             throw new IllegalArgumentException("Must include a non-null Executor.");
601         }
602         if (contactNumbers == null) {
603             throw new IllegalArgumentException("Must include non-null contact number list.");
604         }
605 
606         IImsRcsController imsRcsController = getIImsRcsController();
607         if (imsRcsController == null) {
608             Log.e(TAG, "requestCapabilities: IImsRcsController is null");
609             throw new ImsException("Can not find remote IMS service",
610                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
611         }
612 
613         IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
614             @Override
615             public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
616                 final long callingIdentity = Binder.clearCallingIdentity();
617                 try {
618                     executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
619                 } finally {
620                     restoreCallingIdentity(callingIdentity);
621                 }
622             }
623             @Override
624             public void onComplete(@Nullable SipDetails details) {
625                 final long callingIdentity = Binder.clearCallingIdentity();
626                 try {
627                     executor.execute(() -> c.onComplete(details));
628                 } finally {
629                     restoreCallingIdentity(callingIdentity);
630                 }
631             }
632             @Override
633             public void onError(int errorCode, long retryAfterMilliseconds,
634                     @Nullable SipDetails details) {
635                 final long callingIdentity = Binder.clearCallingIdentity();
636                 try {
637                     executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds, details));
638                 } finally {
639                     restoreCallingIdentity(callingIdentity);
640                 }
641             }
642         };
643 
644         try {
645             imsRcsController.requestCapabilities(mSubId, mContext.getOpPackageName(),
646                     mContext.getAttributionTag(), new ArrayList(contactNumbers), internalCallback);
647         } catch (ServiceSpecificException e) {
648             throw new ImsException(e.toString(), e.errorCode);
649         } catch (RemoteException e) {
650             Log.e(TAG, "Error calling IImsRcsController#requestCapabilities", e);
651             throw new ImsException("Remote IMS Service is not available",
652                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
653         }
654     }
655 
656     /**
657      * Request the RCS capabilities for a phone number using User Capability Exchange.
658      * <p>
659      * Unlike {@link #requestCapabilities(Collection, Executor, CapabilitiesCallback)}, which caches
660      * the result received from the network for a certain amount of time and uses that cached result
661      * for subsequent requests for RCS capabilities of the same phone number, this API will always
662      * request the RCS capabilities of a contact from the carrier's network.
663      * <p>
664      * Depending on the number of requests, this API may throttled internally as the operations are
665      * queued to be executed by the carrier's network.
666      * <p>
667      * Be sure to check the availability of this feature using
668      * {@link ImsRcsManager#isAvailable(int, int)} and ensuring
669      * {@link
670      * android.telephony.ims.feature.RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or
671      * {@link
672      * android.telephony.ims.feature.RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is
673      * enabled or else this operation will fail with
674      * {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
675      *
676      * @param contactNumber The contact of the capabilities is being requested for.
677      * @param executor The executor that will be used when the request is completed and the
678      * {@link CapabilitiesCallback} is called.
679      * @param c A one-time callback for when the request for capabilities completes or there is
680      * an error processing the request.
681      * @throws ImsException if the subscription associated with this instance of
682      * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
683      * available. This can happen if the ImsService has crashed, for example, or if the subscription
684      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
685      * @hide
686      */
687     @SystemApi
688     @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
689             Manifest.permission.READ_CONTACTS})
requestAvailability(@onNull Uri contactNumber, @NonNull @CallbackExecutor Executor executor, @NonNull CapabilitiesCallback c)690     public void requestAvailability(@NonNull Uri contactNumber,
691             @NonNull @CallbackExecutor Executor executor,
692             @NonNull CapabilitiesCallback c) throws ImsException {
693         if (executor == null) {
694             throw new IllegalArgumentException("Must include a non-null Executor.");
695         }
696         if (contactNumber == null) {
697             throw new IllegalArgumentException("Must include non-null contact number.");
698         }
699         if (c == null) {
700             throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
701         }
702 
703         IImsRcsController imsRcsController = getIImsRcsController();
704         if (imsRcsController == null) {
705             Log.e(TAG, "requestAvailability: IImsRcsController is null");
706             throw new ImsException("Cannot find remote IMS service",
707                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
708         }
709 
710         IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
711             @Override
712             public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
713                 final long callingIdentity = Binder.clearCallingIdentity();
714                 try {
715                     executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
716                 } finally {
717                     restoreCallingIdentity(callingIdentity);
718                 }
719             }
720             @Override
721             public void onComplete(@Nullable SipDetails details) {
722                 final long callingIdentity = Binder.clearCallingIdentity();
723                 try {
724                     executor.execute(() -> c.onComplete(details));
725                 } finally {
726                     restoreCallingIdentity(callingIdentity);
727                 }
728             }
729             @Override
730             public void onError(int errorCode, long retryAfterMilliseconds,
731                     @Nullable SipDetails details) {
732                 final long callingIdentity = Binder.clearCallingIdentity();
733                 try {
734                     executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds, details));
735                 } finally {
736                     restoreCallingIdentity(callingIdentity);
737                 }
738             }
739         };
740 
741         try {
742             imsRcsController.requestAvailability(mSubId, mContext.getOpPackageName(),
743                     mContext.getAttributionTag(), contactNumber, internalCallback);
744         } catch (ServiceSpecificException e) {
745             throw new ImsException(e.toString(), e.errorCode);
746         } catch (RemoteException e) {
747             Log.e(TAG, "Error calling IImsRcsController#requestAvailability", e);
748             throw new ImsException("Remote IMS Service is not available",
749                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
750         }
751     }
752 
753     /**
754      * Gets the last publish result from the UCE service if the device is using an RCS presence
755      * server.
756      * @return The last publish result from the UCE service. If the device is using SIP OPTIONS,
757      * this method will return {@link #PUBLISH_STATE_OK} as well.
758      * @throws ImsException if the subscription associated with this instance of
759      * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
760      * available. This can happen if the ImsService has crashed, for example, or if the subscription
761      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
762      * @hide
763      */
764     @SystemApi
765     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
getUcePublishState()766     public @PublishState int getUcePublishState() throws ImsException {
767         IImsRcsController imsRcsController = getIImsRcsController();
768         if (imsRcsController == null) {
769             Log.e(TAG, "getUcePublishState: IImsRcsController is null");
770             throw new ImsException("Can not find remote IMS service",
771                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
772         }
773 
774         try {
775             return imsRcsController.getUcePublishState(mSubId);
776         } catch (ServiceSpecificException e) {
777             throw new ImsException(e.getMessage(), e.errorCode);
778         } catch (RemoteException e) {
779             Log.e(TAG, "Error calling IImsRcsController#getUcePublishState", e);
780             throw new ImsException("Remote IMS Service is not available",
781                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
782         }
783     }
784 
785     /**
786      * Registers a {@link OnPublishStateChangedListener} with the system, which will provide publish
787      * state updates for the subscription specified in {@link ImsManager@getRcsManager(subid)}.
788      * <p>
789      * Use {@link android.telephony.SubscriptionManager.OnSubscriptionsChangedListener} to listen
790      * to subscription
791      * changed events and call
792      * {@link #removeOnPublishStateChangedListener(OnPublishStateChangedListener)} to clean up.
793      * <p>
794      * The registered {@link OnPublishStateChangedListener} will also receive a callback when it is
795      * registered with the current publish state.
796      *
797      * @param executor The executor the listener callback events should be run on.
798      * @param listener The {@link OnPublishStateChangedListener} to be added.
799      * @throws ImsException if the subscription associated with this callback is valid, but
800      * the {@link ImsService} associated with the subscription is not available. This can happen if
801      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
802      * reason.
803      * @hide
804      */
805     @SystemApi
806     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
addOnPublishStateChangedListener(@onNull @allbackExecutor Executor executor, @NonNull OnPublishStateChangedListener listener)807     public void addOnPublishStateChangedListener(@NonNull @CallbackExecutor Executor executor,
808             @NonNull OnPublishStateChangedListener listener) throws ImsException {
809         if (executor == null) {
810             throw new IllegalArgumentException("Must include a non-null Executor.");
811         }
812         if (listener == null) {
813             throw new IllegalArgumentException(
814                     "Must include a non-null OnPublishStateChangedListener.");
815         }
816 
817         IImsRcsController imsRcsController = getIImsRcsController();
818         if (imsRcsController == null) {
819             Log.e(TAG, "addOnPublishStateChangedListener : IImsRcsController is null");
820             throw new ImsException("Cannot find remote IMS service",
821                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
822         }
823 
824         PublishStateCallbackAdapter stateCallback = addPublishStateCallback(executor, listener);
825         try {
826             imsRcsController.registerUcePublishStateCallback(mSubId, stateCallback.getBinder());
827         } catch (ServiceSpecificException e) {
828             throw new ImsException(e.getMessage(), e.errorCode);
829         } catch (RemoteException e) {
830             Log.e(TAG, "Error calling IImsRcsController#registerUcePublishStateCallback", e);
831             throw new ImsException("Remote IMS Service is not available",
832                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
833         }
834     }
835 
836     /**
837      * Removes an existing {@link OnPublishStateChangedListener}.
838      * <p>
839      * When the subscription associated with this callback is removed
840      * (SIM removed, ESIM swap,etc...), this callback will automatically be removed. If this method
841      * is called for an inactive subscription, it will result in a no-op.
842      *
843      * @param listener The callback to be unregistered.
844      * @throws ImsException if the subscription associated with this callback is valid, but
845      * the {@link ImsService} associated with the subscription is not available. This can happen if
846      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
847      * reason.
848      * @hide
849      */
850     @SystemApi
851     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
removeOnPublishStateChangedListener( @onNull OnPublishStateChangedListener listener)852     public void removeOnPublishStateChangedListener(
853             @NonNull OnPublishStateChangedListener listener) throws ImsException {
854         if (listener == null) {
855             throw new IllegalArgumentException(
856                     "Must include a non-null OnPublishStateChangedListener.");
857         }
858         IImsRcsController imsRcsController = getIImsRcsController();
859         if (imsRcsController == null) {
860             Log.e(TAG, "removeOnPublishStateChangedListener: IImsRcsController is null");
861             throw new ImsException("Cannot find remote IMS service",
862                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
863         }
864 
865         PublishStateCallbackAdapter callback = removePublishStateCallback(listener);
866         if (callback == null) {
867             return;
868         }
869 
870         try {
871             imsRcsController.unregisterUcePublishStateCallback(mSubId, callback.getBinder());
872         } catch (android.os.ServiceSpecificException e) {
873             throw new ImsException(e.getMessage(), e.errorCode);
874         } catch (RemoteException e) {
875             Log.e(TAG, "Error calling IImsRcsController#unregisterUcePublishStateCallback", e);
876             throw new ImsException("Remote IMS Service is not available",
877                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
878         }
879     }
880 
881     /**
882      * The setting for whether or not the user has opted in to the automatic refresh of the RCS
883      * capabilities associated with the contacts in the user's contact address book. By default,
884      * this setting is disabled and must be enabled after the user has seen the opt-in dialog shown
885      * by {@link ImsRcsManager#ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN}.
886      * <p>
887      * If this feature is enabled, the device will periodically share the phone numbers of all of
888      * the contacts in the user's address book with the carrier to refresh the RCS capabilities
889      * cache associated with those contacts as the local cache becomes stale.
890      * <p>
891      * This setting will only enable this feature if
892      * {@link android.telephony.CarrierConfigManager.Ims#KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL} is
893      * also enabled.
894      * <p>
895      * Note: This setting does not affect whether or not the device publishes its service
896      * capabilities if the subscription supports presence publication.
897      *
898      * @return true if the user has opted in for automatic refresh of the RCS capabilities of their
899      * contacts, false otherwise.
900      * @throws ImsException if the subscription associated with this instance of
901      * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
902      * available. This can happen if the ImsService has crashed, for example, or if the subscription
903      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
904      */
905     @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
isUceSettingEnabled()906     public boolean isUceSettingEnabled() throws ImsException {
907         IImsRcsController imsRcsController = getIImsRcsController();
908         if (imsRcsController == null) {
909             Log.e(TAG, "isUceSettingEnabled: IImsRcsController is null");
910             throw new ImsException("Can not find remote IMS service",
911                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
912         }
913         try {
914             // Telephony.SimInfo#IMS_RCS_UCE_ENABLED can also be used to listen to changes to this.
915             return imsRcsController.isUceSettingEnabled(mSubId, mContext.getOpPackageName(),
916                     mContext.getAttributionTag());
917         } catch (RemoteException e) {
918             Log.e(TAG, "Error calling IImsRcsController#isUceSettingEnabled", e);
919             throw new ImsException("Remote IMS Service is not available",
920                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
921         }
922     }
923 
924     /**
925      * Change the user’s setting for whether or not the user has opted in to the automatic
926      * refresh of the RCS capabilities associated with the contacts in the user's contact address
927      * book. By default, this setting is disabled and must be enabled using this method after the
928      * user has seen the opt-in dialog shown by
929      * {@link ImsRcsManager#ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN}.
930      * <p>
931      * If an application wishes to request that the user enable this feature, they must launch an
932      * Activity using the Intent {@link ImsRcsManager#ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN},
933      * which will ask the user if they wish to enable this feature. This setting must only be
934      * enabled after the user has opted-in to this feature.
935      * <p>
936      * This must not affect the
937      * {@link #requestCapabilities(Collection, Executor, CapabilitiesCallback)} or
938      * {@link #requestAvailability(Uri, Executor, CapabilitiesCallback)} API,
939      * as those APIs are still required for per-contact RCS capability queries of phone numbers
940      * required for operations such as placing a Video Telephony call or starting an RCS chat
941      * session.
942      * <p>
943      * This setting will only enable this feature if
944      * {@link android.telephony.CarrierConfigManager.Ims#KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL} is
945      * also enabled.
946      * <p>
947      * Note: This setting does not affect whether or not the device publishes its service
948      * capabilities if the subscription supports presence publication.
949      *
950      * @param isEnabled true if the user has opted in for automatic refresh of the RCS capabilities
951      *                  of their contacts, or false if they have chosen to opt-out. By default this
952      *                  setting is disabled.
953      * @throws ImsException if the subscription associated with this instance of
954      * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
955      * available. This can happen if the ImsService has crashed, for example, or if the subscription
956      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
957      * @hide
958      */
959     @SystemApi
960     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
setUceSettingEnabled(boolean isEnabled)961     public void setUceSettingEnabled(boolean isEnabled) throws ImsException {
962         IImsRcsController imsRcsController = getIImsRcsController();
963         if (imsRcsController == null) {
964             Log.e(TAG, "setUceSettingEnabled: IImsRcsController is null");
965             throw new ImsException("Can not find remote IMS service",
966                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
967         }
968 
969         try {
970             imsRcsController.setUceSettingEnabled(mSubId, isEnabled);
971         } catch (RemoteException e) {
972             Log.e(TAG, "Error calling IImsRcsController#setUceSettingEnabled", e);
973             throw new ImsException("Remote IMS Service is not available",
974                     ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
975         }
976     }
977 
978     /**
979      * Add the {@link OnPublishStateChangedListener} to collection for tracking.
980      * @param executor The executor that will be used when the publish state is changed and the
981      * {@link OnPublishStateChangedListener} is called.
982      * @param listener The {@link OnPublishStateChangedListener} to call the publish state changed.
983      * @return The {@link PublishStateCallbackAdapter} to wrapper the
984      * {@link OnPublishStateChangedListener}
985      */
addPublishStateCallback(@onNull Executor executor, @NonNull OnPublishStateChangedListener listener)986     private PublishStateCallbackAdapter addPublishStateCallback(@NonNull Executor executor,
987             @NonNull OnPublishStateChangedListener listener) {
988         PublishStateCallbackAdapter adapter = new PublishStateCallbackAdapter(executor, listener);
989         synchronized (mPublishStateCallbacks) {
990             mPublishStateCallbacks.put(listener, adapter);
991         }
992         return adapter;
993     }
994 
995     /**
996      * Remove the existing {@link OnPublishStateChangedListener}.
997      * @param listener The {@link OnPublishStateChangedListener} to remove from the collection.
998      * @return The wrapper class {@link PublishStateCallbackAdapter} associated with the
999      * {@link OnPublishStateChangedListener}.
1000      */
removePublishStateCallback( @onNull OnPublishStateChangedListener listener)1001     private PublishStateCallbackAdapter removePublishStateCallback(
1002             @NonNull OnPublishStateChangedListener listener) {
1003         synchronized (mPublishStateCallbacks) {
1004             return mPublishStateCallbacks.remove(listener);
1005         }
1006     }
1007 
getIImsRcsController()1008     private IImsRcsController getIImsRcsController() {
1009         IBinder binder = TelephonyFrameworkInitializer
1010                 .getTelephonyServiceManager()
1011                 .getTelephonyImsServiceRegisterer()
1012                 .get();
1013         return IImsRcsController.Stub.asInterface(binder);
1014     }
1015 }
1016