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