blob: ffac20221d7e1da0f839ddea60c25878299d355d [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;
Peter Wangc035ce42020-01-08 21:00:22 -080023import android.telephony.TelephonyFrameworkInitializer;
James.cf Lincad981c2019-12-10 20:37:56 +080024import android.telephony.ims.ImsException;
James.cf Lindc2d5422019-12-31 14:40:25 +080025import android.telephony.ims.RegistrationManager;
James.cf Linaf3183c2019-10-24 00:59:00 +080026import android.telephony.ims.aidl.IImsCapabilityCallback;
27import android.telephony.ims.aidl.IImsRcsController;
James.cf Lindc2d5422019-12-31 14:40:25 +080028import android.telephony.ims.aidl.IImsRegistrationCallback;
James.cf Linaf3183c2019-10-24 00:59:00 +080029import android.telephony.ims.aidl.IRcsUceControllerCallback;
30import android.telephony.ims.feature.RcsFeature;
James.cf Lincad981c2019-12-10 20:37:56 +080031import android.telephony.ims.stub.ImsRegistrationImplBase;
James.cf Linaf3183c2019-10-24 00:59:00 +080032import android.util.Log;
33
James.cf Lindc2d5422019-12-31 14:40:25 +080034import com.android.ims.ImsManager;
James.cf Lincad981c2019-12-10 20:37:56 +080035import com.android.ims.RcsFeatureManager;
James.cf Lindc2d5422019-12-31 14:40:25 +080036import com.android.internal.telephony.IIntegerConsumer;
James.cf Lincad981c2019-12-10 20:37:56 +080037import com.android.internal.telephony.Phone;
38import com.android.internal.telephony.imsphone.ImsPhone;
James.cf Linc9f35a42020-01-15 02:35:22 +080039import com.android.services.telephony.rcs.TelephonyRcsService;
James.cf Lincad981c2019-12-10 20:37:56 +080040
James.cf Linaf3183c2019-10-24 00:59:00 +080041import java.util.List;
42
43/**
44 * Implementation of the IImsRcsController interface.
45 */
46public class ImsRcsController extends IImsRcsController.Stub {
47 private static final String TAG = "ImsRcsController";
48
49 /** The singleton instance. */
50 private static ImsRcsController sInstance;
51
52 private PhoneGlobals mApp;
James.cf Linc9f35a42020-01-15 02:35:22 +080053 private TelephonyRcsService mRcsService;
James.cf Linaf3183c2019-10-24 00:59:00 +080054
55 /**
56 * Initialize the singleton ImsRcsController instance.
57 * This is only done once, at startup, from PhoneApp.onCreate().
58 */
59 static ImsRcsController init(PhoneGlobals app) {
60 synchronized (ImsRcsController.class) {
61 if (sInstance == null) {
62 sInstance = new ImsRcsController(app);
63 } else {
64 Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
65 }
66 return sInstance;
67 }
68 }
69
70 /** Private constructor; @see init() */
71 private ImsRcsController(PhoneGlobals app) {
72 Log.i(TAG, "ImsRcsController");
73 mApp = app;
Peter Wangc035ce42020-01-08 21:00:22 -080074 TelephonyFrameworkInitializer
75 .getTelephonyServiceManager().getTelephonyImsServiceRegisterer().register(this);
James.cf Linaf3183c2019-10-24 00:59:00 +080076 }
77
James.cf Lincad981c2019-12-10 20:37:56 +080078 /**
James.cf Lindc2d5422019-12-31 14:40:25 +080079 * Register a IImsRegistrationCallback to receive IMS network registration state.
80 */
81 @Override
82 public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback)
83 throws RemoteException {
84 enforceReadPrivilegedPermission("registerImsRegistrationCallback");
85 final long token = Binder.clearCallingIdentity();
86 try {
87 getRcsFeatureManager(subId).registerImsRegistrationCallback(callback);
88 } catch (com.android.ims.ImsException e) {
89 Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage());
90 throw new ServiceSpecificException(e.getCode());
91 } finally {
92 Binder.restoreCallingIdentity(token);
93 }
94 }
95
96 /**
97 * Removes an existing {@link RegistrationCallback}.
98 */
99 @Override
100 public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
101 enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
102 final long token = Binder.clearCallingIdentity();
103 try {
104 getRcsFeatureManager(subId).unregisterImsRegistrationCallback(callback);
105 } catch (ServiceSpecificException e) {
106 Log.e(TAG, "unregisterImsRegistrationCallback: error=" + e.errorCode);
107 } finally {
108 Binder.restoreCallingIdentity(token);
109 }
110 }
111
112 /**
113 * Get the IMS service registration state for the RcsFeature associated with this sub id.
114 */
115 @Override
116 public void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer) {
117 enforceReadPrivilegedPermission("getImsRcsRegistrationState");
118 final long token = Binder.clearCallingIdentity();
119 try {
120 getImsPhone(subId).getImsRcsRegistrationState(regState -> {
121 try {
122 consumer.accept((regState == null)
123 ? RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED : regState);
124 } catch (RemoteException e) {
125 Log.w(TAG, "getImsRcsRegistrationState: callback is not available.");
126 }
127 });
128 } finally {
129 Binder.restoreCallingIdentity(token);
130 }
131 }
132
133 /**
134 * Gets the Transport Type associated with the current IMS RCS registration.
135 */
136 @Override
137 public void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer) {
138 enforceReadPrivilegedPermission("getImsRcsRegistrationTransportType");
139 final long token = Binder.clearCallingIdentity();
140 try {
141 getImsPhone(subId).getImsRcsRegistrationTech(regTech -> {
142 // Convert registration tech from ImsRegistrationImplBase -> RegistrationManager
143 int regTechConverted = (regTech == null)
144 ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : regTech;
145 regTechConverted = RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(
146 regTechConverted);
147 try {
148 consumer.accept(regTechConverted);
149 } catch (RemoteException e) {
150 Log.w(TAG, "getImsRcsRegistrationTransportType: callback is not available.");
151 }
152 });
153 } finally {
154 Binder.restoreCallingIdentity(token);
155 }
156 }
157
158 /**
James.cf Lincad981c2019-12-10 20:37:56 +0800159 * Register a capability callback which will provide RCS availability updates for the
160 * subscription specified.
161 *
162 * @param subId the subscription ID
163 * @param callback The ImsCapabilityCallback to be registered.
164 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800165 @Override
James.cf Lincad981c2019-12-10 20:37:56 +0800166 public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)
167 throws RemoteException {
James.cf Linaf3183c2019-10-24 00:59:00 +0800168 enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
James.cf Lincad981c2019-12-10 20:37:56 +0800169 final long token = Binder.clearCallingIdentity();
170 try {
171 getRcsFeatureManager(subId).registerRcsAvailabilityCallback(callback);
172 } catch (com.android.ims.ImsException e) {
173 Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage());
174 throw new ServiceSpecificException(e.getCode());
175 } finally {
176 Binder.restoreCallingIdentity(token);
177 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800178 }
179
James.cf Lincad981c2019-12-10 20:37:56 +0800180 /**
181 * Remove the registered capability callback.
182 *
183 * @param subId the subscription ID
184 * @param callback The ImsCapabilityCallback to be removed.
185 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800186 @Override
James.cf Lincad981c2019-12-10 20:37:56 +0800187 public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800188 enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback");
James.cf Lincad981c2019-12-10 20:37:56 +0800189 final long token = Binder.clearCallingIdentity();
190 try {
191 getRcsFeatureManager(subId).unregisterRcsAvailabilityCallback(callback);
192 } catch (com.android.ims.ImsException e) {
193 Log.e(TAG, "unregisterRcsAvailabilityCallback: sudId=" + subId + "," + e.getMessage());
194 } finally {
195 Binder.restoreCallingIdentity(token);
196 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800197 }
198
James.cf Lincad981c2019-12-10 20:37:56 +0800199 /**
200 * Query for the capability of an IMS RCS service
201 *
202 * @param subId the subscription ID
203 * @param capability the RCS capability to query.
204 * @param radioTech the radio tech that this capability failed for
205 * @return true if the RCS capability is capable for this subscription, false otherwise.
206 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800207 @Override
208 public boolean isCapable(int subId,
James.cf Lincad981c2019-12-10 20:37:56 +0800209 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
210 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800211 enforceReadPrivilegedPermission("isCapable");
James.cf Lincad981c2019-12-10 20:37:56 +0800212 final long token = Binder.clearCallingIdentity();
213 try {
214 return getRcsFeatureManager(subId).isCapable(capability, radioTech);
215 } catch (com.android.ims.ImsException e) {
216 Log.e(TAG, "isCapable: sudId=" + subId
217 + ", capability=" + capability + ", " + e.getMessage());
218 return false;
219 } finally {
220 Binder.restoreCallingIdentity(token);
221 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800222 }
223
James.cf Lincad981c2019-12-10 20:37:56 +0800224 /**
225 * Query the availability of an IMS RCS capability.
226 *
227 * @param subId the subscription ID
228 * @param capability the RCS capability to query.
229 * @return true if the RCS capability is currently available for the associated subscription,
230 * false otherwise.
231 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800232 @Override
233 public boolean isAvailable(int subId,
234 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
235 enforceReadPrivilegedPermission("isAvailable");
James.cf Lincad981c2019-12-10 20:37:56 +0800236 final long token = Binder.clearCallingIdentity();
237 try {
238 return getRcsFeatureManager(subId).isAvailable(capability);
239 } catch (com.android.ims.ImsException e) {
240 Log.e(TAG, "isAvailable: sudId=" + subId
241 + ", capability=" + capability + ", " + e.getMessage());
242 return false;
243 } finally {
244 Binder.restoreCallingIdentity(token);
245 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800246 }
247
248 @Override
249 public void requestCapabilities(int subId, List<Uri> contactNumbers,
250 IRcsUceControllerCallback c) {
251 enforceReadPrivilegedPermission("requestCapabilities");
252 }
253
254 @Override
255 public int getUcePublishState(int subId) {
256 enforceReadPrivilegedPermission("getUcePublishState");
257 return -1;
258 }
259
260 @Override
261 public boolean isUceSettingEnabled(int subId) {
262 enforceReadPrivilegedPermission("isUceSettingEnabled");
263 return false;
264 }
265
266 @Override
267 public void setUceSettingEnabled(int subId, boolean isEnabled) {
268 enforceModifyPermission();
269 }
270
271 /**
272 * Make sure either called from same process as self (phone) or IPC caller has read privilege.
273 *
274 * @throws SecurityException if the caller does not have the required permission
275 */
276 private void enforceReadPrivilegedPermission(String message) {
277 mApp.enforceCallingOrSelfPermission(
278 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
279 }
280
281 /**
282 * Make sure the caller has the MODIFY_PHONE_STATE permission.
283 *
284 * @throws SecurityException if the caller does not have the required permission
285 */
286 private void enforceModifyPermission() {
287 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
288 }
James.cf Lincad981c2019-12-10 20:37:56 +0800289
290 /**
James.cf Lindc2d5422019-12-31 14:40:25 +0800291 * Retrieve ImsPhone instance.
James.cf Lincad981c2019-12-10 20:37:56 +0800292 *
293 * @param subId the subscription ID
James.cf Lindc2d5422019-12-31 14:40:25 +0800294 * @return The ImsPhone instance
295 * @throws ServiceSpecificException if getting ImsPhone instance failed.
James.cf Lincad981c2019-12-10 20:37:56 +0800296 */
James.cf Lindc2d5422019-12-31 14:40:25 +0800297 private ImsPhone getImsPhone(int subId) {
298 if (!ImsManager.isImsSupportedOnDevice(mApp)) {
299 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
300 "IMS is not available on device.");
301 }
James.cf Lincad981c2019-12-10 20:37:56 +0800302 Phone phone = PhoneGlobals.getPhone(subId);
303 if (phone == null) {
304 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
305 "Invalid subscription Id: " + subId);
306 }
307 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
308 if (imsPhone == null) {
James.cf Lindc2d5422019-12-31 14:40:25 +0800309 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
310 "Cannot find ImsPhone instance: " + subId);
311 }
312 return imsPhone;
313 }
314
315 /**
316 * Retrieve RcsFeatureManager instance.
317 *
318 * @param subId the subscription ID
319 * @return The RcsFeatureManager instance
320 * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
321 */
322 private RcsFeatureManager getRcsFeatureManager(int subId) {
323 if (!ImsManager.isImsSupportedOnDevice(mApp)) {
James.cf Lincad981c2019-12-10 20:37:56 +0800324 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
James.cf Lindc2d5422019-12-31 14:40:25 +0800325 "IMS is not available on device.");
326 }
327 Phone phone = PhoneGlobals.getPhone(subId);
328 if (phone == null) {
329 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
330 "Invalid subscription Id: " + subId);
331 }
332 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
333 if (imsPhone == null) {
334 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
James.cf Lincad981c2019-12-10 20:37:56 +0800335 "Cannot find ImsPhone instance: " + subId);
336 }
337 RcsFeatureManager rcsFeatureManager = imsPhone.getRcsManager();
338 if (rcsFeatureManager == null) {
339 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
340 "Cannot find RcsFeatureManager instance: " + subId);
341 }
342 return rcsFeatureManager;
343 }
James.cf Linc9f35a42020-01-15 02:35:22 +0800344
345 void setRcsService(TelephonyRcsService rcsService) {
346 mRcsService = rcsService;
347 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800348}