blob: 766d71949ffbd873feb658f6430470cec6807050 [file] [log] [blame]
James.cf Linaf3183c2019-10-24 00:59:00 +08001/*
2 * Copyright (C) 2019 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
17package com.android.phone;
18
joonhunshin2c33ed92023-12-12 14:29:23 +000019import static android.content.pm.PackageManager.FEATURE_TELEPHONY_IMS;
20import static android.content.pm.PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION;
21import static android.telephony.TelephonyManager.ENABLE_FEATURE_MAPPING;
22
Brad Ebinger4df7e242021-02-17 23:23:21 +000023import android.Manifest;
joonhunshin2c33ed92023-12-12 14:29:23 +000024import android.annotation.NonNull;
25import android.annotation.Nullable;
Hyunho8ea90f32021-11-16 08:53:02 +000026import android.app.compat.CompatChanges;
27import android.compat.annotation.ChangeId;
28import android.compat.annotation.EnabledAfter;
Brad Ebinger63b6f5a2020-10-27 11:43:35 -070029import android.content.pm.PackageManager;
James.cf Linaf3183c2019-10-24 00:59:00 +080030import android.net.Uri;
James.cf Lincad981c2019-12-10 20:37:56 +080031import android.os.Binder;
Hyunho8ea90f32021-11-16 08:53:02 +000032import android.os.Build;
James.cf Lincad981c2019-12-10 20:37:56 +080033import android.os.RemoteException;
James.cf Lincad981c2019-12-10 20:37:56 +080034import android.os.ServiceSpecificException;
joonhunshinf624b2a2024-04-18 04:42:12 +000035import android.os.SystemProperties;
Brad Ebinger63b6f5a2020-10-27 11:43:35 -070036import android.os.UserHandle;
Brad Ebingerb7a866a2020-01-22 17:51:55 -080037import android.telephony.SubscriptionManager;
Peter Wangc035ce42020-01-08 21:00:22 -080038import android.telephony.TelephonyFrameworkInitializer;
Brad Ebingeraf1e9832020-10-14 10:49:28 -070039import android.telephony.ims.DelegateRequest;
James.cf Lincad981c2019-12-10 20:37:56 +080040import android.telephony.ims.ImsException;
Brad Ebingerd4c5bde2021-02-12 06:18:28 +000041import android.telephony.ims.RcsContactUceCapability;
James.cf Lin99a360d2020-11-04 10:48:37 +080042import android.telephony.ims.RcsUceAdapter.PublishState;
James.cf Lindc2d5422019-12-31 14:40:25 +080043import android.telephony.ims.RegistrationManager;
James.cf Linaf3183c2019-10-24 00:59:00 +080044import android.telephony.ims.aidl.IImsCapabilityCallback;
45import android.telephony.ims.aidl.IImsRcsController;
James.cf Lindc2d5422019-12-31 14:40:25 +080046import android.telephony.ims.aidl.IImsRegistrationCallback;
James.cf Linaf3183c2019-10-24 00:59:00 +080047import android.telephony.ims.aidl.IRcsUceControllerCallback;
James.cf Lincdad3862020-02-25 15:55:03 +080048import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
Brad Ebingeraf1e9832020-10-14 10:49:28 -070049import android.telephony.ims.aidl.ISipDelegate;
50import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
51import android.telephony.ims.aidl.ISipDelegateMessageCallback;
Brad Ebingere3ae65a2020-09-11 12:45:11 -070052import android.telephony.ims.feature.ImsFeature;
James.cf Linaf3183c2019-10-24 00:59:00 +080053import android.telephony.ims.feature.RcsFeature;
James.cf Lincad981c2019-12-10 20:37:56 +080054import android.telephony.ims.stub.ImsRegistrationImplBase;
James.cf Linaf3183c2019-10-24 00:59:00 +080055import android.util.Log;
56
James.cf Lindc2d5422019-12-31 14:40:25 +080057import com.android.ims.ImsManager;
Brad Ebingere3ae65a2020-09-11 12:45:11 -070058import com.android.ims.internal.IImsServiceFeatureCallback;
James.cf Lindc2d5422019-12-31 14:40:25 +080059import com.android.internal.telephony.IIntegerConsumer;
sungcheol ahn3991d2d2022-11-10 02:10:49 +000060import com.android.internal.telephony.ISipDialogStateCallback;
James.cf Lincad981c2019-12-10 20:37:56 +080061import com.android.internal.telephony.Phone;
Brad Ebinger8b79edc2020-02-27 19:13:24 -080062import com.android.internal.telephony.TelephonyPermissions;
joonhunshin2c33ed92023-12-12 14:29:23 +000063import com.android.internal.telephony.flags.FeatureFlags;
Brad Ebingere3ae65a2020-09-11 12:45:11 -070064import com.android.internal.telephony.ims.ImsResolver;
Brad Ebingera68a4972020-01-30 17:31:23 -080065import com.android.services.telephony.rcs.RcsFeatureController;
Brad Ebingerb989c7c2020-09-23 17:03:48 -070066import com.android.services.telephony.rcs.SipTransportController;
James.cf Linc9f35a42020-01-15 02:35:22 +080067import com.android.services.telephony.rcs.TelephonyRcsService;
James.cf Lin99a360d2020-11-04 10:48:37 +080068import com.android.services.telephony.rcs.UceControllerManager;
James.cf Lincad981c2019-12-10 20:37:56 +080069
James.cf Linaf3183c2019-10-24 00:59:00 +080070import java.util.List;
Brad Ebingerd4c5bde2021-02-12 06:18:28 +000071import java.util.Set;
James.cf Linaf3183c2019-10-24 00:59:00 +080072
73/**
74 * Implementation of the IImsRcsController interface.
75 */
76public class ImsRcsController extends IImsRcsController.Stub {
77 private static final String TAG = "ImsRcsController";
78
79 /** The singleton instance. */
80 private static ImsRcsController sInstance;
81
82 private PhoneGlobals mApp;
James.cf Linc9f35a42020-01-15 02:35:22 +080083 private TelephonyRcsService mRcsService;
Brad Ebingere3ae65a2020-09-11 12:45:11 -070084 private ImsResolver mImsResolver;
joonhunshin2c33ed92023-12-12 14:29:23 +000085 private FeatureFlags mFeatureFlags;
86 private PackageManager mPackageManager;
Brad Ebinger49a72b42021-01-29 00:55:24 +000087 // set by shell cmd phone src set-device-enabled true/false
88 private Boolean mSingleRegistrationOverride;
joonhunshinf624b2a2024-04-18 04:42:12 +000089 private final int mVendorApiLevel;
James.cf Linaf3183c2019-10-24 00:59:00 +080090
91 /**
Hyunho8ea90f32021-11-16 08:53:02 +000092 * For apps targeting Android T and above, support the publishing state on APIs, such as
93 * {@code RcsUceAdapter#PUBLISH_STATE_PUBLISHING}
94 * @hide
95 */
96 @ChangeId
97 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
98 public static final long SUPPORT_PUBLISHING_STATE = 202894742;
99
100 /**
James.cf Linaf3183c2019-10-24 00:59:00 +0800101 * Initialize the singleton ImsRcsController instance.
102 * This is only done once, at startup, from PhoneApp.onCreate().
103 */
joonhunshin2c33ed92023-12-12 14:29:23 +0000104 static ImsRcsController init(PhoneGlobals app, FeatureFlags featureFlags) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800105 synchronized (ImsRcsController.class) {
106 if (sInstance == null) {
joonhunshin2c33ed92023-12-12 14:29:23 +0000107 sInstance = new ImsRcsController(app, featureFlags);
James.cf Linaf3183c2019-10-24 00:59:00 +0800108 } else {
109 Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
110 }
111 return sInstance;
112 }
113 }
114
115 /** Private constructor; @see init() */
joonhunshin2c33ed92023-12-12 14:29:23 +0000116 private ImsRcsController(PhoneGlobals app, FeatureFlags featureFlags) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800117 Log.i(TAG, "ImsRcsController");
118 mApp = app;
joonhunshin2c33ed92023-12-12 14:29:23 +0000119 mFeatureFlags = featureFlags;
120 mPackageManager = mApp.getPackageManager();
Peter Wangc035ce42020-01-08 21:00:22 -0800121 TelephonyFrameworkInitializer
122 .getTelephonyServiceManager().getTelephonyImsServiceRegisterer().register(this);
Brad Ebingerd1947d82021-05-17 20:54:49 +0000123 mImsResolver = ImsResolver.getInstance();
joonhunshinf624b2a2024-04-18 04:42:12 +0000124 mVendorApiLevel = SystemProperties.getInt(
125 "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
James.cf Linaf3183c2019-10-24 00:59:00 +0800126 }
127
James.cf Lincad981c2019-12-10 20:37:56 +0800128 /**
Brad Ebingera68a4972020-01-30 17:31:23 -0800129 * Register a {@link RegistrationManager.RegistrationCallback} to receive IMS network
130 * registration state.
James.cf Lindc2d5422019-12-31 14:40:25 +0800131 */
132 @Override
Brad Ebingera68a4972020-01-30 17:31:23 -0800133 public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
Nathan Harold75a9ff12021-04-06 11:26:02 -0700134 TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
James.cf Linf020d162021-01-31 22:15:52 +0800135 mApp, subId, "registerImsRegistrationCallback");
joonhunshin2c33ed92023-12-12 14:29:23 +0000136
137 enforceTelephonyFeatureWithException(getCurrentPackageName(),
138 FEATURE_TELEPHONY_IMS, "registerImsRegistrationCallback");
139
James.cf Lindc2d5422019-12-31 14:40:25 +0800140 final long token = Binder.clearCallingIdentity();
141 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800142 getRcsFeatureController(subId).registerImsRegistrationCallback(subId, callback);
143 } catch (ImsException e) {
James.cf Lindc2d5422019-12-31 14:40:25 +0800144 Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage());
145 throw new ServiceSpecificException(e.getCode());
146 } finally {
147 Binder.restoreCallingIdentity(token);
148 }
149 }
150
151 /**
Brad Ebingera68a4972020-01-30 17:31:23 -0800152 * Removes an existing {@link RegistrationManager.RegistrationCallback}.
James.cf Lindc2d5422019-12-31 14:40:25 +0800153 */
154 @Override
155 public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
Nathan Harold75a9ff12021-04-06 11:26:02 -0700156 TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
James.cf Linf020d162021-01-31 22:15:52 +0800157 mApp, subId, "unregisterImsRegistrationCallback");
joonhunshin2c33ed92023-12-12 14:29:23 +0000158
159 enforceTelephonyFeatureWithException(getCurrentPackageName(),
160 FEATURE_TELEPHONY_IMS, "unregisterImsRegistrationCallback");
161
James.cf Lindc2d5422019-12-31 14:40:25 +0800162 final long token = Binder.clearCallingIdentity();
163 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800164 getRcsFeatureController(subId).unregisterImsRegistrationCallback(subId, callback);
James.cf Lindc2d5422019-12-31 14:40:25 +0800165 } catch (ServiceSpecificException e) {
166 Log.e(TAG, "unregisterImsRegistrationCallback: error=" + e.errorCode);
167 } finally {
168 Binder.restoreCallingIdentity(token);
169 }
170 }
171
172 /**
173 * Get the IMS service registration state for the RcsFeature associated with this sub id.
174 */
175 @Override
176 public void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer) {
Nathan Harold75a9ff12021-04-06 11:26:02 -0700177 TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
James.cf Linf020d162021-01-31 22:15:52 +0800178 mApp, subId, "getImsRcsRegistrationState");
joonhunshin2c33ed92023-12-12 14:29:23 +0000179
180 enforceTelephonyFeatureWithException(getCurrentPackageName(),
181 FEATURE_TELEPHONY_IMS, "getImsRcsRegistrationState");
182
James.cf Lindc2d5422019-12-31 14:40:25 +0800183 final long token = Binder.clearCallingIdentity();
184 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800185 getRcsFeatureController(subId).getRegistrationState(regState -> {
James.cf Lindc2d5422019-12-31 14:40:25 +0800186 try {
187 consumer.accept((regState == null)
188 ? RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED : regState);
189 } catch (RemoteException e) {
190 Log.w(TAG, "getImsRcsRegistrationState: callback is not available.");
191 }
192 });
193 } finally {
194 Binder.restoreCallingIdentity(token);
195 }
196 }
197
198 /**
199 * Gets the Transport Type associated with the current IMS RCS registration.
200 */
201 @Override
202 public void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer) {
Nathan Harold75a9ff12021-04-06 11:26:02 -0700203 TelephonyPermissions.enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
James.cf Linf020d162021-01-31 22:15:52 +0800204 mApp, subId, "getImsRcsRegistrationTransportType");
joonhunshin2c33ed92023-12-12 14:29:23 +0000205
206 enforceTelephonyFeatureWithException(getCurrentPackageName(),
207 FEATURE_TELEPHONY_IMS, "getImsRcsRegistrationTransportType");
208
James.cf Lindc2d5422019-12-31 14:40:25 +0800209 final long token = Binder.clearCallingIdentity();
210 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800211 getRcsFeatureController(subId).getRegistrationTech(regTech -> {
James.cf Lindc2d5422019-12-31 14:40:25 +0800212 // Convert registration tech from ImsRegistrationImplBase -> RegistrationManager
213 int regTechConverted = (regTech == null)
214 ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : regTech;
215 regTechConverted = RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(
216 regTechConverted);
217 try {
218 consumer.accept(regTechConverted);
219 } catch (RemoteException e) {
220 Log.w(TAG, "getImsRcsRegistrationTransportType: callback is not available.");
221 }
222 });
223 } finally {
224 Binder.restoreCallingIdentity(token);
225 }
226 }
227
228 /**
James.cf Lincad981c2019-12-10 20:37:56 +0800229 * Register a capability callback which will provide RCS availability updates for the
230 * subscription specified.
231 *
232 * @param subId the subscription ID
233 * @param callback The ImsCapabilityCallback to be registered.
234 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800235 @Override
Brad Ebingera68a4972020-01-30 17:31:23 -0800236 public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800237 enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
joonhunshin2c33ed92023-12-12 14:29:23 +0000238
239 enforceTelephonyFeatureWithException(getCurrentPackageName(),
240 FEATURE_TELEPHONY_IMS, "registerRcsAvailabilityCallback");
241
James.cf Lincad981c2019-12-10 20:37:56 +0800242 final long token = Binder.clearCallingIdentity();
243 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800244 getRcsFeatureController(subId).registerRcsAvailabilityCallback(subId, callback);
245 } catch (ImsException e) {
James.cf Lincad981c2019-12-10 20:37:56 +0800246 Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage());
247 throw new ServiceSpecificException(e.getCode());
248 } finally {
249 Binder.restoreCallingIdentity(token);
250 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800251 }
252
James.cf Lincad981c2019-12-10 20:37:56 +0800253 /**
254 * Remove the registered capability callback.
255 *
256 * @param subId the subscription ID
257 * @param callback The ImsCapabilityCallback to be removed.
258 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800259 @Override
James.cf Lincad981c2019-12-10 20:37:56 +0800260 public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800261 enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback");
joonhunshin2c33ed92023-12-12 14:29:23 +0000262
263 enforceTelephonyFeatureWithException(getCurrentPackageName(),
264 FEATURE_TELEPHONY_IMS, "unregisterRcsAvailabilityCallback");
265
James.cf Lincad981c2019-12-10 20:37:56 +0800266 final long token = Binder.clearCallingIdentity();
267 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800268 getRcsFeatureController(subId).unregisterRcsAvailabilityCallback(subId, callback);
Brad Ebinger919631e2021-06-02 17:46:35 -0700269 } catch (ServiceSpecificException e) {
270 Log.e(TAG, "unregisterRcsAvailabilityCallback: error=" + e.errorCode);
James.cf Lincad981c2019-12-10 20:37:56 +0800271 } finally {
272 Binder.restoreCallingIdentity(token);
273 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800274 }
275
James.cf Lincad981c2019-12-10 20:37:56 +0800276 /**
277 * Query for the capability of an IMS RCS service
278 *
279 * @param subId the subscription ID
280 * @param capability the RCS capability to query.
James.cf Linf020d162021-01-31 22:15:52 +0800281 * @param radioTech the radio technology type that we are querying.
James.cf Lincad981c2019-12-10 20:37:56 +0800282 * @return true if the RCS capability is capable for this subscription, false otherwise.
283 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800284 @Override
285 public boolean isCapable(int subId,
James.cf Lincad981c2019-12-10 20:37:56 +0800286 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
287 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800288 enforceReadPrivilegedPermission("isCapable");
joonhunshin2c33ed92023-12-12 14:29:23 +0000289
290 enforceTelephonyFeatureWithException(getCurrentPackageName(),
291 FEATURE_TELEPHONY_IMS, "isCapable");
292
James.cf Lincad981c2019-12-10 20:37:56 +0800293 final long token = Binder.clearCallingIdentity();
294 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800295 return getRcsFeatureController(subId).isCapable(capability, radioTech);
296 } catch (ImsException e) {
James.cf Lincad981c2019-12-10 20:37:56 +0800297 Log.e(TAG, "isCapable: sudId=" + subId
298 + ", capability=" + capability + ", " + e.getMessage());
Brad Ebingere3885b22022-02-16 13:18:59 -0800299 throw new ServiceSpecificException(e.getCode(), e.getMessage());
James.cf Lincad981c2019-12-10 20:37:56 +0800300 } finally {
301 Binder.restoreCallingIdentity(token);
302 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800303 }
304
James.cf Lincad981c2019-12-10 20:37:56 +0800305 /**
306 * Query the availability of an IMS RCS capability.
307 *
308 * @param subId the subscription ID
309 * @param capability the RCS capability to query.
310 * @return true if the RCS capability is currently available for the associated subscription,
James.cf Linf020d162021-01-31 22:15:52 +0800311 * @param radioTech the radio technology type that we are querying.
James.cf Lincad981c2019-12-10 20:37:56 +0800312 * false otherwise.
313 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800314 @Override
315 public boolean isAvailable(int subId,
James.cf Linf020d162021-01-31 22:15:52 +0800316 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
317 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800318 enforceReadPrivilegedPermission("isAvailable");
joonhunshin2c33ed92023-12-12 14:29:23 +0000319
320 enforceTelephonyFeatureWithException(getCurrentPackageName(),
321 FEATURE_TELEPHONY_IMS, "isAvailable");
322
James.cf Lincad981c2019-12-10 20:37:56 +0800323 final long token = Binder.clearCallingIdentity();
324 try {
James.cf Linf020d162021-01-31 22:15:52 +0800325 return getRcsFeatureController(subId).isAvailable(capability, radioTech);
Brad Ebingera68a4972020-01-30 17:31:23 -0800326 } catch (ImsException e) {
James.cf Lincad981c2019-12-10 20:37:56 +0800327 Log.e(TAG, "isAvailable: sudId=" + subId
328 + ", capability=" + capability + ", " + e.getMessage());
Brad Ebingere3885b22022-02-16 13:18:59 -0800329 throw new ServiceSpecificException(e.getCode(), e.getMessage());
James.cf Lincad981c2019-12-10 20:37:56 +0800330 } finally {
331 Binder.restoreCallingIdentity(token);
332 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800333 }
334
335 @Override
Brad Ebinger8b79edc2020-02-27 19:13:24 -0800336 public void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
337 List<Uri> contactNumbers, IRcsUceControllerCallback c) {
James.cf Lin051dd252021-01-21 03:30:54 +0800338 enforceAccessUserCapabilityExchangePermission("requestCapabilities");
339 enforceReadContactsPermission("requestCapabilities");
joonhunshin2c33ed92023-12-12 14:29:23 +0000340
341 enforceTelephonyFeatureWithException(callingPackage,
342 FEATURE_TELEPHONY_IMS, "requestCapabilities");
343
Brad Ebingera68a4972020-01-30 17:31:23 -0800344 final long token = Binder.clearCallingIdentity();
345 try {
James.cf Lin99a360d2020-11-04 10:48:37 +0800346 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
347 UceControllerManager.class);
348 if (uceCtrlManager == null) {
Brad Ebingera68a4972020-01-30 17:31:23 -0800349 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
350 "This subscription does not support UCE.");
351 }
James.cf Lin99a360d2020-11-04 10:48:37 +0800352 uceCtrlManager.requestCapabilities(contactNumbers, c);
353 } catch (ImsException e) {
354 throw new ServiceSpecificException(e.getCode(), e.getMessage());
Brad Ebingera68a4972020-01-30 17:31:23 -0800355 } finally {
356 Binder.restoreCallingIdentity(token);
Brad Ebinger1aa94992020-01-22 14:17:23 -0800357 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800358 }
359
360 @Override
James.cf Linbcdf8b32021-01-14 16:44:13 +0800361 public void requestAvailability(int subId, String callingPackage,
James.cf Lin64e91212020-10-30 01:09:52 +0800362 String callingFeatureId, Uri contactNumber, IRcsUceControllerCallback c) {
James.cf Lin051dd252021-01-21 03:30:54 +0800363 enforceAccessUserCapabilityExchangePermission("requestAvailability");
364 enforceReadContactsPermission("requestAvailability");
joonhunshin2c33ed92023-12-12 14:29:23 +0000365
366 enforceTelephonyFeatureWithException(callingPackage,
367 FEATURE_TELEPHONY_IMS, "requestAvailability");
368
Brad Ebingera68a4972020-01-30 17:31:23 -0800369 final long token = Binder.clearCallingIdentity();
370 try {
James.cf Lin99a360d2020-11-04 10:48:37 +0800371 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
372 UceControllerManager.class);
373 if (uceCtrlManager == null) {
Brad Ebingera68a4972020-01-30 17:31:23 -0800374 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
375 "This subscription does not support UCE.");
376 }
James.cf Lin99a360d2020-11-04 10:48:37 +0800377 uceCtrlManager.requestNetworkAvailability(contactNumber, c);
378 } catch (ImsException e) {
379 throw new ServiceSpecificException(e.getCode(), e.getMessage());
380 } finally {
381 Binder.restoreCallingIdentity(token);
382 }
383 }
384
385 @Override
386 public @PublishState int getUcePublishState(int subId) {
387 enforceReadPrivilegedPermission("getUcePublishState");
joonhunshin2c33ed92023-12-12 14:29:23 +0000388
389 enforceTelephonyFeatureWithException(getCurrentPackageName(),
390 FEATURE_TELEPHONY_IMS, "getUcePublishState");
391
Hyunho8ea90f32021-11-16 08:53:02 +0000392 final int uid = Binder.getCallingUid();
James.cf Lin99a360d2020-11-04 10:48:37 +0800393 final long token = Binder.clearCallingIdentity();
Hyunho8ea90f32021-11-16 08:53:02 +0000394 boolean isSupportPublishingState = false;
James.cf Lin99a360d2020-11-04 10:48:37 +0800395 try {
396 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
397 UceControllerManager.class);
398 if (uceCtrlManager == null) {
399 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
400 "This subscription does not support UCE.");
401 }
Hyunho8ea90f32021-11-16 08:53:02 +0000402 if (CompatChanges.isChangeEnabled(SUPPORT_PUBLISHING_STATE, uid)) {
403 isSupportPublishingState = true;
404 }
405 return uceCtrlManager.getUcePublishState(isSupportPublishingState);
James.cf Lin99a360d2020-11-04 10:48:37 +0800406 } catch (ImsException e) {
407 throw new ServiceSpecificException(e.getCode(), e.getMessage());
408 } finally {
409 Binder.restoreCallingIdentity(token);
410 }
411 }
412
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000413 /**
414 * Add new feature tags to the Set used to calculate the capabilities in PUBLISH.
415 */
416 // Used for SHELL command only right now.
417 public RcsContactUceCapability addUceRegistrationOverrideShell(int subId,
418 Set<String> featureTags) throws ImsException {
419 // Permission check happening in PhoneInterfaceManager.
Brad Ebinger919631e2021-06-02 17:46:35 -0700420 try {
421 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
422 UceControllerManager.class);
423 if (uceCtrlManager == null) {
424 return null;
425 }
426 return uceCtrlManager.addUceRegistrationOverride(featureTags);
427 } catch (ServiceSpecificException e) {
428 throw new ImsException(e.getMessage(), e.errorCode);
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000429 }
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000430 }
431
432 /**
433 * Remove existing feature tags to the Set used to calculate the capabilities in PUBLISH.
434 */
435 // Used for SHELL command only right now.
436 public RcsContactUceCapability removeUceRegistrationOverrideShell(int subId,
437 Set<String> featureTags) throws ImsException {
438 // Permission check happening in PhoneInterfaceManager.
Brad Ebinger919631e2021-06-02 17:46:35 -0700439 try {
440 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
441 UceControllerManager.class);
442 if (uceCtrlManager == null) {
443 return null;
444 }
445 return uceCtrlManager.removeUceRegistrationOverride(featureTags);
446 } catch (ServiceSpecificException e) {
447 throw new ImsException(e.getMessage(), e.errorCode);
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000448 }
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000449 }
450
451 /**
452 * Clear all overrides in the Set used to calculate the capabilities in PUBLISH.
453 */
454 // Used for SHELL command only right now.
455 public RcsContactUceCapability clearUceRegistrationOverrideShell(int subId)
456 throws ImsException {
Brad Ebinger919631e2021-06-02 17:46:35 -0700457 try {
458 // Permission check happening in PhoneInterfaceManager.
459 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
460 UceControllerManager.class);
461 if (uceCtrlManager == null) {
462 return null;
463 }
464 return uceCtrlManager.clearUceRegistrationOverride();
465 } catch (ServiceSpecificException e) {
466 throw new ImsException(e.getMessage(), e.errorCode);
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000467 }
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000468 }
469
470 /**
471 * @return current RcsContactUceCapability instance that will be used for PUBLISH.
472 */
473 // Used for SHELL command only right now.
474 public RcsContactUceCapability getLatestRcsContactUceCapabilityShell(int subId)
475 throws ImsException {
Brad Ebinger919631e2021-06-02 17:46:35 -0700476 try {
477 // Permission check happening in PhoneInterfaceManager.
478 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
479 UceControllerManager.class);
480 if (uceCtrlManager == null) {
481 return null;
482 }
483 return uceCtrlManager.getLatestRcsContactUceCapability();
484 } catch (ServiceSpecificException e) {
485 throw new ImsException(e.getMessage(), e.errorCode);
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000486 }
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000487 }
488
489 /**
490 * @return the PIDf XML used in the last PUBLISH procedure or "none" if the device is not
491 * published. Returns {@code null} if the operation failed due to an error.
492 */
493 // Used for SHELL command only right now.
494 public String getLastUcePidfXmlShell(int subId) throws ImsException {
Brad Ebinger919631e2021-06-02 17:46:35 -0700495 try {
496 // Permission check happening in PhoneInterfaceManager.
497 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
498 UceControllerManager.class);
499 if (uceCtrlManager == null) {
500 return null;
501 }
502 String pidfXml = uceCtrlManager.getLastPidfXml();
503 return pidfXml == null ? "none" : pidfXml;
504 } catch (ServiceSpecificException e) {
505 throw new ImsException(e.getMessage(), e.errorCode);
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000506 }
Brad Ebingerd4c5bde2021-02-12 06:18:28 +0000507 }
508
James.cf Line8713a42021-04-29 16:04:26 +0800509 /**
510 * Remove UCE requests cannot be sent to the network status.
511 * @return true if this command is successful.
512 */
513 // Used for SHELL command only right now.
514 public boolean removeUceRequestDisallowedStatus(int subId) throws ImsException {
Brad Ebinger919631e2021-06-02 17:46:35 -0700515 try {
James.cf Linc6b449f2021-06-05 01:11:15 +0800516 UceControllerManager uceCtrlManager = getRcsFeatureController(subId, true).getFeature(
Brad Ebinger919631e2021-06-02 17:46:35 -0700517 UceControllerManager.class);
518 if (uceCtrlManager == null) {
519 return false;
520 }
521 return uceCtrlManager.removeUceRequestDisallowedStatus();
522 } catch (ServiceSpecificException e) {
523 throw new ImsException(e.getMessage(), e.errorCode);
James.cf Line8713a42021-04-29 16:04:26 +0800524 }
James.cf Line8713a42021-04-29 16:04:26 +0800525 }
526
James.cf Lin0fc71b02021-05-25 01:37:38 +0800527 /**
528 * Set the timeout for contact capabilities request.
529 */
530 // Used for SHELL command only right now.
531 public boolean setCapabilitiesRequestTimeout(int subId, long timeoutAfter) throws ImsException {
Brad Ebinger919631e2021-06-02 17:46:35 -0700532 try {
James.cf Linc6b449f2021-06-05 01:11:15 +0800533 UceControllerManager uceCtrlManager = getRcsFeatureController(subId, true).getFeature(
Brad Ebinger919631e2021-06-02 17:46:35 -0700534 UceControllerManager.class);
535 if (uceCtrlManager == null) {
536 return false;
537 }
538 return uceCtrlManager.setCapabilitiesRequestTimeout(timeoutAfter);
539 } catch (ServiceSpecificException e) {
540 throw new ImsException(e.getMessage(), e.errorCode);
James.cf Lin0fc71b02021-05-25 01:37:38 +0800541 }
James.cf Lin0fc71b02021-05-25 01:37:38 +0800542 }
543
James.cf Lin99a360d2020-11-04 10:48:37 +0800544 @Override
545 public void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
546 enforceReadPrivilegedPermission("registerUcePublishStateCallback");
joonhunshin2c33ed92023-12-12 14:29:23 +0000547
548 enforceTelephonyFeatureWithException(getCurrentPackageName(),
549 FEATURE_TELEPHONY_IMS, "registerUcePublishStateCallback");
550
Hyunho8ea90f32021-11-16 08:53:02 +0000551 final int uid = Binder.getCallingUid();
James.cf Lin99a360d2020-11-04 10:48:37 +0800552 final long token = Binder.clearCallingIdentity();
Hyunho8ea90f32021-11-16 08:53:02 +0000553 boolean isSupportPublishingState = false;
James.cf Lin99a360d2020-11-04 10:48:37 +0800554 try {
555 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
556 UceControllerManager.class);
557 if (uceCtrlManager == null) {
558 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
559 "This subscription does not support UCE.");
560 }
Hyunho8ea90f32021-11-16 08:53:02 +0000561
562 if (CompatChanges.isChangeEnabled(SUPPORT_PUBLISHING_STATE, uid)) {
563 isSupportPublishingState = true;
564 }
565 uceCtrlManager.registerPublishStateCallback(c, isSupportPublishingState);
James.cf Lin99a360d2020-11-04 10:48:37 +0800566 } catch (ImsException e) {
567 throw new ServiceSpecificException(e.getCode(), e.getMessage());
568 } finally {
569 Binder.restoreCallingIdentity(token);
570 }
571 }
572
573 @Override
574 public void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
575 enforceReadPrivilegedPermission("unregisterUcePublishStateCallback");
joonhunshin2c33ed92023-12-12 14:29:23 +0000576
577 enforceTelephonyFeatureWithException(getCurrentPackageName(),
578 FEATURE_TELEPHONY_IMS, "unregisterUcePublishStateCallback");
579
James.cf Lin99a360d2020-11-04 10:48:37 +0800580 final long token = Binder.clearCallingIdentity();
581 try {
582 UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
583 UceControllerManager.class);
584 if (uceCtrlManager == null) {
585 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
586 "This subscription does not support UCE.");
587 }
588 uceCtrlManager.unregisterPublishStateCallback(c);
Brad Ebinger919631e2021-06-02 17:46:35 -0700589 } catch (ServiceSpecificException e) {
590 Log.e(TAG, "unregisterUcePublishStateCallback: error=" + e.errorCode);
Brad Ebingera68a4972020-01-30 17:31:23 -0800591 } finally {
592 Binder.restoreCallingIdentity(token);
Brad Ebinger1aa94992020-01-22 14:17:23 -0800593 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800594 }
595
596 @Override
Brad Ebinger8b79edc2020-02-27 19:13:24 -0800597 public boolean isUceSettingEnabled(int subId, String callingPackage, String callingFeatureId) {
598 if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
599 mApp, subId, callingPackage, callingFeatureId, "isUceSettingEnabled")) {
600 Log.w(TAG, "isUceSettingEnabled: READ_PHONE_STATE app op disabled when accessing "
601 + "isUceSettingEnabled");
602 return false;
603 }
joonhunshin2c33ed92023-12-12 14:29:23 +0000604
605 enforceTelephonyFeatureWithException(callingPackage,
606 FEATURE_TELEPHONY_IMS, "isUceSettingEnabled");
607
Brad Ebinger8b79edc2020-02-27 19:13:24 -0800608 final long token = Binder.clearCallingIdentity();
609 try {
610 return SubscriptionManager.getBooleanSubscriptionProperty(subId,
611 SubscriptionManager.IMS_RCS_UCE_ENABLED, false /*defaultValue*/, mApp);
612 } finally {
613 Binder.restoreCallingIdentity(token);
614 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800615 }
616
617 @Override
618 public void setUceSettingEnabled(int subId, boolean isEnabled) {
619 enforceModifyPermission();
joonhunshin2c33ed92023-12-12 14:29:23 +0000620
621 enforceTelephonyFeatureWithException(getCurrentPackageName(),
622 FEATURE_TELEPHONY_IMS, "setUceSettingEnabled");
623
Brad Ebinger8b79edc2020-02-27 19:13:24 -0800624 final long token = Binder.clearCallingIdentity();
625 try {
626 SubscriptionManager.setSubscriptionProperty(subId,
627 SubscriptionManager.IMS_RCS_UCE_ENABLED, (isEnabled ? "1" : "0"));
628 } finally {
629 Binder.restoreCallingIdentity(token);
630 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800631 }
632
Brad Ebingerb989c7c2020-09-23 17:03:48 -0700633 @Override
634 public boolean isSipDelegateSupported(int subId) {
Brad Ebinger4df7e242021-02-17 23:23:21 +0000635 TelephonyPermissions.enforceAnyPermissionGranted(mApp, Binder.getCallingUid(),
636 "isSipDelegateSupported",
637 Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION,
638 Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
Brad Ebinger49a72b42021-01-29 00:55:24 +0000639 if (!isImsSingleRegistrationSupportedOnDevice()) {
640 return false;
641 }
Brad Ebingerb989c7c2020-09-23 17:03:48 -0700642 final long token = Binder.clearCallingIdentity();
643 try {
644 SipTransportController transport = getRcsFeatureController(subId).getFeature(
645 SipTransportController.class);
646 if (transport == null) {
647 return false;
648 }
649 return transport.isSupported(subId);
650 } catch (ImsException e) {
651 throw new ServiceSpecificException(e.getCode(), e.getMessage());
652 } catch (ServiceSpecificException e) {
653 if (e.errorCode == ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
654 return false;
655 }
656 throw e;
657 } finally {
658 Binder.restoreCallingIdentity(token);
659 }
660 }
661
Brad Ebingeraf1e9832020-10-14 10:49:28 -0700662 @Override
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700663 public void createSipDelegate(int subId, DelegateRequest request, String packageName,
Brad Ebingeraf1e9832020-10-14 10:49:28 -0700664 ISipDelegateConnectionStateCallback delegateState,
665 ISipDelegateMessageCallback delegateMessage) {
Brad Ebinger4df7e242021-02-17 23:23:21 +0000666 enforceImsSingleRegistrationPermission("createSipDelegate");
Brad Ebinger49a72b42021-01-29 00:55:24 +0000667 if (!isImsSingleRegistrationSupportedOnDevice()) {
668 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
669 "SipDelegate creation is only supported for devices supporting IMS single "
670 + "registration");
671 }
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700672 if (!UserHandle.getUserHandleForUid(Binder.getCallingUid()).isSystem()) {
673 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
674 "SipDelegate creation is only available to primary user.");
675 }
676 try {
677 int remoteUid = mApp.getPackageManager().getPackageUid(packageName, 0 /*flags*/);
678 if (Binder.getCallingUid() != remoteUid) {
679 throw new SecurityException("passed in packageName does not match the caller");
680 }
681 } catch (PackageManager.NameNotFoundException e) {
682 throw new SecurityException("Passed in PackageName can not be found on device");
683 }
Brad Ebingeraf1e9832020-10-14 10:49:28 -0700684
Jinyoung Jeongca77e1c2021-10-21 04:34:46 +0000685 final int uid = Binder.getCallingUid();
Brad Ebingeraf1e9832020-10-14 10:49:28 -0700686 final long identity = Binder.clearCallingIdentity();
687 SipTransportController transport = getRcsFeatureController(subId).getFeature(
688 SipTransportController.class);
689 if (transport == null) {
690 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
691 "This subscription does not support the creation of SIP delegates");
692 }
693 try {
Jinyoung Jeongca77e1c2021-10-21 04:34:46 +0000694 transport.createSipDelegate(subId, uid, request, packageName, delegateState,
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700695 delegateMessage);
Brad Ebingeraf1e9832020-10-14 10:49:28 -0700696 } catch (ImsException e) {
697 throw new ServiceSpecificException(e.getCode(), e.getMessage());
698 } finally {
699 Binder.restoreCallingIdentity(identity);
700 }
701 }
702
703 @Override
704 public void destroySipDelegate(int subId, ISipDelegate connection, int reason) {
Brad Ebinger652411e2021-06-30 09:30:35 -0700705 // Do not check permissions here - the caller needs to have a connection already from the
706 // create method to call this method.
707 if (connection == null) {
708 return;
709 }
Brad Ebingeraf1e9832020-10-14 10:49:28 -0700710 final long identity = Binder.clearCallingIdentity();
711 try {
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700712 SipTransportController transport = getRcsFeatureController(subId).getFeature(
713 SipTransportController.class);
714 if (transport == null) {
715 return;
716 }
717 transport.destroySipDelegate(subId, connection, reason);
Brad Ebinger919631e2021-06-02 17:46:35 -0700718 } catch (ServiceSpecificException e) {
719 Log.e(TAG, "destroySipDelegate: error=" + e.errorCode);
Brad Ebingeraf1e9832020-10-14 10:49:28 -0700720 } finally {
721 Binder.restoreCallingIdentity(identity);
722 }
723 }
724
Brad Ebinger36221382020-12-09 00:33:39 +0000725 @Override
726 public void triggerNetworkRegistration(int subId, ISipDelegate connection, int sipCode,
727 String sipReason) {
Brad Ebinger4df7e242021-02-17 23:23:21 +0000728 enforceImsSingleRegistrationPermission("triggerNetworkRegistration");
Brad Ebinger36221382020-12-09 00:33:39 +0000729
730 final long identity = Binder.clearCallingIdentity();
731 try {
732 SipTransportController transport = getRcsFeatureController(subId).getFeature(
733 SipTransportController.class);
734 if (transport == null) {
735 return;
736 }
737 transport.triggerFullNetworkRegistration(subId, connection, sipCode, sipReason);
Brad Ebinger919631e2021-06-02 17:46:35 -0700738 } catch (ServiceSpecificException e) {
739 Log.e(TAG, "triggerNetworkRegistration: error=" + e.errorCode);
Brad Ebinger36221382020-12-09 00:33:39 +0000740 } finally {
741 Binder.restoreCallingIdentity(identity);
742 }
743 }
744
James.cf Linaf3183c2019-10-24 00:59:00 +0800745 /**
sungcheol ahn3991d2d2022-11-10 02:10:49 +0000746 * Register a state of Sip Dialog callback
747 */
748 @Override
749 public void registerSipDialogStateCallback(int subId, ISipDialogStateCallback cb) {
750 enforceReadPrivilegedPermission("registerSipDialogStateCallback");
751 if (cb == null) {
752 throw new IllegalArgumentException("SipDialogStateCallback is null");
753 }
754 final long identity = Binder.clearCallingIdentity();
755 if (!SubscriptionManager.isValidSubscriptionId(subId)) {
756 throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
757 }
joonhunshin2c33ed92023-12-12 14:29:23 +0000758
759 enforceTelephonyFeatureWithException(getCurrentPackageName(),
760 FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION, "registerSipDialogStateCallback");
761
sungcheol ahn3991d2d2022-11-10 02:10:49 +0000762 try {
763 SipTransportController transport = getRcsFeatureController(subId).getFeature(
764 SipTransportController.class);
765 if (transport == null) {
766 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
767 "This transport does not support the registerSipDialogStateCallback"
768 + " of SIP delegates");
769 }
770 transport.addCallbackForSipDialogState(subId, cb);
771 } finally {
772 Binder.restoreCallingIdentity(identity);
773 }
774 }
775
776 /**
777 * Unregister a state of Sip Dialog callback
778 */
779 @Override
780 public void unregisterSipDialogStateCallback(int subId, ISipDialogStateCallback cb) {
781 enforceReadPrivilegedPermission("unregisterSipDialogStateCallback");
782 if (cb == null) {
783 throw new IllegalArgumentException("SipDialogStateCallback is null");
784 }
785 final long identity = Binder.clearCallingIdentity();
786 if (!SubscriptionManager.isValidSubscriptionId(subId)) {
787 throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
788 }
joonhunshin2c33ed92023-12-12 14:29:23 +0000789
790 enforceTelephonyFeatureWithException(getCurrentPackageName(),
791 FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION, "unregisterSipDialogStateCallback");
792
sungcheol ahn3991d2d2022-11-10 02:10:49 +0000793 try {
794 SipTransportController transport = getRcsFeatureController(subId).getFeature(
795 SipTransportController.class);
796 if (transport == null) {
797 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
798 "This transport does not support the unregisterSipDialogStateCallback"
799 + " of SIP delegates");
800 }
801 transport.removeCallbackForSipDialogState(subId, cb);
802 } finally {
803 Binder.restoreCallingIdentity(identity);
804 }
805 }
806
807 /**
Brad Ebingere3ae65a2020-09-11 12:45:11 -0700808 * Registers for updates to the RcsFeature connection through the IImsServiceFeatureCallback
809 * callback.
810 */
811 @Override
Brad Ebinger6366ce92020-10-01 13:51:05 -0700812 public void registerRcsFeatureCallback(int slotId, IImsServiceFeatureCallback callback) {
Brad Ebingere3ae65a2020-09-11 12:45:11 -0700813 enforceModifyPermission();
814
815 final long identity = Binder.clearCallingIdentity();
816 try {
817 if (mImsResolver == null) {
818 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
819 "Device does not support IMS");
820 }
Brad Ebinger6366ce92020-10-01 13:51:05 -0700821 mImsResolver.listenForFeature(slotId, ImsFeature.FEATURE_RCS, callback);
Brad Ebingere3ae65a2020-09-11 12:45:11 -0700822 } finally {
823 Binder.restoreCallingIdentity(identity);
824 }
825 }
Brad Ebinger6366ce92020-10-01 13:51:05 -0700826
Brad Ebingere3ae65a2020-09-11 12:45:11 -0700827 /**
828 * Unregister a previously registered IImsServiceFeatureCallback associated with an ImsFeature.
829 */
830 @Override
831 public void unregisterImsFeatureCallback(IImsServiceFeatureCallback callback) {
832 enforceModifyPermission();
833
834 final long identity = Binder.clearCallingIdentity();
835 try {
836 if (mImsResolver == null) return;
837 mImsResolver.unregisterImsFeatureCallback(callback);
838 } finally {
839 Binder.restoreCallingIdentity(identity);
840 }
841 }
842
843 /**
James.cf Linaf3183c2019-10-24 00:59:00 +0800844 * Make sure either called from same process as self (phone) or IPC caller has read privilege.
845 *
846 * @throws SecurityException if the caller does not have the required permission
847 */
848 private void enforceReadPrivilegedPermission(String message) {
849 mApp.enforceCallingOrSelfPermission(
850 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
851 }
852
853 /**
Brad Ebinger4df7e242021-02-17 23:23:21 +0000854 * @throws SecurityException if the caller does not have the required
855 * PERFORM_IMS_SINGLE_REGISTRATION permission.
856 */
857 private void enforceImsSingleRegistrationPermission(String message) {
858 mApp.enforceCallingOrSelfPermission(
859 Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION, message);
860 }
861
862 /**
James.cf Linaf3183c2019-10-24 00:59:00 +0800863 * Make sure the caller has the MODIFY_PHONE_STATE permission.
864 *
865 * @throws SecurityException if the caller does not have the required permission
866 */
867 private void enforceModifyPermission() {
868 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
869 }
James.cf Lincad981c2019-12-10 20:37:56 +0800870
871 /**
James.cf Lin051dd252021-01-21 03:30:54 +0800872 * Make sure the caller has the ACCESS_RCS_USER_CAPABILITY_EXCHANGE permission.
873 *
874 * @throws SecurityException if the caller does not have the required permission.
875 */
876 private void enforceAccessUserCapabilityExchangePermission(String message) {
877 mApp.enforceCallingOrSelfPermission(
878 android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, message);
879 }
880
881 /**
882 * Make sure the caller has the READ_CONTACTS permission.
883 *
884 * @throws SecurityException if the caller does not have the required permission.
885 */
886 private void enforceReadContactsPermission(String message) {
887 mApp.enforceCallingOrSelfPermission(
888 android.Manifest.permission.READ_CONTACTS, message);
889 }
890
891 /**
James.cf Lindc2d5422019-12-31 14:40:25 +0800892 * Retrieve RcsFeatureManager instance.
893 *
894 * @param subId the subscription ID
895 * @return The RcsFeatureManager instance
896 * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
897 */
Brad Ebingera68a4972020-01-30 17:31:23 -0800898 private RcsFeatureController getRcsFeatureController(int subId) {
James.cf Linc6b449f2021-06-05 01:11:15 +0800899 return getRcsFeatureController(subId, false /* skipVerifyingConfig */);
900 }
901
902 /**
903 * Retrieve RcsFeatureManager instance.
904 *
905 * @param subId the subscription ID
906 * @param skipVerifyingConfig If the RCS configuration can be skip.
907 * @return The RcsFeatureManager instance
908 * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
909 */
910 private RcsFeatureController getRcsFeatureController(int subId, boolean skipVerifyingConfig) {
James.cf Lindc2d5422019-12-31 14:40:25 +0800911 if (!ImsManager.isImsSupportedOnDevice(mApp)) {
James.cf Lincad981c2019-12-10 20:37:56 +0800912 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
James.cf Lindc2d5422019-12-31 14:40:25 +0800913 "IMS is not available on device.");
914 }
Brad Ebingera68a4972020-01-30 17:31:23 -0800915 if (mRcsService == null) {
916 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
917 "IMS is not available on device.");
918 }
James.cf Lindc2d5422019-12-31 14:40:25 +0800919 Phone phone = PhoneGlobals.getPhone(subId);
920 if (phone == null) {
921 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
922 "Invalid subscription Id: " + subId);
923 }
Brad Ebingera68a4972020-01-30 17:31:23 -0800924 int slotId = phone.getPhoneId();
James.cf Linc6b449f2021-06-05 01:11:15 +0800925 if (!skipVerifyingConfig) {
926 verifyImsRcsConfiguredOrThrow(slotId);
Brad Ebingere3885b22022-02-16 13:18:59 -0800927 verifyRcsSubIdActiveOrThrow(slotId, subId);
James.cf Linc6b449f2021-06-05 01:11:15 +0800928 }
Brad Ebingera68a4972020-01-30 17:31:23 -0800929 RcsFeatureController c = mRcsService.getFeatureController(slotId);
930 if (c == null) {
Brad Ebingere3885b22022-02-16 13:18:59 -0800931 // If we hit this case, we have verified that TelephonyRcsService has processed any
932 // subId changes for the associated slot and applied configs. In this case, the configs
933 // do not have the RCS feature enabled.
Brad Ebinger036dc9e2020-02-06 15:49:06 -0800934 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
935 "The requested operation is not supported for subId " + subId);
James.cf Lincad981c2019-12-10 20:37:56 +0800936 }
Brad Ebingere3885b22022-02-16 13:18:59 -0800937 if (!skipVerifyingConfig && c.getAssociatedSubId() != subId) {
938 // If we hit this case, the ImsFeature has not finished setting up the RCS feature yet
939 // or the RCS feature has crashed and is being set up again.
940 Log.w(TAG, "getRcsFeatureController: service unavailable on slot " + slotId
941 + " for subId " + subId);
942 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
943 "The ImsService is not currently available for subid " + subId
944 + ", please try again");
945 }
Brad Ebingera68a4972020-01-30 17:31:23 -0800946 return c;
James.cf Lincad981c2019-12-10 20:37:56 +0800947 }
James.cf Linc9f35a42020-01-15 02:35:22 +0800948
Brad Ebinger919631e2021-06-02 17:46:35 -0700949 /**
Brad Ebingere3885b22022-02-16 13:18:59 -0800950 * Ensure the TelephonyRcsService is tracking the supplied subId for the supplied slotId and has
951 * set up the stack.
952 */
953 private void verifyRcsSubIdActiveOrThrow(int slotId, int subId) {
954 if (mRcsService.verifyActiveSubId(slotId, subId)) return;
955
956 Log.w(TAG, "verifyRcsSubIdActiveOrThrow: verify failed, service not set up yet on "
957 + "slot " + slotId + " for subId " + subId);
958 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
959 "ImsService set up in progress for subId " + subId
960 + ", please try again");
961 }
962
963 /**
Brad Ebinger919631e2021-06-02 17:46:35 -0700964 * Throw an ImsException if the IMS resolver does not have an ImsService configured for RCS
965 * for the given slot ID or no ImsResolver instance has been created.
966 * @param slotId The slot ID that the IMS service is created for.
967 * @throws ServiceSpecificException If there is no ImsService configured for this slot.
968 */
969 private void verifyImsRcsConfiguredOrThrow(int slotId) {
970 if (mImsResolver == null
971 || !mImsResolver.isImsServiceConfiguredForFeature(slotId, ImsFeature.FEATURE_RCS)) {
972 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
973 "This subscription does not support RCS");
974 }
975 }
976
Brad Ebinger49a72b42021-01-29 00:55:24 +0000977 private boolean isImsSingleRegistrationSupportedOnDevice() {
978 return mSingleRegistrationOverride != null ? mSingleRegistrationOverride
979 : mApp.getPackageManager().hasSystemFeature(
980 PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION);
981 }
982
joonhunshin2c33ed92023-12-12 14:29:23 +0000983 /**
984 * Get the current calling package name.
985 * @return the current calling package name
986 */
987 @Nullable
988 private String getCurrentPackageName() {
989 if (mPackageManager == null) return null;
990 String[] callingUids = mPackageManager.getPackagesForUid(Binder.getCallingUid());
991 return (callingUids == null) ? null : callingUids[0];
992 }
993
994 /**
995 * Make sure the device has required telephony feature
996 *
997 * @throws UnsupportedOperationException if the device does not have required telephony feature
998 */
999 private void enforceTelephonyFeatureWithException(@Nullable String callingPackage,
1000 @NonNull String telephonyFeature, @NonNull String methodName) {
1001 if (callingPackage == null || mPackageManager == null) {
1002 return;
1003 }
1004
1005 if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
1006 || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
joonhunshinf624b2a2024-04-18 04:42:12 +00001007 Binder.getCallingUserHandle())
1008 || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
1009 // Skip to check associated telephony feature,
1010 // if compatibility change is not enabled for the current process or
1011 // the SDK version of vendor partition is less than Android V.
joonhunshin2c33ed92023-12-12 14:29:23 +00001012 return;
1013 }
1014
1015 if (!mPackageManager.hasSystemFeature(telephonyFeature)) {
1016 throw new UnsupportedOperationException(
1017 methodName + " is unsupported without " + telephonyFeature);
1018 }
1019 }
1020
James.cf Linc9f35a42020-01-15 02:35:22 +08001021 void setRcsService(TelephonyRcsService rcsService) {
1022 mRcsService = rcsService;
1023 }
Brad Ebinger49a72b42021-01-29 00:55:24 +00001024
1025 /**
1026 * Override device RCS single registration support check for CTS testing or remove override
1027 * if the Boolean is set to null.
1028 */
1029 void setDeviceSingleRegistrationSupportOverride(Boolean deviceOverrideValue) {
1030 mSingleRegistrationOverride = deviceOverrideValue;
1031 }
James.cf Linaf3183c2019-10-24 00:59:00 +08001032}