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