blob: f5f24d36ab857a33101956967b27ab4b637a666c [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
James.cf Linaf3183c2019-10-24 00:59:00 +080019import android.net.Uri;
James.cf Lincad981c2019-12-10 20:37:56 +080020import android.os.Binder;
21import android.os.RemoteException;
James.cf Lincad981c2019-12-10 20:37:56 +080022import android.os.ServiceSpecificException;
Brad Ebingerb7a866a2020-01-22 17:51:55 -080023import android.telephony.SubscriptionManager;
Peter Wangc035ce42020-01-08 21:00:22 -080024import android.telephony.TelephonyFrameworkInitializer;
James.cf Lincad981c2019-12-10 20:37:56 +080025import android.telephony.ims.ImsException;
James.cf Lindc2d5422019-12-31 14:40:25 +080026import android.telephony.ims.RegistrationManager;
James.cf Linaf3183c2019-10-24 00:59:00 +080027import android.telephony.ims.aidl.IImsCapabilityCallback;
28import android.telephony.ims.aidl.IImsRcsController;
James.cf Lindc2d5422019-12-31 14:40:25 +080029import android.telephony.ims.aidl.IImsRegistrationCallback;
James.cf Linaf3183c2019-10-24 00:59:00 +080030import android.telephony.ims.aidl.IRcsUceControllerCallback;
James.cf Lincdad3862020-02-25 15:55:03 +080031import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
James.cf Linaf3183c2019-10-24 00:59:00 +080032import android.telephony.ims.feature.RcsFeature;
James.cf Lincad981c2019-12-10 20:37:56 +080033import android.telephony.ims.stub.ImsRegistrationImplBase;
James.cf Linaf3183c2019-10-24 00:59:00 +080034import android.util.Log;
35
James.cf Lindc2d5422019-12-31 14:40:25 +080036import com.android.ims.ImsManager;
James.cf Lindc2d5422019-12-31 14:40:25 +080037import com.android.internal.telephony.IIntegerConsumer;
James.cf Lincad981c2019-12-10 20:37:56 +080038import com.android.internal.telephony.Phone;
Brad Ebinger8b79edc2020-02-27 19:13:24 -080039import com.android.internal.telephony.TelephonyPermissions;
James.cf Lincad981c2019-12-10 20:37:56 +080040import com.android.internal.telephony.imsphone.ImsPhone;
Brad Ebingera68a4972020-01-30 17:31:23 -080041import com.android.services.telephony.rcs.RcsFeatureController;
James.cf Linc9f35a42020-01-15 02:35:22 +080042import com.android.services.telephony.rcs.TelephonyRcsService;
Brad Ebingera68a4972020-01-30 17:31:23 -080043import com.android.services.telephony.rcs.UserCapabilityExchangeImpl;
James.cf Lincad981c2019-12-10 20:37:56 +080044
James.cf Linaf3183c2019-10-24 00:59:00 +080045import java.util.List;
46
47/**
48 * Implementation of the IImsRcsController interface.
49 */
50public class ImsRcsController extends IImsRcsController.Stub {
51 private static final String TAG = "ImsRcsController";
52
53 /** The singleton instance. */
54 private static ImsRcsController sInstance;
55
56 private PhoneGlobals mApp;
James.cf Linc9f35a42020-01-15 02:35:22 +080057 private TelephonyRcsService mRcsService;
James.cf Linaf3183c2019-10-24 00:59:00 +080058
59 /**
60 * Initialize the singleton ImsRcsController instance.
61 * This is only done once, at startup, from PhoneApp.onCreate().
62 */
63 static ImsRcsController init(PhoneGlobals app) {
64 synchronized (ImsRcsController.class) {
65 if (sInstance == null) {
66 sInstance = new ImsRcsController(app);
67 } else {
68 Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
69 }
70 return sInstance;
71 }
72 }
73
74 /** Private constructor; @see init() */
75 private ImsRcsController(PhoneGlobals app) {
76 Log.i(TAG, "ImsRcsController");
77 mApp = app;
Peter Wangc035ce42020-01-08 21:00:22 -080078 TelephonyFrameworkInitializer
79 .getTelephonyServiceManager().getTelephonyImsServiceRegisterer().register(this);
James.cf Linaf3183c2019-10-24 00:59:00 +080080 }
81
James.cf Lincad981c2019-12-10 20:37:56 +080082 /**
Brad Ebingera68a4972020-01-30 17:31:23 -080083 * Register a {@link RegistrationManager.RegistrationCallback} to receive IMS network
84 * registration state.
James.cf Lindc2d5422019-12-31 14:40:25 +080085 */
86 @Override
Brad Ebingera68a4972020-01-30 17:31:23 -080087 public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
James.cf Lindc2d5422019-12-31 14:40:25 +080088 enforceReadPrivilegedPermission("registerImsRegistrationCallback");
89 final long token = Binder.clearCallingIdentity();
90 try {
Brad Ebingera68a4972020-01-30 17:31:23 -080091 getRcsFeatureController(subId).registerImsRegistrationCallback(subId, callback);
92 } catch (ImsException e) {
James.cf Lindc2d5422019-12-31 14:40:25 +080093 Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage());
94 throw new ServiceSpecificException(e.getCode());
95 } finally {
96 Binder.restoreCallingIdentity(token);
97 }
98 }
99
100 /**
Brad Ebingera68a4972020-01-30 17:31:23 -0800101 * Removes an existing {@link RegistrationManager.RegistrationCallback}.
James.cf Lindc2d5422019-12-31 14:40:25 +0800102 */
103 @Override
104 public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
105 enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
106 final long token = Binder.clearCallingIdentity();
107 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800108 getRcsFeatureController(subId).unregisterImsRegistrationCallback(subId, callback);
James.cf Lindc2d5422019-12-31 14:40:25 +0800109 } catch (ServiceSpecificException e) {
110 Log.e(TAG, "unregisterImsRegistrationCallback: error=" + e.errorCode);
111 } finally {
112 Binder.restoreCallingIdentity(token);
113 }
114 }
115
116 /**
117 * Get the IMS service registration state for the RcsFeature associated with this sub id.
118 */
119 @Override
120 public void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer) {
121 enforceReadPrivilegedPermission("getImsRcsRegistrationState");
122 final long token = Binder.clearCallingIdentity();
123 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800124 getRcsFeatureController(subId).getRegistrationState(regState -> {
James.cf Lindc2d5422019-12-31 14:40:25 +0800125 try {
126 consumer.accept((regState == null)
127 ? RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED : regState);
128 } catch (RemoteException e) {
129 Log.w(TAG, "getImsRcsRegistrationState: callback is not available.");
130 }
131 });
132 } finally {
133 Binder.restoreCallingIdentity(token);
134 }
135 }
136
137 /**
138 * Gets the Transport Type associated with the current IMS RCS registration.
139 */
140 @Override
141 public void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer) {
142 enforceReadPrivilegedPermission("getImsRcsRegistrationTransportType");
143 final long token = Binder.clearCallingIdentity();
144 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800145 getRcsFeatureController(subId).getRegistrationTech(regTech -> {
James.cf Lindc2d5422019-12-31 14:40:25 +0800146 // Convert registration tech from ImsRegistrationImplBase -> RegistrationManager
147 int regTechConverted = (regTech == null)
148 ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : regTech;
149 regTechConverted = RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(
150 regTechConverted);
151 try {
152 consumer.accept(regTechConverted);
153 } catch (RemoteException e) {
154 Log.w(TAG, "getImsRcsRegistrationTransportType: callback is not available.");
155 }
156 });
157 } finally {
158 Binder.restoreCallingIdentity(token);
159 }
160 }
161
162 /**
James.cf Lincad981c2019-12-10 20:37:56 +0800163 * Register a capability callback which will provide RCS availability updates for the
164 * subscription specified.
165 *
166 * @param subId the subscription ID
167 * @param callback The ImsCapabilityCallback to be registered.
168 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800169 @Override
Brad Ebingera68a4972020-01-30 17:31:23 -0800170 public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800171 enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
James.cf Lincad981c2019-12-10 20:37:56 +0800172 final long token = Binder.clearCallingIdentity();
173 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800174 getRcsFeatureController(subId).registerRcsAvailabilityCallback(subId, callback);
175 } catch (ImsException e) {
James.cf Lincad981c2019-12-10 20:37:56 +0800176 Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage());
177 throw new ServiceSpecificException(e.getCode());
178 } finally {
179 Binder.restoreCallingIdentity(token);
180 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800181 }
182
James.cf Lincad981c2019-12-10 20:37:56 +0800183 /**
184 * Remove the registered capability callback.
185 *
186 * @param subId the subscription ID
187 * @param callback The ImsCapabilityCallback to be removed.
188 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800189 @Override
James.cf Lincad981c2019-12-10 20:37:56 +0800190 public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800191 enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback");
James.cf Lincad981c2019-12-10 20:37:56 +0800192 final long token = Binder.clearCallingIdentity();
193 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800194 getRcsFeatureController(subId).unregisterRcsAvailabilityCallback(subId, callback);
James.cf Lincad981c2019-12-10 20:37:56 +0800195 } finally {
196 Binder.restoreCallingIdentity(token);
197 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800198 }
199
James.cf Lincdad3862020-02-25 15:55:03 +0800200 @Override
201 public void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
202 enforceReadPrivilegedPermission("registerUcePublishStateCallback");
203 final long token = Binder.clearCallingIdentity();
204 try {
205 UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
206 UserCapabilityExchangeImpl.class);
207 if (uce == null) {
208 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
209 "This subscription does not support UCE.");
210 }
211 uce.registerPublishStateCallback(c);
212 } finally {
213 Binder.restoreCallingIdentity(token);
214 }
215 }
216
217 @Override
218 public void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
219 enforceReadPrivilegedPermission("unregisterUcePublishStateCallback");
220 final long token = Binder.clearCallingIdentity();
221 try {
222 UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
223 UserCapabilityExchangeImpl.class);
224 if (uce == null) {
225 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
226 "This subscription does not support UCE.");
227 }
228 uce.unregisterUcePublishStateCallback(c);
229 } finally {
230 Binder.restoreCallingIdentity(token);
231 }
232 }
233
James.cf Lincad981c2019-12-10 20:37:56 +0800234 /**
235 * Query for the capability of an IMS RCS service
236 *
237 * @param subId the subscription ID
238 * @param capability the RCS capability to query.
239 * @param radioTech the radio tech that this capability failed for
240 * @return true if the RCS capability is capable for this subscription, false otherwise.
241 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800242 @Override
243 public boolean isCapable(int subId,
James.cf Lincad981c2019-12-10 20:37:56 +0800244 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
245 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800246 enforceReadPrivilegedPermission("isCapable");
James.cf Lincad981c2019-12-10 20:37:56 +0800247 final long token = Binder.clearCallingIdentity();
248 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800249 return getRcsFeatureController(subId).isCapable(capability, radioTech);
250 } catch (ImsException e) {
James.cf Lincad981c2019-12-10 20:37:56 +0800251 Log.e(TAG, "isCapable: sudId=" + subId
252 + ", capability=" + capability + ", " + e.getMessage());
253 return false;
254 } finally {
255 Binder.restoreCallingIdentity(token);
256 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800257 }
258
James.cf Lincad981c2019-12-10 20:37:56 +0800259 /**
260 * Query the availability of an IMS RCS capability.
261 *
262 * @param subId the subscription ID
263 * @param capability the RCS capability to query.
264 * @return true if the RCS capability is currently available for the associated subscription,
265 * false otherwise.
266 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800267 @Override
268 public boolean isAvailable(int subId,
269 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
270 enforceReadPrivilegedPermission("isAvailable");
James.cf Lincad981c2019-12-10 20:37:56 +0800271 final long token = Binder.clearCallingIdentity();
272 try {
Brad Ebingera68a4972020-01-30 17:31:23 -0800273 return getRcsFeatureController(subId).isAvailable(capability);
274 } catch (ImsException e) {
James.cf Lincad981c2019-12-10 20:37:56 +0800275 Log.e(TAG, "isAvailable: sudId=" + subId
276 + ", capability=" + capability + ", " + e.getMessage());
277 return false;
278 } finally {
279 Binder.restoreCallingIdentity(token);
280 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800281 }
282
283 @Override
Brad Ebinger8b79edc2020-02-27 19:13:24 -0800284 public void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
285 List<Uri> contactNumbers, IRcsUceControllerCallback c) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800286 enforceReadPrivilegedPermission("requestCapabilities");
Brad Ebinger8b79edc2020-02-27 19:13:24 -0800287 if (!isUceSettingEnabled(subId, callingPackage, callingFeatureId)) {
288 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
289 "The user has not enabled UCE for this subscription.");
290 }
Brad Ebingera68a4972020-01-30 17:31:23 -0800291 final long token = Binder.clearCallingIdentity();
292 try {
293 UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
294 UserCapabilityExchangeImpl.class);
295 if (uce == null) {
296 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
297 "This subscription does not support UCE.");
298 }
299 uce.requestCapabilities(contactNumbers, c);
300 } finally {
301 Binder.restoreCallingIdentity(token);
Brad Ebinger1aa94992020-01-22 14:17:23 -0800302 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800303 }
304
305 @Override
306 public int getUcePublishState(int subId) {
307 enforceReadPrivilegedPermission("getUcePublishState");
Brad Ebingera68a4972020-01-30 17:31:23 -0800308 final long token = Binder.clearCallingIdentity();
309 try {
310 UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
311 UserCapabilityExchangeImpl.class);
312 if (uce == null) {
313 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
314 "This subscription does not support UCE.");
315 }
316 return uce.getUcePublishState();
317 } finally {
318 Binder.restoreCallingIdentity(token);
Brad Ebinger1aa94992020-01-22 14:17:23 -0800319 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800320 }
321
322 @Override
Brad Ebinger8b79edc2020-02-27 19:13:24 -0800323 public boolean isUceSettingEnabled(int subId, String callingPackage, String callingFeatureId) {
324 if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
325 mApp, subId, callingPackage, callingFeatureId, "isUceSettingEnabled")) {
326 Log.w(TAG, "isUceSettingEnabled: READ_PHONE_STATE app op disabled when accessing "
327 + "isUceSettingEnabled");
328 return false;
329 }
330 final long token = Binder.clearCallingIdentity();
331 try {
332 return SubscriptionManager.getBooleanSubscriptionProperty(subId,
333 SubscriptionManager.IMS_RCS_UCE_ENABLED, false /*defaultValue*/, mApp);
334 } finally {
335 Binder.restoreCallingIdentity(token);
336 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800337 }
338
339 @Override
340 public void setUceSettingEnabled(int subId, boolean isEnabled) {
341 enforceModifyPermission();
Brad Ebinger8b79edc2020-02-27 19:13:24 -0800342 final long token = Binder.clearCallingIdentity();
343 try {
344 SubscriptionManager.setSubscriptionProperty(subId,
345 SubscriptionManager.IMS_RCS_UCE_ENABLED, (isEnabled ? "1" : "0"));
346 } finally {
347 Binder.restoreCallingIdentity(token);
348 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800349 }
350
351 /**
352 * Make sure either called from same process as self (phone) or IPC caller has read privilege.
353 *
354 * @throws SecurityException if the caller does not have the required permission
355 */
356 private void enforceReadPrivilegedPermission(String message) {
357 mApp.enforceCallingOrSelfPermission(
358 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
359 }
360
361 /**
362 * Make sure the caller has the MODIFY_PHONE_STATE permission.
363 *
364 * @throws SecurityException if the caller does not have the required permission
365 */
366 private void enforceModifyPermission() {
367 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
368 }
James.cf Lincad981c2019-12-10 20:37:56 +0800369
370 /**
James.cf Lindc2d5422019-12-31 14:40:25 +0800371 * Retrieve ImsPhone instance.
James.cf Lincad981c2019-12-10 20:37:56 +0800372 *
373 * @param subId the subscription ID
James.cf Lindc2d5422019-12-31 14:40:25 +0800374 * @return The ImsPhone instance
375 * @throws ServiceSpecificException if getting ImsPhone instance failed.
James.cf Lincad981c2019-12-10 20:37:56 +0800376 */
James.cf Lindc2d5422019-12-31 14:40:25 +0800377 private ImsPhone getImsPhone(int subId) {
378 if (!ImsManager.isImsSupportedOnDevice(mApp)) {
379 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
380 "IMS is not available on device.");
381 }
James.cf Lincad981c2019-12-10 20:37:56 +0800382 Phone phone = PhoneGlobals.getPhone(subId);
383 if (phone == null) {
384 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
385 "Invalid subscription Id: " + subId);
386 }
387 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
388 if (imsPhone == null) {
James.cf Lindc2d5422019-12-31 14:40:25 +0800389 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
390 "Cannot find ImsPhone instance: " + subId);
391 }
392 return imsPhone;
393 }
394
395 /**
396 * Retrieve RcsFeatureManager instance.
397 *
398 * @param subId the subscription ID
399 * @return The RcsFeatureManager instance
400 * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
401 */
Brad Ebingera68a4972020-01-30 17:31:23 -0800402 private RcsFeatureController getRcsFeatureController(int subId) {
James.cf Lindc2d5422019-12-31 14:40:25 +0800403 if (!ImsManager.isImsSupportedOnDevice(mApp)) {
James.cf Lincad981c2019-12-10 20:37:56 +0800404 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
James.cf Lindc2d5422019-12-31 14:40:25 +0800405 "IMS is not available on device.");
406 }
Brad Ebingera68a4972020-01-30 17:31:23 -0800407 if (mRcsService == null) {
408 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
409 "IMS is not available on device.");
410 }
James.cf Lindc2d5422019-12-31 14:40:25 +0800411 Phone phone = PhoneGlobals.getPhone(subId);
412 if (phone == null) {
413 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
414 "Invalid subscription Id: " + subId);
415 }
Brad Ebingera68a4972020-01-30 17:31:23 -0800416 int slotId = phone.getPhoneId();
417 RcsFeatureController c = mRcsService.getFeatureController(slotId);
418 if (c == null) {
Brad Ebinger036dc9e2020-02-06 15:49:06 -0800419 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
420 "The requested operation is not supported for subId " + subId);
James.cf Lincad981c2019-12-10 20:37:56 +0800421 }
Brad Ebingera68a4972020-01-30 17:31:23 -0800422 return c;
James.cf Lincad981c2019-12-10 20:37:56 +0800423 }
James.cf Linc9f35a42020-01-15 02:35:22 +0800424
425 void setRcsService(TelephonyRcsService rcsService) {
426 mRcsService = rcsService;
427 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800428}