blob: 1a28afdeb1800d6455cfc546e5cf9eb5aedb4dbc [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
19import android.content.Context;
20import android.net.Uri;
James.cf Lincad981c2019-12-10 20:37:56 +080021import android.os.Binder;
22import android.os.RemoteException;
James.cf Linaf3183c2019-10-24 00:59:00 +080023import android.os.ServiceManager;
James.cf Lincad981c2019-12-10 20:37:56 +080024import android.os.ServiceSpecificException;
25import 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;
40
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;
53
54 /**
55 * Initialize the singleton ImsRcsController instance.
56 * This is only done once, at startup, from PhoneApp.onCreate().
57 */
58 static ImsRcsController init(PhoneGlobals app) {
59 synchronized (ImsRcsController.class) {
60 if (sInstance == null) {
61 sInstance = new ImsRcsController(app);
62 } else {
63 Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
64 }
65 return sInstance;
66 }
67 }
68
69 /** Private constructor; @see init() */
70 private ImsRcsController(PhoneGlobals app) {
71 Log.i(TAG, "ImsRcsController");
72 mApp = app;
73 ServiceManager.addService(Context.TELEPHONY_IMS_SERVICE, this);
74 }
75
James.cf Lincad981c2019-12-10 20:37:56 +080076 /**
James.cf Lindc2d5422019-12-31 14:40:25 +080077 * Register a IImsRegistrationCallback to receive IMS network registration state.
78 */
79 @Override
80 public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback)
81 throws RemoteException {
82 enforceReadPrivilegedPermission("registerImsRegistrationCallback");
83 final long token = Binder.clearCallingIdentity();
84 try {
85 getRcsFeatureManager(subId).registerImsRegistrationCallback(callback);
86 } catch (com.android.ims.ImsException e) {
87 Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage());
88 throw new ServiceSpecificException(e.getCode());
89 } finally {
90 Binder.restoreCallingIdentity(token);
91 }
92 }
93
94 /**
95 * Removes an existing {@link RegistrationCallback}.
96 */
97 @Override
98 public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
99 enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
100 final long token = Binder.clearCallingIdentity();
101 try {
102 getRcsFeatureManager(subId).unregisterImsRegistrationCallback(callback);
103 } catch (ServiceSpecificException e) {
104 Log.e(TAG, "unregisterImsRegistrationCallback: error=" + e.errorCode);
105 } finally {
106 Binder.restoreCallingIdentity(token);
107 }
108 }
109
110 /**
111 * Get the IMS service registration state for the RcsFeature associated with this sub id.
112 */
113 @Override
114 public void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer) {
115 enforceReadPrivilegedPermission("getImsRcsRegistrationState");
116 final long token = Binder.clearCallingIdentity();
117 try {
118 getImsPhone(subId).getImsRcsRegistrationState(regState -> {
119 try {
120 consumer.accept((regState == null)
121 ? RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED : regState);
122 } catch (RemoteException e) {
123 Log.w(TAG, "getImsRcsRegistrationState: callback is not available.");
124 }
125 });
126 } finally {
127 Binder.restoreCallingIdentity(token);
128 }
129 }
130
131 /**
132 * Gets the Transport Type associated with the current IMS RCS registration.
133 */
134 @Override
135 public void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer) {
136 enforceReadPrivilegedPermission("getImsRcsRegistrationTransportType");
137 final long token = Binder.clearCallingIdentity();
138 try {
139 getImsPhone(subId).getImsRcsRegistrationTech(regTech -> {
140 // Convert registration tech from ImsRegistrationImplBase -> RegistrationManager
141 int regTechConverted = (regTech == null)
142 ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : regTech;
143 regTechConverted = RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(
144 regTechConverted);
145 try {
146 consumer.accept(regTechConverted);
147 } catch (RemoteException e) {
148 Log.w(TAG, "getImsRcsRegistrationTransportType: callback is not available.");
149 }
150 });
151 } finally {
152 Binder.restoreCallingIdentity(token);
153 }
154 }
155
156 /**
James.cf Lincad981c2019-12-10 20:37:56 +0800157 * Register a capability callback which will provide RCS availability updates for the
158 * subscription specified.
159 *
160 * @param subId the subscription ID
161 * @param callback The ImsCapabilityCallback to be registered.
162 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800163 @Override
James.cf Lincad981c2019-12-10 20:37:56 +0800164 public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)
165 throws RemoteException {
James.cf Linaf3183c2019-10-24 00:59:00 +0800166 enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
James.cf Lincad981c2019-12-10 20:37:56 +0800167 final long token = Binder.clearCallingIdentity();
168 try {
169 getRcsFeatureManager(subId).registerRcsAvailabilityCallback(callback);
170 } catch (com.android.ims.ImsException e) {
171 Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage());
172 throw new ServiceSpecificException(e.getCode());
173 } finally {
174 Binder.restoreCallingIdentity(token);
175 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800176 }
177
James.cf Lincad981c2019-12-10 20:37:56 +0800178 /**
179 * Remove the registered capability callback.
180 *
181 * @param subId the subscription ID
182 * @param callback The ImsCapabilityCallback to be removed.
183 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800184 @Override
James.cf Lincad981c2019-12-10 20:37:56 +0800185 public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800186 enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback");
James.cf Lincad981c2019-12-10 20:37:56 +0800187 final long token = Binder.clearCallingIdentity();
188 try {
189 getRcsFeatureManager(subId).unregisterRcsAvailabilityCallback(callback);
190 } catch (com.android.ims.ImsException e) {
191 Log.e(TAG, "unregisterRcsAvailabilityCallback: sudId=" + subId + "," + e.getMessage());
192 } finally {
193 Binder.restoreCallingIdentity(token);
194 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800195 }
196
James.cf Lincad981c2019-12-10 20:37:56 +0800197 /**
198 * Query for the capability of an IMS RCS service
199 *
200 * @param subId the subscription ID
201 * @param capability the RCS capability to query.
202 * @param radioTech the radio tech that this capability failed for
203 * @return true if the RCS capability is capable for this subscription, false otherwise.
204 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800205 @Override
206 public boolean isCapable(int subId,
James.cf Lincad981c2019-12-10 20:37:56 +0800207 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
208 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
James.cf Linaf3183c2019-10-24 00:59:00 +0800209 enforceReadPrivilegedPermission("isCapable");
James.cf Lincad981c2019-12-10 20:37:56 +0800210 final long token = Binder.clearCallingIdentity();
211 try {
212 return getRcsFeatureManager(subId).isCapable(capability, radioTech);
213 } catch (com.android.ims.ImsException e) {
214 Log.e(TAG, "isCapable: sudId=" + subId
215 + ", capability=" + capability + ", " + e.getMessage());
216 return false;
217 } finally {
218 Binder.restoreCallingIdentity(token);
219 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800220 }
221
James.cf Lincad981c2019-12-10 20:37:56 +0800222 /**
223 * Query the availability of an IMS RCS capability.
224 *
225 * @param subId the subscription ID
226 * @param capability the RCS capability to query.
227 * @return true if the RCS capability is currently available for the associated subscription,
228 * false otherwise.
229 */
James.cf Linaf3183c2019-10-24 00:59:00 +0800230 @Override
231 public boolean isAvailable(int subId,
232 @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
233 enforceReadPrivilegedPermission("isAvailable");
James.cf Lincad981c2019-12-10 20:37:56 +0800234 final long token = Binder.clearCallingIdentity();
235 try {
236 return getRcsFeatureManager(subId).isAvailable(capability);
237 } catch (com.android.ims.ImsException e) {
238 Log.e(TAG, "isAvailable: sudId=" + subId
239 + ", capability=" + capability + ", " + e.getMessage());
240 return false;
241 } finally {
242 Binder.restoreCallingIdentity(token);
243 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800244 }
245
246 @Override
247 public void requestCapabilities(int subId, List<Uri> contactNumbers,
248 IRcsUceControllerCallback c) {
249 enforceReadPrivilegedPermission("requestCapabilities");
250 }
251
252 @Override
253 public int getUcePublishState(int subId) {
254 enforceReadPrivilegedPermission("getUcePublishState");
255 return -1;
256 }
257
258 @Override
259 public boolean isUceSettingEnabled(int subId) {
260 enforceReadPrivilegedPermission("isUceSettingEnabled");
261 return false;
262 }
263
264 @Override
265 public void setUceSettingEnabled(int subId, boolean isEnabled) {
266 enforceModifyPermission();
267 }
268
269 /**
270 * Make sure either called from same process as self (phone) or IPC caller has read privilege.
271 *
272 * @throws SecurityException if the caller does not have the required permission
273 */
274 private void enforceReadPrivilegedPermission(String message) {
275 mApp.enforceCallingOrSelfPermission(
276 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);
277 }
278
279 /**
280 * Make sure the caller has the MODIFY_PHONE_STATE permission.
281 *
282 * @throws SecurityException if the caller does not have the required permission
283 */
284 private void enforceModifyPermission() {
285 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
286 }
James.cf Lincad981c2019-12-10 20:37:56 +0800287
288 /**
James.cf Lindc2d5422019-12-31 14:40:25 +0800289 * Retrieve ImsPhone instance.
James.cf Lincad981c2019-12-10 20:37:56 +0800290 *
291 * @param subId the subscription ID
James.cf Lindc2d5422019-12-31 14:40:25 +0800292 * @return The ImsPhone instance
293 * @throws ServiceSpecificException if getting ImsPhone instance failed.
James.cf Lincad981c2019-12-10 20:37:56 +0800294 */
James.cf Lindc2d5422019-12-31 14:40:25 +0800295 private ImsPhone getImsPhone(int subId) {
296 if (!ImsManager.isImsSupportedOnDevice(mApp)) {
297 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
298 "IMS is not available on device.");
299 }
James.cf Lincad981c2019-12-10 20:37:56 +0800300 Phone phone = PhoneGlobals.getPhone(subId);
301 if (phone == null) {
302 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
303 "Invalid subscription Id: " + subId);
304 }
305 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
306 if (imsPhone == null) {
James.cf Lindc2d5422019-12-31 14:40:25 +0800307 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
308 "Cannot find ImsPhone instance: " + subId);
309 }
310 return imsPhone;
311 }
312
313 /**
314 * Retrieve RcsFeatureManager instance.
315 *
316 * @param subId the subscription ID
317 * @return The RcsFeatureManager instance
318 * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
319 */
320 private RcsFeatureManager getRcsFeatureManager(int subId) {
321 if (!ImsManager.isImsSupportedOnDevice(mApp)) {
James.cf Lincad981c2019-12-10 20:37:56 +0800322 throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
James.cf Lindc2d5422019-12-31 14:40:25 +0800323 "IMS is not available on device.");
324 }
325 Phone phone = PhoneGlobals.getPhone(subId);
326 if (phone == null) {
327 throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
328 "Invalid subscription Id: " + subId);
329 }
330 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
331 if (imsPhone == null) {
332 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
James.cf Lincad981c2019-12-10 20:37:56 +0800333 "Cannot find ImsPhone instance: " + subId);
334 }
335 RcsFeatureManager rcsFeatureManager = imsPhone.getRcsManager();
336 if (rcsFeatureManager == null) {
337 throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
338 "Cannot find RcsFeatureManager instance: " + subId);
339 }
340 return rcsFeatureManager;
341 }
James.cf Linaf3183c2019-10-24 00:59:00 +0800342}