blob: 50d3a452efaa86c0c546432d37861b61b887ac95 [file] [log] [blame]
Wink Savilleef36ef62014-06-11 08:39:38 -07001/*
2 * Copyright (c) 2013 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.ims;
18
19import android.app.PendingIntent;
20import android.content.Context;
21import android.content.Intent;
Wink Savilleef36ef62014-06-11 08:39:38 -070022import android.os.IBinder;
23import android.os.IBinder.DeathRecipient;
24import android.os.Message;
25import android.os.Process;
26import android.os.RemoteException;
27import android.os.ServiceManager;
Etan Cohenaf55a402014-09-04 22:34:41 -070028import android.os.SystemProperties;
Wink Savilleef36ef62014-06-11 08:39:38 -070029import android.telephony.Rlog;
Etan Cohencfc784d2014-08-07 18:40:31 -070030import android.telephony.TelephonyManager;
Wink Savilleef36ef62014-06-11 08:39:38 -070031
32import com.android.ims.internal.IImsCallSession;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -070033import com.android.ims.internal.IImsEcbm;
34import com.android.ims.internal.IImsEcbmListener;
Wink Savilleef36ef62014-06-11 08:39:38 -070035import com.android.ims.internal.IImsRegistrationListener;
36import com.android.ims.internal.IImsService;
37import com.android.ims.internal.IImsUt;
38import com.android.ims.internal.ImsCallSession;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -050039import com.android.ims.internal.IImsConfig;
40
Etan Cohend7727462014-07-12 14:54:10 -070041import java.util.HashMap;
42
Wink Savilleef36ef62014-06-11 08:39:38 -070043/**
44 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
45 * the operator's IMS network. This class is the starting point for any IMS actions.
46 * You can acquire an instance of it with {@link #getInstance getInstance()}.</p>
47 * <p>The APIs in this class allows you to:</p>
48 *
49 * @hide
50 */
51public class ImsManager {
Etan Cohen19604c02014-08-11 14:32:57 -070052
Etan Cohenaf55a402014-09-04 22:34:41 -070053 /*
54 * Debug flag to override configuration flag
55 */
Etan Cohenb651fa52014-10-22 10:51:29 -070056 public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr";
57 public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohenea2b5832014-10-23 18:50:35 -070058 public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr";
59 public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohenaf55a402014-09-04 22:34:41 -070060
Wink Savilleef36ef62014-06-11 08:39:38 -070061 /**
62 * For accessing the IMS related service.
63 * Internal use only.
64 * @hide
65 */
Etan Cohend7727462014-07-12 14:54:10 -070066 private static final String IMS_SERVICE = "ims";
Wink Savilleef36ef62014-06-11 08:39:38 -070067
68 /**
69 * The result code to be sent back with the incoming call {@link PendingIntent}.
70 * @see #open(PendingIntent, ImsConnectionStateListener)
71 */
72 public static final int INCOMING_CALL_RESULT_CODE = 101;
73
74 /**
75 * Key to retrieve the call ID from an incoming call intent.
76 * @see #open(PendingIntent, ImsConnectionStateListener)
77 */
78 public static final String EXTRA_CALL_ID = "android:imsCallID";
79
80 /**
81 * Action to broadcast when ImsService is up.
82 * Internal use only.
83 * @hide
84 */
85 public static final String ACTION_IMS_SERVICE_UP =
86 "com.android.ims.IMS_SERVICE_UP";
87
88 /**
89 * Action to broadcast when ImsService is down.
90 * Internal use only.
91 * @hide
92 */
93 public static final String ACTION_IMS_SERVICE_DOWN =
94 "com.android.ims.IMS_SERVICE_DOWN";
95
96 /**
Etan Cohend7727462014-07-12 14:54:10 -070097 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
Etan Cohenabbd7882014-09-26 22:35:35 -070098 * A long value; the phone ID corresponding to the IMS service coming up or down.
Etan Cohend7727462014-07-12 14:54:10 -070099 * Internal use only.
100 * @hide
101 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700102 public static final String EXTRA_PHONE_ID = "android:phone_id";
Etan Cohend7727462014-07-12 14:54:10 -0700103
104 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700105 * Action for the incoming call intent for the Phone app.
106 * Internal use only.
107 * @hide
108 */
109 public static final String ACTION_IMS_INCOMING_CALL =
110 "com.android.ims.IMS_INCOMING_CALL";
111
112 /**
113 * Part of the ACTION_IMS_INCOMING_CALL intents.
114 * An integer value; service identifier obtained from {@link ImsManager#open}.
115 * Internal use only.
116 * @hide
117 */
118 public static final String EXTRA_SERVICE_ID = "android:imsServiceId";
119
120 /**
121 * Part of the ACTION_IMS_INCOMING_CALL intents.
122 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD.
123 * The value "true" indicates that the incoming call is for USSD.
124 * Internal use only.
125 * @hide
126 */
127 public static final String EXTRA_USSD = "android:ussd";
128
Wink Savilleef36ef62014-06-11 08:39:38 -0700129 private static final String TAG = "ImsManager";
130 private static final boolean DBG = true;
131
Wink Saville1e5a38a2014-10-23 10:24:46 -0700132 private static HashMap<Integer, ImsManager> sImsManagerInstances =
133 new HashMap<Integer, ImsManager>();
Etan Cohend7727462014-07-12 14:54:10 -0700134
Wink Savilleef36ef62014-06-11 08:39:38 -0700135 private Context mContext;
Etan Cohenabbd7882014-09-26 22:35:35 -0700136 private int mPhoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700137 private IImsService mImsService = null;
138 private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient();
139 // Ut interface for the supplementary service configuration
140 private ImsUt mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500141 // Interface to get/set ims config items
142 private ImsConfig mConfig = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700143
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700144 // ECBM interface
145 private ImsEcbm mEcbm = null;
146
Wink Savilleef36ef62014-06-11 08:39:38 -0700147 /**
148 * Gets a manager instance.
149 *
150 * @param context application context for creating the manager object
Etan Cohenabbd7882014-09-26 22:35:35 -0700151 * @param phoneId the phone ID for the IMS Service
152 * @return the manager instance corresponding to the phoneId
Wink Savilleef36ef62014-06-11 08:39:38 -0700153 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700154 public static ImsManager getInstance(Context context, int phoneId) {
Etan Cohend7727462014-07-12 14:54:10 -0700155 synchronized (sImsManagerInstances) {
Etan Cohenabbd7882014-09-26 22:35:35 -0700156 if (sImsManagerInstances.containsKey(phoneId))
157 return sImsManagerInstances.get(phoneId);
Wink Savilleef36ef62014-06-11 08:39:38 -0700158
Etan Cohenabbd7882014-09-26 22:35:35 -0700159 ImsManager mgr = new ImsManager(context, phoneId);
160 sImsManagerInstances.put(phoneId, mgr);
Etan Cohend7727462014-07-12 14:54:10 -0700161
162 return mgr;
163 }
Wink Savilleef36ef62014-06-11 08:39:38 -0700164 }
165
Etan Cohen45b5f312014-08-19 15:55:08 -0700166 /**
167 * Returns the user configuration of Enhanced 4G LTE Mode setting
168 */
169 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) {
Libin.Tang@motorola.com8a6bf4b2014-10-10 15:02:41 -0500170 int enabled = android.provider.Settings.Global.getInt(
171 context.getContentResolver(),
Etan Cohenb651fa52014-10-22 10:51:29 -0700172 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
Libin.Tang@motorola.com8a6bf4b2014-10-10 15:02:41 -0500173 return (enabled == 1)? true:false;
Etan Cohen45b5f312014-08-19 15:55:08 -0700174 }
175
176 /**
Etan Cohenea2b5832014-10-23 18:50:35 -0700177 * Returns a platform configuration for VoLTE which may override the user setting.
Etan Cohen45b5f312014-08-19 15:55:08 -0700178 */
Etan Cohenea2b5832014-10-23 18:50:35 -0700179 public static boolean isVolteEnabledByPlatform(Context context) {
Etan Cohenb651fa52014-10-22 10:51:29 -0700180 if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE,
181 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) {
Etan Cohenaf55a402014-09-04 22:34:41 -0700182 return true;
183 }
184
185 return
186 context.getResources().getBoolean(
Etan Cohenb651fa52014-10-22 10:51:29 -0700187 com.android.internal.R.bool.config_device_volte_available) &&
Etan Cohenaf55a402014-09-04 22:34:41 -0700188 context.getResources().getBoolean(
Etan Cohenb651fa52014-10-22 10:51:29 -0700189 com.android.internal.R.bool.config_carrier_volte_available);
190 }
191
Etan Cohenea2b5832014-10-23 18:50:35 -0700192 /**
193 * Returns a platform configuration for VT which may override the user setting.
194 *
195 * Note: VT presumes that VoLTE is enabled (these are configuration settings
196 * which must be done correctly).
197 */
Etan Cohenb651fa52014-10-22 10:51:29 -0700198 public static boolean isVtEnabledByPlatform(Context context) {
Etan Cohenea2b5832014-10-23 18:50:35 -0700199 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE,
200 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) {
201 return true;
202 }
203
Etan Cohenb651fa52014-10-22 10:51:29 -0700204 return
205 context.getResources().getBoolean(
206 com.android.internal.R.bool.config_device_vt_available) &&
207 context.getResources().getBoolean(
208 com.android.internal.R.bool.config_carrier_vt_available);
Etan Cohen45b5f312014-08-19 15:55:08 -0700209 }
210
Etan Cohenabbd7882014-09-26 22:35:35 -0700211 private ImsManager(Context context, int phoneId) {
Wink Savilleef36ef62014-06-11 08:39:38 -0700212 mContext = context;
Etan Cohenabbd7882014-09-26 22:35:35 -0700213 mPhoneId = phoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700214 createImsService(true);
215 }
216
217 /**
218 * Opens the IMS service for making calls and/or receiving generic IMS calls.
219 * The caller may make subsquent calls through {@link #makeCall}.
220 * The IMS service will register the device to the operator's network with the credentials
221 * (from ISIM) periodically in order to receive calls from the operator's network.
222 * When the IMS service receives a new call, it will send out an intent with
223 * the provided action string.
224 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call.
225 *
226 * @param serviceClass a service class specified in {@link ImsServiceClass}
227 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
228 * @param incomingCallPendingIntent When an incoming call is received,
229 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to
230 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE}
231 * as the result code and the intent to fill in the call ID; It cannot be null
232 * @param listener To listen to IMS registration events; It cannot be null
233 * @return identifier (greater than 0) for the specified service
234 * @throws NullPointerException if {@code incomingCallPendingIntent}
235 * or {@code listener} is null
236 * @throws ImsException if calling the IMS service results in an error
237 * @see #getCallId
238 * @see #getServiceId
239 */
240 public int open(int serviceClass, PendingIntent incomingCallPendingIntent,
241 ImsConnectionStateListener listener) throws ImsException {
242 checkAndThrowExceptionIfServiceUnavailable();
243
244 if (incomingCallPendingIntent == null) {
245 throw new NullPointerException("incomingCallPendingIntent can't be null");
246 }
247
248 if (listener == null) {
249 throw new NullPointerException("listener can't be null");
250 }
251
252 int result = 0;
253
254 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700255 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent,
Wink Savilleef36ef62014-06-11 08:39:38 -0700256 createRegistrationListenerProxy(serviceClass, listener));
257 } catch (RemoteException e) {
258 throw new ImsException("open()", e,
259 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
260 }
261
262 if (result <= 0) {
263 // If the return value is a minus value,
264 // it means that an error occurred in the service.
265 // So, it needs to convert to the reason code specified in ImsReasonInfo.
266 throw new ImsException("open()", (result * (-1)));
267 }
268
269 return result;
270 }
271
272 /**
273 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls.
274 * All the resources that were allocated to the service are also released.
275 *
276 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open}
277 * @throws ImsException if calling the IMS service results in an error
278 */
279 public void close(int serviceId) throws ImsException {
280 checkAndThrowExceptionIfServiceUnavailable();
281
282 try {
283 mImsService.close(serviceId);
284 } catch (RemoteException e) {
285 throw new ImsException("close()", e,
286 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
287 } finally {
288 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500289 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700290 mEcbm = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700291 }
292 }
293
294 /**
295 * Gets the configuration interface to provision / withdraw the supplementary service settings.
296 *
297 * @param serviceId a service id which is obtained from {@link ImsManager#open}
298 * @return the Ut interface instance
299 * @throws ImsException if getting the Ut interface results in an error
300 */
301 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId)
302 throws ImsException {
303 // FIXME: manage the multiple Ut interfaces based on the service id
304 if (mUt == null) {
305 checkAndThrowExceptionIfServiceUnavailable();
306
307 try {
308 IImsUt iUt = mImsService.getUtInterface(serviceId);
309
310 if (iUt == null) {
311 throw new ImsException("getSupplementaryServiceConfiguration()",
312 ImsReasonInfo.CODE_UT_NOT_SUPPORTED);
313 }
314
315 mUt = new ImsUt(iUt);
316 } catch (RemoteException e) {
317 throw new ImsException("getSupplementaryServiceConfiguration()", e,
318 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
319 }
320 }
321
322 return mUt;
323 }
324
325 /**
326 * Checks if the IMS service has successfully registered to the IMS network
327 * with the specified service & call type.
328 *
329 * @param serviceId a service id which is obtained from {@link ImsManager#open}
330 * @param serviceType a service type that is specified in {@link ImsCallProfile}
331 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
332 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
333 * @param callType a call type that is specified in {@link ImsCallProfile}
334 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
335 * {@link ImsCallProfile#CALL_TYPE_VOICE}
336 * {@link ImsCallProfile#CALL_TYPE_VT}
337 * {@link ImsCallProfile#CALL_TYPE_VS}
338 * @return true if the specified service id is connected to the IMS network;
339 * false otherwise
340 * @throws ImsException if calling the IMS service results in an error
341 */
342 public boolean isConnected(int serviceId, int serviceType, int callType)
343 throws ImsException {
344 checkAndThrowExceptionIfServiceUnavailable();
345
346 try {
347 return mImsService.isConnected(serviceId, serviceType, callType);
348 } catch (RemoteException e) {
349 throw new ImsException("isServiceConnected()", e,
350 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
351 }
352 }
353
354 /**
355 * Checks if the specified IMS service is opend.
356 *
357 * @param serviceId a service id which is obtained from {@link ImsManager#open}
358 * @return true if the specified service id is opened; false otherwise
359 * @throws ImsException if calling the IMS service results in an error
360 */
361 public boolean isOpened(int serviceId) throws ImsException {
362 checkAndThrowExceptionIfServiceUnavailable();
363
364 try {
365 return mImsService.isOpened(serviceId);
366 } catch (RemoteException e) {
367 throw new ImsException("isOpened()", e,
368 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
369 }
370 }
371
372 /**
373 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
374 *
375 * @param serviceId a service id which is obtained from {@link ImsManager#open}
376 * @param serviceType a service type that is specified in {@link ImsCallProfile}
377 * {@link ImsCallProfile#SERVICE_TYPE_NONE}
378 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
379 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
380 * @param callType a call type that is specified in {@link ImsCallProfile}
381 * {@link ImsCallProfile#CALL_TYPE_VOICE}
382 * {@link ImsCallProfile#CALL_TYPE_VT}
383 * {@link ImsCallProfile#CALL_TYPE_VT_TX}
384 * {@link ImsCallProfile#CALL_TYPE_VT_RX}
385 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
386 * {@link ImsCallProfile#CALL_TYPE_VS}
387 * {@link ImsCallProfile#CALL_TYPE_VS_TX}
388 * {@link ImsCallProfile#CALL_TYPE_VS_RX}
389 * @return a {@link ImsCallProfile} object
390 * @throws ImsException if calling the IMS service results in an error
391 */
392 public ImsCallProfile createCallProfile(int serviceId,
393 int serviceType, int callType) throws ImsException {
394 checkAndThrowExceptionIfServiceUnavailable();
395
396 try {
397 return mImsService.createCallProfile(serviceId, serviceType, callType);
398 } catch (RemoteException e) {
399 throw new ImsException("createCallProfile()", e,
400 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
401 }
402 }
403
404 /**
405 * Creates a {@link ImsCall} to make a call.
406 *
407 * @param serviceId a service id which is obtained from {@link ImsManager#open}
408 * @param profile a call profile to make the call
409 * (it contains service type, call type, media information, etc.)
410 * @param participants participants to invite the conference call
411 * @param listener listen to the call events from {@link ImsCall}
412 * @return a {@link ImsCall} object
413 * @throws ImsException if calling the IMS service results in an error
414 */
415 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees,
416 ImsCall.Listener listener) throws ImsException {
417 if (DBG) {
418 log("makeCall :: serviceId=" + serviceId
419 + ", profile=" + profile + ", callees=" + callees);
420 }
421
422 checkAndThrowExceptionIfServiceUnavailable();
423
424 ImsCall call = new ImsCall(mContext, profile);
425
426 call.setListener(listener);
427 ImsCallSession session = createCallSession(serviceId, profile);
428
429 if ((callees != null) && (callees.length == 1)) {
430 call.start(session, callees[0]);
431 } else {
432 call.start(session, callees);
433 }
434
435 return call;
436 }
437
438 /**
439 * Creates a {@link ImsCall} to take an incoming call.
440 *
441 * @param serviceId a service id which is obtained from {@link ImsManager#open}
442 * @param incomingCallIntent the incoming call broadcast intent
443 * @param listener to listen to the call events from {@link ImsCall}
444 * @return a {@link ImsCall} object
445 * @throws ImsException if calling the IMS service results in an error
446 */
447 public ImsCall takeCall(int serviceId, Intent incomingCallIntent,
448 ImsCall.Listener listener) throws ImsException {
449 if (DBG) {
450 log("takeCall :: serviceId=" + serviceId
451 + ", incomingCall=" + incomingCallIntent);
452 }
453
454 checkAndThrowExceptionIfServiceUnavailable();
455
456 if (incomingCallIntent == null) {
457 throw new ImsException("Can't retrieve session with null intent",
458 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
459 }
460
461 int incomingServiceId = getServiceId(incomingCallIntent);
462
463 if (serviceId != incomingServiceId) {
464 throw new ImsException("Service id is mismatched in the incoming call intent",
465 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
466 }
467
468 String callId = getCallId(incomingCallIntent);
469
470 if (callId == null) {
471 throw new ImsException("Call ID missing in the incoming call intent",
472 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
473 }
474
475 try {
476 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId);
477
478 if (session == null) {
479 throw new ImsException("No pending session for the call",
480 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL);
481 }
482
483 ImsCall call = new ImsCall(mContext, session.getCallProfile());
484
485 call.attachSession(new ImsCallSession(session));
486 call.setListener(listener);
487
488 return call;
489 } catch (Throwable t) {
490 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED);
491 }
492 }
493
494 /**
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500495 * Gets the config interface to get/set service/capability parameters.
496 *
497 * @return the ImsConfig instance.
498 * @throws ImsException if getting the setting interface results in an error.
499 */
500 public ImsConfig getConfigInterface() throws ImsException {
501
502 if (mConfig == null) {
503 checkAndThrowExceptionIfServiceUnavailable();
504
505 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700506 IImsConfig config = mImsService.getConfigInterface(mPhoneId);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500507 if (config == null) {
508 throw new ImsException("getConfigInterface()",
509 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
510 }
Libin.Tang@motorola.com54953c72014-08-07 15:02:08 -0500511 mConfig = new ImsConfig(config, mContext);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500512 } catch (RemoteException e) {
513 throw new ImsException("getConfigInterface()", e,
514 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
515 }
516 }
517 if (DBG) log("getConfigInterface(), mConfig= " + mConfig);
518 return mConfig;
519 }
520
Shriram Ganeshc403b7b2014-08-14 14:18:57 +0530521 public void setUiTTYMode(int serviceId, int uiTtyMode, Message onComplete)
522 throws ImsException {
523
524 checkAndThrowExceptionIfServiceUnavailable();
525
526 try {
527 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete);
528 } catch (RemoteException e) {
529 throw new ImsException("setTTYMode()", e,
530 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
531 }
532 }
533
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500534 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700535 * Gets the call ID from the specified incoming call broadcast intent.
536 *
537 * @param incomingCallIntent the incoming call broadcast intent
538 * @return the call ID or null if the intent does not contain it
539 */
540 private static String getCallId(Intent incomingCallIntent) {
541 if (incomingCallIntent == null) {
542 return null;
543 }
544
545 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
546 }
547
548 /**
549 * Gets the service type from the specified incoming call broadcast intent.
550 *
551 * @param incomingCallIntent the incoming call broadcast intent
552 * @return the service identifier or -1 if the intent does not contain it
553 */
554 private static int getServiceId(Intent incomingCallIntent) {
555 if (incomingCallIntent == null) {
556 return (-1);
557 }
558
559 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1);
560 }
561
562 /**
563 * Binds the IMS service only if the service is not created.
564 */
565 private void checkAndThrowExceptionIfServiceUnavailable()
566 throws ImsException {
567 if (mImsService == null) {
568 createImsService(true);
569
570 if (mImsService == null) {
571 throw new ImsException("Service is unavailable",
572 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
573 }
574 }
575 }
576
Etan Cohenabbd7882014-09-26 22:35:35 -0700577 private static String getImsServiceName(int phoneId) {
578 // TODO: MSIM implementation needs to decide on service name as a function of phoneId
Etan Cohend7727462014-07-12 14:54:10 -0700579 return IMS_SERVICE;
580 }
581
Wink Savilleef36ef62014-06-11 08:39:38 -0700582 /**
583 * Binds the IMS service to make/receive the call.
584 */
585 private void createImsService(boolean checkService) {
586 if (checkService) {
Etan Cohenabbd7882014-09-26 22:35:35 -0700587 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -0700588
589 if (binder == null) {
590 return;
591 }
592 }
593
Etan Cohenabbd7882014-09-26 22:35:35 -0700594 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -0700595
596 if (b != null) {
597 try {
598 b.linkToDeath(mDeathRecipient, 0);
599 } catch (RemoteException e) {
600 }
601 }
602
603 mImsService = IImsService.Stub.asInterface(b);
604 }
605
606 /**
607 * Creates a {@link ImsCallSession} with the specified call profile.
608 * Use other methods, if applicable, instead of interacting with
609 * {@link ImsCallSession} directly.
610 *
611 * @param serviceId a service id which is obtained from {@link ImsManager#open}
612 * @param profile a call profile to make the call
613 */
614 private ImsCallSession createCallSession(int serviceId,
615 ImsCallProfile profile) throws ImsException {
616 try {
617 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null));
618 } catch (RemoteException e) {
619 return null;
620 }
621 }
622
623 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass,
624 ImsConnectionStateListener listener) {
625 ImsRegistrationListenerProxy proxy =
626 new ImsRegistrationListenerProxy(serviceClass, listener);
627 return proxy;
628 }
629
630 private void log(String s) {
631 Rlog.d(TAG, s);
632 }
633
634 private void loge(String s) {
635 Rlog.e(TAG, s);
636 }
637
638 private void loge(String s, Throwable t) {
639 Rlog.e(TAG, s, t);
640 }
641
642 /**
ram7da5a112014-07-16 20:59:27 +0530643 * Used for turning on IMS.if its off already
644 */
645 public void turnOnIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -0700646 checkAndThrowExceptionIfServiceUnavailable();
647
ram7da5a112014-07-16 20:59:27 +0530648 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700649 mImsService.turnOnIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +0530650 } catch (RemoteException e) {
651 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
652 }
653 }
654
Etan Cohencfc784d2014-08-07 18:40:31 -0700655 public void setAdvanced4GMode(boolean turnOn) throws ImsException {
656 checkAndThrowExceptionIfServiceUnavailable();
657
658 ImsConfig config = getConfigInterface();
659 if (config != null) {
660 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
661 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
Etan Cohenb651fa52014-10-22 10:51:29 -0700662 if (isVtEnabledByPlatform(mContext)) {
663 // TODO: once VT is available on platform replace the '1' with the current
664 // user configuration of VT.
665 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
666 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
667 }
Etan Cohencfc784d2014-08-07 18:40:31 -0700668 }
669
670 if (turnOn) {
671 turnOnIms();
672 } else if (mContext.getResources().getBoolean(
673 com.android.internal.R.bool.imsServiceAllowTurnOff)) {
674 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms");
675 turnOffIms();
676 }
677 }
678
ram7da5a112014-07-16 20:59:27 +0530679 /**
680 * Used for turning off IMS completely in order to make the device CSFB'ed.
681 * Once turned off, all calls will be over CS.
682 */
683 public void turnOffIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -0700684 checkAndThrowExceptionIfServiceUnavailable();
685
ram7da5a112014-07-16 20:59:27 +0530686 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700687 mImsService.turnOffIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +0530688 } catch (RemoteException e) {
689 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
690 }
691 }
692
693 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700694 * Death recipient class for monitoring IMS service.
695 */
696 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient {
697 @Override
698 public void binderDied() {
699 mImsService = null;
700 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500701 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700702 mEcbm = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700703
704 if (mContext != null) {
Etan Cohend7727462014-07-12 14:54:10 -0700705 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN);
Etan Cohenabbd7882014-09-26 22:35:35 -0700706 intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
Etan Cohend7727462014-07-12 14:54:10 -0700707 mContext.sendBroadcast(new Intent(intent));
Wink Savilleef36ef62014-06-11 08:39:38 -0700708 }
709 }
710 }
711
712 /**
713 * Adapter class for {@link IImsRegistrationListener}.
714 */
715 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub {
716 private int mServiceClass;
717 private ImsConnectionStateListener mListener;
718
719 public ImsRegistrationListenerProxy(int serviceClass,
720 ImsConnectionStateListener listener) {
721 mServiceClass = serviceClass;
722 mListener = listener;
723 }
724
725 public boolean isSameProxy(int serviceClass) {
726 return (mServiceClass == serviceClass);
727 }
728
729 @Override
730 public void registrationConnected() {
731 if (DBG) {
732 log("registrationConnected ::");
733 }
734
735 if (mListener != null) {
736 mListener.onImsConnected();
737 }
738 }
739
740 @Override
741 public void registrationDisconnected() {
742 if (DBG) {
743 log("registrationDisconnected ::");
744 }
745
746 if (mListener != null) {
747 mListener.onImsDisconnected();
748 }
749 }
750
751 @Override
752 public void registrationResumed() {
753 if (DBG) {
754 log("registrationResumed ::");
755 }
756
757 if (mListener != null) {
758 mListener.onImsResumed();
759 }
760 }
761
762 @Override
763 public void registrationSuspended() {
764 if (DBG) {
765 log("registrationSuspended ::");
766 }
767
768 if (mListener != null) {
769 mListener.onImsSuspended();
770 }
771 }
772
773 @Override
774 public void registrationServiceCapabilityChanged(int serviceClass, int event) {
775 log("registrationServiceCapabilityChanged :: serviceClass=" +
776 serviceClass + ", event=" + event);
777
778 if (mListener != null) {
779 mListener.onImsConnected();
780 }
781 }
ram7da5a112014-07-16 20:59:27 +0530782
783 @Override
784 public void registrationFeatureCapabilityChanged(int serviceClass,
785 int[] enabledFeatures, int[] disabledFeatures) {
786 log("registrationFeatureCapabilityChanged :: serviceClass=" +
787 serviceClass);
Libin.Tang@motorola.come2296782014-08-19 14:20:01 -0500788 if (mListener != null) {
789 mListener.onFeatureCapabilityChanged(serviceClass,
790 enabledFeatures, disabledFeatures);
791 }
ram7da5a112014-07-16 20:59:27 +0530792 }
793
Wink Savilleef36ef62014-06-11 08:39:38 -0700794 }
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700795 /**
796 * Gets the ECBM interface to request ECBM exit.
797 *
798 * @param serviceId a service id which is obtained from {@link ImsManager#open}
799 * @return the ECBM interface instance
800 * @throws ImsException if getting the ECBM interface results in an error
801 */
802 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException {
803 if (mEcbm == null) {
804 checkAndThrowExceptionIfServiceUnavailable();
805
806 try {
807 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId);
808
809 if (iEcbm == null) {
810 throw new ImsException("getEcbmInterface()",
811 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED);
812 }
813 mEcbm = new ImsEcbm(iEcbm);
814 } catch (RemoteException e) {
815 throw new ImsException("getEcbmInterface()", e,
816 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
817 }
818 }
819 return mEcbm;
820 }
Wink Savilleef36ef62014-06-11 08:39:38 -0700821}