ImsService.java revision cd3c59c6400678adcd175f8a8d1a0d32388ca44e
1/* 2 * Copyright (C) 2017 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 android.telephony.ims; 18 19import android.app.PendingIntent; 20import android.content.Intent; 21import android.os.IBinder; 22import android.os.Message; 23import android.os.RemoteException; 24import android.telephony.CarrierConfigManager; 25import android.telephony.ims.feature.ImsFeature; 26import android.telephony.ims.feature.MMTelFeature; 27import android.telephony.ims.feature.RcsFeature; 28import android.util.Log; 29import android.util.SparseArray; 30 31import com.android.ims.ImsCallProfile; 32import com.android.ims.internal.IImsCallSession; 33import com.android.ims.internal.IImsCallSessionListener; 34import com.android.ims.internal.IImsConfig; 35import com.android.ims.internal.IImsEcbm; 36import com.android.ims.internal.IImsFeatureStatusCallback; 37import com.android.ims.internal.IImsMultiEndpoint; 38import com.android.ims.internal.IImsRegistrationListener; 39import com.android.ims.internal.IImsServiceController; 40import com.android.ims.internal.IImsServiceFeatureListener; 41import com.android.ims.internal.IImsUt; 42import com.android.internal.annotations.VisibleForTesting; 43 44import static android.Manifest.permission.MODIFY_PHONE_STATE; 45import static android.Manifest.permission.READ_PHONE_STATE; 46 47/** 48 * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend 49 * ImsService must register the service in their AndroidManifest to be detected by the framework. 50 * First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE" 51 * permission. Then, the ImsService definition in the manifest must follow the following format: 52 * 53 * ... 54 * <service android:name=".EgImsService" 55 * android:permission="android.permission.BIND_IMS_SERVICE" > 56 * <!-- Apps must declare which features they support as metadata. The different categories are 57 * defined below. In this example, the RCS_FEATURE feature is supported. --> 58 * <meta-data android:name="android.telephony.ims.RCS_FEATURE" android:value="true" /> 59 * <intent-filter> 60 * <action android:name="android.telephony.ims.ImsService" /> 61 * </intent-filter> 62 * </service> 63 * ... 64 * 65 * The telephony framework will then bind to the ImsService you have defined in your manifest 66 * if you are either: 67 * 1) Defined as the default ImsService for the device in the device overlay using 68 * "config_ims_package". 69 * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using 70 * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}. 71 * 72 * The features that are currently supported in an ImsService are: 73 * - RCS_FEATURE: This ImsService implements the {@link RcsFeature} class. 74 * - MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class. 75 * - EMERGENCY_MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class and will be 76 * available to place emergency calls at all times. This MUST be implemented by the default 77 * ImsService provided in the device overlay. 78 * 79 * @hide 80 */ 81public abstract class ImsService extends ImsServiceBase { 82 83 private static final String LOG_TAG = "ImsService"; 84 85 /** 86 * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService. 87 */ 88 public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService"; 89 90 // A map of slot Id -> Set of features corresponding to that slot. 91 private final SparseArray<SparseArray<ImsFeature>> mFeatures = new SparseArray<>(); 92 93 // Implements all supported features as a flat interface. 94 protected final IBinder mImsServiceController = new IImsServiceController.Stub() { 95 96 @Override 97 public void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c) 98 throws RemoteException { 99 synchronized (mFeatures) { 100 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createImsFeature"); 101 onCreateImsFeatureInternal(slotId, feature, c); 102 } 103 } 104 105 @Override 106 public void removeImsFeature(int slotId, int feature) throws RemoteException { 107 synchronized (mFeatures) { 108 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "removeImsFeature"); 109 onRemoveImsFeatureInternal(slotId, feature); 110 } 111 } 112 113 @Override 114 public int startSession(int slotId, int featureType, PendingIntent incomingCallIntent, 115 IImsRegistrationListener listener) throws RemoteException { 116 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "startSession"); 117 synchronized (mFeatures) { 118 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 119 if (feature != null) { 120 return feature.startSession(incomingCallIntent, listener); 121 } 122 } 123 return 0; 124 } 125 126 @Override 127 public void endSession(int slotId, int featureType, int sessionId) throws RemoteException { 128 synchronized (mFeatures) { 129 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "endSession"); 130 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 131 if (feature != null) { 132 feature.endSession(sessionId); 133 } 134 } 135 } 136 137 @Override 138 public boolean isConnected(int slotId, int featureType, int callSessionType, int callType) 139 throws RemoteException { 140 enforceCallingOrSelfPermission(READ_PHONE_STATE, "isConnected"); 141 synchronized (mFeatures) { 142 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 143 if (feature != null) { 144 return feature.isConnected(callSessionType, callType); 145 } 146 } 147 return false; 148 } 149 150 @Override 151 public boolean isOpened(int slotId, int featureType) throws RemoteException { 152 enforceCallingOrSelfPermission(READ_PHONE_STATE, "isOpened"); 153 synchronized (mFeatures) { 154 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 155 if (feature != null) { 156 return feature.isOpened(); 157 } 158 } 159 return false; 160 } 161 162 @Override 163 public int getFeatureStatus(int slotId, int featureType) throws RemoteException { 164 enforceCallingOrSelfPermission(READ_PHONE_STATE, "getFeatureStatus"); 165 int status = ImsFeature.STATE_NOT_AVAILABLE; 166 synchronized (mFeatures) { 167 SparseArray<ImsFeature> featureMap = mFeatures.get(slotId); 168 if (featureMap != null) { 169 ImsFeature feature = getImsFeatureFromType(featureMap, featureType); 170 if (feature != null) { 171 status = feature.getFeatureState(); 172 } 173 } 174 } 175 return status; 176 } 177 178 @Override 179 public void addRegistrationListener(int slotId, int featureType, 180 IImsRegistrationListener listener) throws RemoteException { 181 enforceCallingOrSelfPermission(READ_PHONE_STATE, "addRegistrationListener"); 182 synchronized (mFeatures) { 183 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 184 if (feature != null) { 185 feature.addRegistrationListener(listener); 186 } 187 } 188 } 189 190 @Override 191 public void removeRegistrationListener(int slotId, int featureType, 192 IImsRegistrationListener listener) throws RemoteException { 193 enforceCallingOrSelfPermission(READ_PHONE_STATE, "removeRegistrationListener"); 194 synchronized (mFeatures) { 195 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 196 if (feature != null) { 197 feature.removeRegistrationListener(listener); 198 } 199 } 200 } 201 202 @Override 203 public ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId, 204 int callSessionType, int callType) throws RemoteException { 205 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallProfile"); 206 synchronized (mFeatures) { 207 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 208 if (feature != null) { 209 return feature.createCallProfile(sessionId, callSessionType, callType); 210 } 211 } 212 return null; 213 } 214 215 @Override 216 public IImsCallSession createCallSession(int slotId, int featureType, int sessionId, 217 ImsCallProfile profile, IImsCallSessionListener listener) throws RemoteException { 218 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallSession"); 219 synchronized (mFeatures) { 220 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 221 if (feature != null) { 222 return feature.createCallSession(sessionId, profile, listener); 223 } 224 } 225 return null; 226 } 227 228 @Override 229 public IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId, 230 String callId) throws RemoteException { 231 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getPendingCallSession"); 232 synchronized (mFeatures) { 233 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 234 if (feature != null) { 235 return feature.getPendingCallSession(sessionId, callId); 236 } 237 } 238 return null; 239 } 240 241 @Override 242 public IImsUt getUtInterface(int slotId, int featureType) 243 throws RemoteException { 244 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getUtInterface"); 245 synchronized (mFeatures) { 246 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 247 if (feature != null) { 248 return feature.getUtInterface(); 249 } 250 } 251 return null; 252 } 253 254 @Override 255 public IImsConfig getConfigInterface(int slotId, int featureType) 256 throws RemoteException { 257 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getConfigInterface"); 258 synchronized (mFeatures) { 259 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 260 if (feature != null) { 261 return feature.getConfigInterface(); 262 } 263 } 264 return null; 265 } 266 267 @Override 268 public void turnOnIms(int slotId, int featureType) throws RemoteException { 269 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOnIms"); 270 synchronized (mFeatures) { 271 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 272 if (feature != null) { 273 feature.turnOnIms(); 274 } 275 } 276 } 277 278 @Override 279 public void turnOffIms(int slotId, int featureType) throws RemoteException { 280 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOffIms"); 281 synchronized (mFeatures) { 282 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 283 if (feature != null) { 284 feature.turnOffIms(); 285 } 286 } 287 } 288 289 @Override 290 public IImsEcbm getEcbmInterface(int slotId, int featureType) 291 throws RemoteException { 292 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getEcbmInterface"); 293 synchronized (mFeatures) { 294 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 295 if (feature != null) { 296 return feature.getEcbmInterface(); 297 } 298 } 299 return null; 300 } 301 302 @Override 303 public void setUiTTYMode(int slotId, int featureType, int uiTtyMode, Message onComplete) 304 throws RemoteException { 305 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "setUiTTYMode"); 306 synchronized (mFeatures) { 307 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 308 if (feature != null) { 309 feature.setUiTTYMode(uiTtyMode, onComplete); 310 } 311 } 312 } 313 314 @Override 315 public IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType) 316 throws RemoteException { 317 enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getMultiEndpointInterface"); 318 synchronized (mFeatures) { 319 MMTelFeature feature = resolveMMTelFeature(slotId, featureType); 320 if (feature != null) { 321 return feature.getMultiEndpointInterface(); 322 } 323 } 324 return null; 325 } 326 327 }; 328 329 @Override 330 public IBinder onBind(Intent intent) { 331 if(SERVICE_INTERFACE.equals(intent.getAction())) { 332 return mImsServiceController; 333 } 334 return null; 335 } 336 337 /** 338 * Called from the ImsResolver to create the requested ImsFeature, as defined by the slot and 339 * featureType 340 * @param slotId An integer representing which SIM slot the ImsFeature is assigned to. 341 * @param featureType An integer representing the type of ImsFeature being created. This is 342 * defined in {@link ImsFeature}. 343 */ 344 // Be sure to lock on mFeatures before accessing this method 345 private void onCreateImsFeatureInternal(int slotId, int featureType, 346 IImsFeatureStatusCallback c) { 347 SparseArray<ImsFeature> featureMap = mFeatures.get(slotId); 348 if (featureMap == null) { 349 featureMap = new SparseArray<>(); 350 mFeatures.put(slotId, featureMap); 351 } 352 ImsFeature f = makeImsFeature(slotId, featureType); 353 if (f != null) { 354 f.setImsFeatureStatusCallback(c); 355 featureMap.put(featureType, f); 356 } 357 358 } 359 /** 360 * Called from the ImsResolver to remove an existing ImsFeature, as defined by the slot and 361 * featureType. 362 * @param slotId An integer representing which SIM slot the ImsFeature is assigned to. 363 * @param featureType An integer representing the type of ImsFeature being removed. This is 364 * defined in {@link ImsFeature}. 365 */ 366 // Be sure to lock on mFeatures before accessing this method 367 private void onRemoveImsFeatureInternal(int slotId, int featureType) { 368 SparseArray<ImsFeature> featureMap = mFeatures.get(slotId); 369 if (featureMap == null) { 370 return; 371 } 372 373 ImsFeature featureToRemove = getImsFeatureFromType(featureMap, featureType); 374 if (featureToRemove != null) { 375 featureMap.remove(featureType); 376 featureToRemove.notifyFeatureRemoved(slotId); 377 // Remove reference to Binder 378 featureToRemove.setImsFeatureStatusCallback(null); 379 } 380 } 381 382 // Be sure to lock on mFeatures before accessing this method 383 private MMTelFeature resolveMMTelFeature(int slotId, int featureType) { 384 SparseArray<ImsFeature> features = getImsFeatureMap(slotId); 385 MMTelFeature feature = null; 386 if (features != null) { 387 feature = resolveImsFeature(features, featureType, MMTelFeature.class); 388 } 389 return feature; 390 } 391 392 // Be sure to lock on mFeatures before accessing this method 393 private <T extends ImsFeature> T resolveImsFeature(SparseArray<ImsFeature> set, int featureType, 394 Class<T> className) { 395 ImsFeature feature = getImsFeatureFromType(set, featureType); 396 if (feature == null) { 397 return null; 398 } 399 try { 400 return className.cast(feature); 401 } catch (ClassCastException e) 402 { 403 Log.e(LOG_TAG, "Can not cast ImsFeature! Exception: " + e.getMessage()); 404 } 405 return null; 406 } 407 408 @VisibleForTesting 409 // Be sure to lock on mFeatures before accessing this method 410 public SparseArray<ImsFeature> getImsFeatureMap(int slotId) { 411 return mFeatures.get(slotId); 412 } 413 414 @VisibleForTesting 415 // Be sure to lock on mFeatures before accessing this method 416 public ImsFeature getImsFeatureFromType(SparseArray<ImsFeature> set, int featureType) { 417 return set.get(featureType); 418 } 419 420 private ImsFeature makeImsFeature(int slotId, int feature) { 421 switch (feature) { 422 case ImsFeature.EMERGENCY_MMTEL: { 423 return onCreateEmergencyMMTelImsFeature(slotId); 424 } 425 case ImsFeature.MMTEL: { 426 return onCreateMMTelImsFeature(slotId); 427 } 428 case ImsFeature.RCS: { 429 return onCreateRcsFeature(slotId); 430 } 431 } 432 // Tried to create feature that is not defined. 433 return null; 434 } 435 436 /** 437 * @return An implementation of MMTelFeature that will be used by the system for MMTel 438 * functionality. Must be able to handle emergency calls at any time as well. 439 */ 440 public abstract MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId); 441 442 /** 443 * @return An implementation of MMTelFeature that will be used by the system for MMTel 444 * functionality. 445 */ 446 public abstract MMTelFeature onCreateMMTelImsFeature(int slotId); 447 448 /** 449 * @return An implementation of RcsFeature that will be used by the system for RCS. 450 */ 451 public abstract RcsFeature onCreateRcsFeature(int slotId); 452} 453