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