blob: 48300c91b4ed2a7a02434df1a91ae92715f5edbb [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;
31import android.telephony.ims.feature.RcsFeature;
James.cf Lincad981c2019-12-10 20:37:56 +080032import android.telephony.ims.stub.ImsRegistrationImplBase;
James.cf Linaf3183c2019-10-24 00:59:00 +080033import android.util.Log;
34
James.cf Lindc2d5422019-12-31 14:40:25 +080035import com.android.ims.ImsManager;
James.cf Lincad981c2019-12-10 20:37:56 +080036import com.android.ims.RcsFeatureManager;
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;
39import com.android.internal.telephony.imsphone.ImsPhone;
James.cf Linc9f35a42020-01-15 02:35:22 +080040import com.android.services.telephony.rcs.TelephonyRcsService;
James.cf Lincad981c2019-12-10 20:37:56 +080041
James.cf Linaf3183c2019-10-24 00:59:00 +080042import java.util.List;
43
44/**
45 * Implementation of the IImsRcsController interface.
46 */
47public class ImsRcsController extends IImsRcsController.Stub {
48 private static final String TAG = "ImsRcsController";
49
50 /** The singleton instance. */
51 private static ImsRcsController sInstance;
52
53 private PhoneGlobals mApp;
James.cf Linc9f35a42020-01-15 02:35:22 +080054 private TelephonyRcsService mRcsService;
James.cf Linaf3183c2019-10-24 00:59:00 +080055
56 /**
57 * Initialize the singleton ImsRcsController instance.
58 * This is only done once, at startup, from PhoneApp.onCreate().
59 */
60 static ImsRcsController init(PhoneGlobals app) {
61 synchronized (ImsRcsController.class) {
62 if (sInstance == null) {
63 sInstance = new ImsRcsController(app);
64 } else {
65 Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
66 }
67 return sInstance;
68 }
69 }
70
71 /** Private constructor; @see init() */
72 private ImsRcsController(PhoneGlobals app) {
73 Log.i(TAG, "ImsRcsController");
74 mApp = app;
Peter Wangc035ce42020-01-08 21:00:22 -080075 TelephonyFrameworkInitializer
76 .getTelephonyServiceManager().getTelephonyImsServiceRegisterer().register(this);
James.cf Linaf3183c2019-10-24 00:59:00 +080077 }
78
James.cf Lincad981c2019-12-10 20:37:56 +080079 /**
James.cf Lindc2d5422019-12-31 14:40:25 +080080 * Register a IImsRegistrationCallback to receive IMS network registration state.
81 */
82 @Override
83 public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback)
84 throws RemoteException {
85 enforceReadPrivilegedPermission("registerImsRegistrationCallback");
86 final long token = Binder.clearCallingIdentity();
87 try {
88 getRcsFeatureManager(subId).registerImsRegistrationCallback(callback);
89 } catch (com.android.ims.ImsException e) {
90 Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage());
91 throw new ServiceSpecificException(e.getCode());
92 } finally {
93 Binder.restoreCallingIdentity(token);
94 }
95 }
96
97 /**
98 * Removes an existing {@link RegistrationCallback}.
99 */
100 @Override
101 public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
102 enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
103 final long token = Binder.clearCallingIdentity();
104 try {
105 getRcsFeatureManager(subId).unregisterImsRegistrationCallback(callback);
106 } catch (ServiceSpecificException e) {
107 Log.e(TAG, "unregisterImsRegistrationCallback: error=" + e.errorCode);
108 } finally {
109 Binder.restoreCallingIdentity(token);
110 }
111 }
112
113 /**
114 * Get the IMS service registration state for the RcsFeature associated with this sub id.
115 */
116 @Override
117 public void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer) {
118 enforceReadPrivilegedPermission("getImsRcsRegistrationState");
119 final long token = Binder.clearCallingIdentity();
120 try {
121 getImsPhone(subId).getImsRcsRegistrationState(regState -> {
122 try {
123 consumer.accept((regState == null)
124 ? RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED : regState);
125 } catch (RemoteException e) {
126 Log.w(TAG, "getImsRcsRegistrationState: callback is not available.");
127 }
128 });
129 } finally {
130 Binder.restoreCallingIdentity(token);
131 }
132 }
133
134 /**
135 * Gets the Transport Type associated with the current IMS RCS registration.
136 */
137 @Override
138 public void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer) {
139 enforceReadPrivilegedPermission("getImsRcsRegistrationTransportType");
140 final long token = Binder.clearCallingIdentity();
141 try {
142 getImsPhone(subId).getImsRcsRegistrationTech(regTech -> {
143 // Convert registration tech from ImsRegistrationImplBase -> RegistrationManager
144 int regTechConverted = (regTech == null)
145 ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : regTech;
146 regTechConverted = RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(
147 regTechConverted);
148 try {
149 consumer.accept(regTechConverted);
150 } catch (RemoteException e) {
151 Log.w(TAG, "getImsRcsRegistrationTransportType: callback is not available.");
152 }
153 });
154 } finally {
155 Binder.restoreCallingIdentity(token);
156 }
157 }
158
159 /**
James.cf Lincad981c2019-12-10 20:37:56 +0800160 * Register a capability callback which will provide RCS availability updates for the
161 * subscription specified.
162 *
163 * @param subId the subscription ID
164 * @param callback The ImsCapabilityCallback to be registered.
165 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800166 @Override
James.cf Lincad981c2019-12-10 20:37:56 +0800167 public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)
168 throws RemoteException {
James.cf Linaf3183c2019-10-24 00:59:00 +0800169 enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
James.cf Lincad981c2019-12-10 20:37:56 +0800170 final long token = Binder.clearCallingIdentity();
171 try {
172 getRcsFeatureManager(subId).registerRcsAvailabilityCallback(callback);
173 } catch (com.android.ims.ImsException e) {
174 Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage());
175 throw new ServiceSpecificException(e.getCode());
176 } finally {
177 Binder.restoreCallingIdentity(token);
178 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800179 }
180
James.cf Lincad981c2019-12-10 20:37:56 +0800181 /**
182 * Remove the registered capability callback.
183 *
184 * @param subId the subscription ID
185 * @param callback The ImsCapabilityCallback to be removed.
186 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800187 @Override
James.cf Lincad981c2019-12-10 20:37:56 +0800188 public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800189 enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback");
James.cf Lincad981c2019-12-10 20:37:56 +0800190 final long token = Binder.clearCallingIdentity();
191 try {
192 getRcsFeatureManager(subId).unregisterRcsAvailabilityCallback(callback);
193 } catch (com.android.ims.ImsException e) {
194 Log.e(TAG, "unregisterRcsAvailabilityCallback: sudId=" + subId + "," + e.getMessage());
195 } finally {
196 Binder.restoreCallingIdentity(token);
197 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800198 }
199
James.cf Lincad981c2019-12-10 20:37:56 +0800200 /**
201 * Query for the capability of an IMS RCS service
202 *
203 * @param subId the subscription ID
204 * @param capability the RCS capability to query.
205 * @param radioTech the radio tech that this capability failed for
206 * @return true if the RCS capability is capable for this subscription, false otherwise.
207 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800208 @Override
209 public boolean isCapable(int subId,
James.cf Lincad981c2019-12-10 20:37:56 +0800210 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
211 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800212 enforceReadPrivilegedPermission("isCapable");
James.cf Lincad981c2019-12-10 20:37:56 +0800213 final long token = Binder.clearCallingIdentity();
214 try {
215 return getRcsFeatureManager(subId).isCapable(capability, radioTech);
216 } catch (com.android.ims.ImsException e) {
217 Log.e(TAG, "isCapable: sudId=" + subId
218 + ", capability=" + capability + ", " + e.getMessage());
219 return false;
220 } finally {
221 Binder.restoreCallingIdentity(token);
222 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800223 }
224
James.cf Lincad981c2019-12-10 20:37:56 +0800225 /**
226 * Query the availability of an IMS RCS capability.
227 *
228 * @param subId the subscription ID
229 * @param capability the RCS capability to query.
230 * @return true if the RCS capability is currently available for the associated subscription,
231 * false otherwise.
232 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800233 @Override
234 public boolean isAvailable(int subId,
235 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
236 enforceReadPrivilegedPermission("isAvailable");
James.cf Lincad981c2019-12-10 20:37:56 +0800237 final long token = Binder.clearCallingIdentity();
238 try {
239 return getRcsFeatureManager(subId).isAvailable(capability);
240 } catch (com.android.ims.ImsException e) {
241 Log.e(TAG, "isAvailable: sudId=" + subId
242 + ", capability=" + capability + ", " + e.getMessage());
243 return false;
244 } finally {
245 Binder.restoreCallingIdentity(token);
246 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800247 }
248
249 @Override
250 public void requestCapabilities(int subId, List<Uri> contactNumbers,
251 IRcsUceControllerCallback c) {
252 enforceReadPrivilegedPermission("requestCapabilities");
253 }
254
255 @Override
256 public int getUcePublishState(int subId) {
257 enforceReadPrivilegedPermission("getUcePublishState");
258 return -1;
259 }
260
261 @Override
262 public boolean isUceSettingEnabled(int subId) {
263 enforceReadPrivilegedPermission("isUceSettingEnabled");
Brad Ebingerb7a866a2020-01-22 17:51:55 -0800264 return SubscriptionManager.getBooleanSubscriptionProperty(subId,
265 SubscriptionManager.IMS_RCS_UCE_ENABLED, false /*defaultValue*/, mApp);
James.cf Linaf3183c2019-10-24 00:59:00 +0800266 }
267
268 @Override
269 public void setUceSettingEnabled(int subId, boolean isEnabled) {
270 enforceModifyPermission();
Brad Ebingerb7a866a2020-01-22 17:51:55 -0800271 SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.IMS_RCS_UCE_ENABLED,
272 (isEnabled ? "1" : "0"));
James.cf Linaf3183c2019-10-24 00:59:00 +0800273 }
274
275 /**
276 * Make sure either called from same process as self (phone) or IPC caller has read privilege.
277 *
278 * @throws SecurityException if the caller does not have the required permission
279 */
280 private void enforceReadPrivilegedPermission(String message) {
281 mApp.enforceCallingOrSelfPermission(
282 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
283 }
284
285 /**
286 * Make sure the caller has the MODIFY_PHONE_STATE permission.
287 *
288 * @throws SecurityException if the caller does not have the required permission
289 */
290 private void enforceModifyPermission() {
291 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
292 }
James.cf Lincad981c2019-12-10 20:37:56 +0800293
294 /**
James.cf Lindc2d5422019-12-31 14:40:25 +0800295 * Retrieve ImsPhone instance.
James.cf Lincad981c2019-12-10 20:37:56 +0800296 *
297 * @param subId the subscription ID
James.cf Lindc2d5422019-12-31 14:40:25 +0800298 * @return The ImsPhone instance
299 * @throws ServiceSpecificException if getting ImsPhone instance failed.
James.cf Lincad981c2019-12-10 20:37:56 +0800300 */
James.cf Lindc2d5422019-12-31 14:40:25 +0800301 private ImsPhone getImsPhone(int subId) {
302 if (!ImsManager.isImsSupportedOnDevice(mApp)) {
303 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
304 "IMS is not available on device.");
305 }
James.cf Lincad981c2019-12-10 20:37:56 +0800306 Phone phone = PhoneGlobals.getPhone(subId);
307 if (phone == null) {
308 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
309 "Invalid subscription Id: " + subId);
310 }
311 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
312 if (imsPhone == null) {
James.cf Lindc2d5422019-12-31 14:40:25 +0800313 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
314 "Cannot find ImsPhone instance: " + subId);
315 }
316 return imsPhone;
317 }
318
319 /**
320 * Retrieve RcsFeatureManager instance.
321 *
322 * @param subId the subscription ID
323 * @return The RcsFeatureManager instance
324 * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
325 */
326 private RcsFeatureManager getRcsFeatureManager(int subId) {
327 if (!ImsManager.isImsSupportedOnDevice(mApp)) {
James.cf Lincad981c2019-12-10 20:37:56 +0800328 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
James.cf Lindc2d5422019-12-31 14:40:25 +0800329 "IMS is not available on device.");
330 }
331 Phone phone = PhoneGlobals.getPhone(subId);
332 if (phone == null) {
333 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
334 "Invalid subscription Id: " + subId);
335 }
336 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
337 if (imsPhone == null) {
338 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
James.cf Lincad981c2019-12-10 20:37:56 +0800339 "Cannot find ImsPhone instance: " + subId);
340 }
341 RcsFeatureManager rcsFeatureManager = imsPhone.getRcsManager();
342 if (rcsFeatureManager == null) {
343 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
344 "Cannot find RcsFeatureManager instance: " + subId);
345 }
346 return rcsFeatureManager;
347 }
James.cf Linc9f35a42020-01-15 02:35:22 +0800348
349 void setRcsService(TelephonyRcsService rcsService) {
350 mRcsService = rcsService;
351 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800352}