blob: 689ea05842f0ad55b8df80cfeba453e40a6d8acf [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;
28import android.telephony.Rlog;
Etan Cohencfc784d2014-08-07 18:40:31 -070029import android.telephony.TelephonyManager;
Wink Savilleef36ef62014-06-11 08:39:38 -070030
31import com.android.ims.internal.IImsCallSession;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -070032import com.android.ims.internal.IImsEcbm;
33import com.android.ims.internal.IImsEcbmListener;
Wink Savilleef36ef62014-06-11 08:39:38 -070034import com.android.ims.internal.IImsRegistrationListener;
35import com.android.ims.internal.IImsService;
36import com.android.ims.internal.IImsUt;
37import com.android.ims.internal.ImsCallSession;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -050038import com.android.ims.internal.IImsConfig;
39
Etan Cohend7727462014-07-12 14:54:10 -070040import java.util.HashMap;
41
Wink Savilleef36ef62014-06-11 08:39:38 -070042/**
43 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
44 * the operator's IMS network. This class is the starting point for any IMS actions.
45 * You can acquire an instance of it with {@link #getInstance getInstance()}.</p>
46 * <p>The APIs in this class allows you to:</p>
47 *
48 * @hide
49 */
50public class ImsManager {
Etan Cohen19604c02014-08-11 14:32:57 -070051 /*
52 * Shared preference constants storing the "Enhanced 4G LTE Mode" configuration
53 */
54 public static final String IMS_SHARED_PREFERENCES = "IMS_PREFERENCES";
55 public static final String KEY_IMS_ON = "IMS";
Etan Cohen45b5f312014-08-19 15:55:08 -070056 public static final boolean IMS_DEFAULT_SETTING = true;
Etan Cohen19604c02014-08-11 14:32:57 -070057
Wink Savilleef36ef62014-06-11 08:39:38 -070058 /**
59 * For accessing the IMS related service.
60 * Internal use only.
61 * @hide
62 */
Etan Cohend7727462014-07-12 14:54:10 -070063 private static final String IMS_SERVICE = "ims";
Wink Savilleef36ef62014-06-11 08:39:38 -070064
65 /**
66 * The result code to be sent back with the incoming call {@link PendingIntent}.
67 * @see #open(PendingIntent, ImsConnectionStateListener)
68 */
69 public static final int INCOMING_CALL_RESULT_CODE = 101;
70
71 /**
72 * Key to retrieve the call ID from an incoming call intent.
73 * @see #open(PendingIntent, ImsConnectionStateListener)
74 */
75 public static final String EXTRA_CALL_ID = "android:imsCallID";
76
77 /**
78 * Action to broadcast when ImsService is up.
79 * Internal use only.
80 * @hide
81 */
82 public static final String ACTION_IMS_SERVICE_UP =
83 "com.android.ims.IMS_SERVICE_UP";
84
85 /**
86 * Action to broadcast when ImsService is down.
87 * Internal use only.
88 * @hide
89 */
90 public static final String ACTION_IMS_SERVICE_DOWN =
91 "com.android.ims.IMS_SERVICE_DOWN";
92
93 /**
Etan Cohend7727462014-07-12 14:54:10 -070094 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
95 * A long value; the subId corresponding to the IMS service coming up or down.
96 * Internal use only.
97 * @hide
98 */
99 public static final String EXTRA_SUBID = "android:subid";
100
101 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700102 * Action for the incoming call intent for the Phone app.
103 * Internal use only.
104 * @hide
105 */
106 public static final String ACTION_IMS_INCOMING_CALL =
107 "com.android.ims.IMS_INCOMING_CALL";
108
109 /**
110 * Part of the ACTION_IMS_INCOMING_CALL intents.
111 * An integer value; service identifier obtained from {@link ImsManager#open}.
112 * Internal use only.
113 * @hide
114 */
115 public static final String EXTRA_SERVICE_ID = "android:imsServiceId";
116
117 /**
118 * Part of the ACTION_IMS_INCOMING_CALL intents.
119 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD.
120 * The value "true" indicates that the incoming call is for USSD.
121 * Internal use only.
122 * @hide
123 */
124 public static final String EXTRA_USSD = "android:ussd";
125
Wink Savilleef36ef62014-06-11 08:39:38 -0700126 private static final String TAG = "ImsManager";
127 private static final boolean DBG = true;
128
Etan Cohend7727462014-07-12 14:54:10 -0700129 private static HashMap<Long, ImsManager> sImsManagerInstances =
130 new HashMap<Long, ImsManager>();
131
Wink Savilleef36ef62014-06-11 08:39:38 -0700132 private Context mContext;
Etan Cohend7727462014-07-12 14:54:10 -0700133 private long mSubId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700134 private IImsService mImsService = null;
135 private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient();
136 // Ut interface for the supplementary service configuration
137 private ImsUt mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500138 // Interface to get/set ims config items
139 private ImsConfig mConfig = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700140
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700141 // ECBM interface
142 private ImsEcbm mEcbm = null;
143
Wink Savilleef36ef62014-06-11 08:39:38 -0700144 /**
145 * Gets a manager instance.
146 *
147 * @param context application context for creating the manager object
Etan Cohend7727462014-07-12 14:54:10 -0700148 * @param subId the subscription ID for the IMS Service
149 * @return the manager instance corresponding to the subId
Wink Savilleef36ef62014-06-11 08:39:38 -0700150 */
Etan Cohend7727462014-07-12 14:54:10 -0700151 public static ImsManager getInstance(Context context, long subId) {
152 synchronized (sImsManagerInstances) {
153 if (sImsManagerInstances.containsKey(subId))
154 return sImsManagerInstances.get(subId);
Wink Savilleef36ef62014-06-11 08:39:38 -0700155
Etan Cohend7727462014-07-12 14:54:10 -0700156 ImsManager mgr = new ImsManager(context, subId);
157 sImsManagerInstances.put(subId, mgr);
158
159 return mgr;
160 }
Wink Savilleef36ef62014-06-11 08:39:38 -0700161 }
162
Etan Cohen45b5f312014-08-19 15:55:08 -0700163 /**
164 * Returns the user configuration of Enhanced 4G LTE Mode setting
165 */
166 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) {
167 return context.getSharedPreferences(IMS_SHARED_PREFERENCES,
168 Context.MODE_WORLD_READABLE).getBoolean(KEY_IMS_ON,
169 IMS_DEFAULT_SETTING);
170 }
171
172 /**
173 * Returns a platform configuration which may override the user setting.
174 */
175 public static boolean isEnhanced4gLteModeSettingEnabledByPlatform(Context context) {
176 return context.getResources().getBoolean(
177 com.android.internal.R.bool.config_mobile_allow_volte_vt);
178 }
179
Etan Cohend7727462014-07-12 14:54:10 -0700180 private ImsManager(Context context, long subId) {
Wink Savilleef36ef62014-06-11 08:39:38 -0700181 mContext = context;
Etan Cohend7727462014-07-12 14:54:10 -0700182 mSubId = subId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700183 createImsService(true);
184 }
185
186 /**
187 * Opens the IMS service for making calls and/or receiving generic IMS calls.
188 * The caller may make subsquent calls through {@link #makeCall}.
189 * The IMS service will register the device to the operator's network with the credentials
190 * (from ISIM) periodically in order to receive calls from the operator's network.
191 * When the IMS service receives a new call, it will send out an intent with
192 * the provided action string.
193 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call.
194 *
195 * @param serviceClass a service class specified in {@link ImsServiceClass}
196 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
197 * @param incomingCallPendingIntent When an incoming call is received,
198 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to
199 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE}
200 * as the result code and the intent to fill in the call ID; It cannot be null
201 * @param listener To listen to IMS registration events; It cannot be null
202 * @return identifier (greater than 0) for the specified service
203 * @throws NullPointerException if {@code incomingCallPendingIntent}
204 * or {@code listener} is null
205 * @throws ImsException if calling the IMS service results in an error
206 * @see #getCallId
207 * @see #getServiceId
208 */
209 public int open(int serviceClass, PendingIntent incomingCallPendingIntent,
210 ImsConnectionStateListener listener) throws ImsException {
211 checkAndThrowExceptionIfServiceUnavailable();
212
213 if (incomingCallPendingIntent == null) {
214 throw new NullPointerException("incomingCallPendingIntent can't be null");
215 }
216
217 if (listener == null) {
218 throw new NullPointerException("listener can't be null");
219 }
220
221 int result = 0;
222
223 try {
224 result = mImsService.open(serviceClass, incomingCallPendingIntent,
225 createRegistrationListenerProxy(serviceClass, listener));
226 } catch (RemoteException e) {
227 throw new ImsException("open()", e,
228 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
229 }
230
231 if (result <= 0) {
232 // If the return value is a minus value,
233 // it means that an error occurred in the service.
234 // So, it needs to convert to the reason code specified in ImsReasonInfo.
235 throw new ImsException("open()", (result * (-1)));
236 }
237
238 return result;
239 }
240
241 /**
242 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls.
243 * All the resources that were allocated to the service are also released.
244 *
245 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open}
246 * @throws ImsException if calling the IMS service results in an error
247 */
248 public void close(int serviceId) throws ImsException {
249 checkAndThrowExceptionIfServiceUnavailable();
250
251 try {
252 mImsService.close(serviceId);
253 } catch (RemoteException e) {
254 throw new ImsException("close()", e,
255 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
256 } finally {
257 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500258 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700259 mEcbm = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700260 }
261 }
262
263 /**
264 * Gets the configuration interface to provision / withdraw the supplementary service settings.
265 *
266 * @param serviceId a service id which is obtained from {@link ImsManager#open}
267 * @return the Ut interface instance
268 * @throws ImsException if getting the Ut interface results in an error
269 */
270 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId)
271 throws ImsException {
272 // FIXME: manage the multiple Ut interfaces based on the service id
273 if (mUt == null) {
274 checkAndThrowExceptionIfServiceUnavailable();
275
276 try {
277 IImsUt iUt = mImsService.getUtInterface(serviceId);
278
279 if (iUt == null) {
280 throw new ImsException("getSupplementaryServiceConfiguration()",
281 ImsReasonInfo.CODE_UT_NOT_SUPPORTED);
282 }
283
284 mUt = new ImsUt(iUt);
285 } catch (RemoteException e) {
286 throw new ImsException("getSupplementaryServiceConfiguration()", e,
287 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
288 }
289 }
290
291 return mUt;
292 }
293
294 /**
295 * Checks if the IMS service has successfully registered to the IMS network
296 * with the specified service & call type.
297 *
298 * @param serviceId a service id which is obtained from {@link ImsManager#open}
299 * @param serviceType a service type that is specified in {@link ImsCallProfile}
300 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
301 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
302 * @param callType a call type that is specified in {@link ImsCallProfile}
303 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
304 * {@link ImsCallProfile#CALL_TYPE_VOICE}
305 * {@link ImsCallProfile#CALL_TYPE_VT}
306 * {@link ImsCallProfile#CALL_TYPE_VS}
307 * @return true if the specified service id is connected to the IMS network;
308 * false otherwise
309 * @throws ImsException if calling the IMS service results in an error
310 */
311 public boolean isConnected(int serviceId, int serviceType, int callType)
312 throws ImsException {
313 checkAndThrowExceptionIfServiceUnavailable();
314
315 try {
316 return mImsService.isConnected(serviceId, serviceType, callType);
317 } catch (RemoteException e) {
318 throw new ImsException("isServiceConnected()", e,
319 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
320 }
321 }
322
323 /**
324 * Checks if the specified IMS service is opend.
325 *
326 * @param serviceId a service id which is obtained from {@link ImsManager#open}
327 * @return true if the specified service id is opened; false otherwise
328 * @throws ImsException if calling the IMS service results in an error
329 */
330 public boolean isOpened(int serviceId) throws ImsException {
331 checkAndThrowExceptionIfServiceUnavailable();
332
333 try {
334 return mImsService.isOpened(serviceId);
335 } catch (RemoteException e) {
336 throw new ImsException("isOpened()", e,
337 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
338 }
339 }
340
341 /**
342 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
343 *
344 * @param serviceId a service id which is obtained from {@link ImsManager#open}
345 * @param serviceType a service type that is specified in {@link ImsCallProfile}
346 * {@link ImsCallProfile#SERVICE_TYPE_NONE}
347 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
348 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
349 * @param callType a call type that is specified in {@link ImsCallProfile}
350 * {@link ImsCallProfile#CALL_TYPE_VOICE}
351 * {@link ImsCallProfile#CALL_TYPE_VT}
352 * {@link ImsCallProfile#CALL_TYPE_VT_TX}
353 * {@link ImsCallProfile#CALL_TYPE_VT_RX}
354 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
355 * {@link ImsCallProfile#CALL_TYPE_VS}
356 * {@link ImsCallProfile#CALL_TYPE_VS_TX}
357 * {@link ImsCallProfile#CALL_TYPE_VS_RX}
358 * @return a {@link ImsCallProfile} object
359 * @throws ImsException if calling the IMS service results in an error
360 */
361 public ImsCallProfile createCallProfile(int serviceId,
362 int serviceType, int callType) throws ImsException {
363 checkAndThrowExceptionIfServiceUnavailable();
364
365 try {
366 return mImsService.createCallProfile(serviceId, serviceType, callType);
367 } catch (RemoteException e) {
368 throw new ImsException("createCallProfile()", e,
369 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
370 }
371 }
372
373 /**
374 * Creates a {@link ImsCall} to make a call.
375 *
376 * @param serviceId a service id which is obtained from {@link ImsManager#open}
377 * @param profile a call profile to make the call
378 * (it contains service type, call type, media information, etc.)
379 * @param participants participants to invite the conference call
380 * @param listener listen to the call events from {@link ImsCall}
381 * @return a {@link ImsCall} object
382 * @throws ImsException if calling the IMS service results in an error
383 */
384 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees,
385 ImsCall.Listener listener) throws ImsException {
386 if (DBG) {
387 log("makeCall :: serviceId=" + serviceId
388 + ", profile=" + profile + ", callees=" + callees);
389 }
390
391 checkAndThrowExceptionIfServiceUnavailable();
392
393 ImsCall call = new ImsCall(mContext, profile);
394
395 call.setListener(listener);
396 ImsCallSession session = createCallSession(serviceId, profile);
397
398 if ((callees != null) && (callees.length == 1)) {
399 call.start(session, callees[0]);
400 } else {
401 call.start(session, callees);
402 }
403
404 return call;
405 }
406
407 /**
408 * Creates a {@link ImsCall} to take an incoming call.
409 *
410 * @param serviceId a service id which is obtained from {@link ImsManager#open}
411 * @param incomingCallIntent the incoming call broadcast intent
412 * @param listener to listen to the call events from {@link ImsCall}
413 * @return a {@link ImsCall} object
414 * @throws ImsException if calling the IMS service results in an error
415 */
416 public ImsCall takeCall(int serviceId, Intent incomingCallIntent,
417 ImsCall.Listener listener) throws ImsException {
418 if (DBG) {
419 log("takeCall :: serviceId=" + serviceId
420 + ", incomingCall=" + incomingCallIntent);
421 }
422
423 checkAndThrowExceptionIfServiceUnavailable();
424
425 if (incomingCallIntent == null) {
426 throw new ImsException("Can't retrieve session with null intent",
427 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
428 }
429
430 int incomingServiceId = getServiceId(incomingCallIntent);
431
432 if (serviceId != incomingServiceId) {
433 throw new ImsException("Service id is mismatched in the incoming call intent",
434 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
435 }
436
437 String callId = getCallId(incomingCallIntent);
438
439 if (callId == null) {
440 throw new ImsException("Call ID missing in the incoming call intent",
441 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
442 }
443
444 try {
445 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId);
446
447 if (session == null) {
448 throw new ImsException("No pending session for the call",
449 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL);
450 }
451
452 ImsCall call = new ImsCall(mContext, session.getCallProfile());
453
454 call.attachSession(new ImsCallSession(session));
455 call.setListener(listener);
456
457 return call;
458 } catch (Throwable t) {
459 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED);
460 }
461 }
462
463 /**
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500464 * Gets the config interface to get/set service/capability parameters.
465 *
466 * @return the ImsConfig instance.
467 * @throws ImsException if getting the setting interface results in an error.
468 */
469 public ImsConfig getConfigInterface() throws ImsException {
470
471 if (mConfig == null) {
472 checkAndThrowExceptionIfServiceUnavailable();
473
474 try {
475 IImsConfig config = mImsService.getConfigInterface();
476 if (config == null) {
477 throw new ImsException("getConfigInterface()",
478 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
479 }
480 mConfig = new ImsConfig(config);
481 } catch (RemoteException e) {
482 throw new ImsException("getConfigInterface()", e,
483 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
484 }
485 }
486 if (DBG) log("getConfigInterface(), mConfig= " + mConfig);
487 return mConfig;
488 }
489
490 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700491 * Gets the call ID from the specified incoming call broadcast intent.
492 *
493 * @param incomingCallIntent the incoming call broadcast intent
494 * @return the call ID or null if the intent does not contain it
495 */
496 private static String getCallId(Intent incomingCallIntent) {
497 if (incomingCallIntent == null) {
498 return null;
499 }
500
501 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
502 }
503
504 /**
505 * Gets the service type from the specified incoming call broadcast intent.
506 *
507 * @param incomingCallIntent the incoming call broadcast intent
508 * @return the service identifier or -1 if the intent does not contain it
509 */
510 private static int getServiceId(Intent incomingCallIntent) {
511 if (incomingCallIntent == null) {
512 return (-1);
513 }
514
515 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1);
516 }
517
518 /**
519 * Binds the IMS service only if the service is not created.
520 */
521 private void checkAndThrowExceptionIfServiceUnavailable()
522 throws ImsException {
523 if (mImsService == null) {
524 createImsService(true);
525
526 if (mImsService == null) {
527 throw new ImsException("Service is unavailable",
528 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
529 }
530 }
531 }
532
Etan Cohend7727462014-07-12 14:54:10 -0700533 private static String getImsServiceName(long subId) {
534 // TODO: MSIM implementation needs to decide on service name as a function of subId
535 // or value derived from subId (slot ID?)
536 return IMS_SERVICE;
537 }
538
Wink Savilleef36ef62014-06-11 08:39:38 -0700539 /**
540 * Binds the IMS service to make/receive the call.
541 */
542 private void createImsService(boolean checkService) {
543 if (checkService) {
Etan Cohend7727462014-07-12 14:54:10 -0700544 IBinder binder = ServiceManager.checkService(getImsServiceName(mSubId));
Wink Savilleef36ef62014-06-11 08:39:38 -0700545
546 if (binder == null) {
547 return;
548 }
549 }
550
Etan Cohend7727462014-07-12 14:54:10 -0700551 IBinder b = ServiceManager.getService(getImsServiceName(mSubId));
Wink Savilleef36ef62014-06-11 08:39:38 -0700552
553 if (b != null) {
554 try {
555 b.linkToDeath(mDeathRecipient, 0);
556 } catch (RemoteException e) {
557 }
558 }
559
560 mImsService = IImsService.Stub.asInterface(b);
561 }
562
563 /**
564 * Creates a {@link ImsCallSession} with the specified call profile.
565 * Use other methods, if applicable, instead of interacting with
566 * {@link ImsCallSession} directly.
567 *
568 * @param serviceId a service id which is obtained from {@link ImsManager#open}
569 * @param profile a call profile to make the call
570 */
571 private ImsCallSession createCallSession(int serviceId,
572 ImsCallProfile profile) throws ImsException {
573 try {
574 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null));
575 } catch (RemoteException e) {
576 return null;
577 }
578 }
579
580 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass,
581 ImsConnectionStateListener listener) {
582 ImsRegistrationListenerProxy proxy =
583 new ImsRegistrationListenerProxy(serviceClass, listener);
584 return proxy;
585 }
586
587 private void log(String s) {
588 Rlog.d(TAG, s);
589 }
590
591 private void loge(String s) {
592 Rlog.e(TAG, s);
593 }
594
595 private void loge(String s, Throwable t) {
596 Rlog.e(TAG, s, t);
597 }
598
599 /**
ram7da5a112014-07-16 20:59:27 +0530600 * Used for turning on IMS.if its off already
601 */
602 public void turnOnIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -0700603 checkAndThrowExceptionIfServiceUnavailable();
604
ram7da5a112014-07-16 20:59:27 +0530605 try {
606 mImsService.turnOnIms();
607 } catch (RemoteException e) {
608 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
609 }
610 }
611
Etan Cohencfc784d2014-08-07 18:40:31 -0700612 public void setAdvanced4GMode(boolean turnOn) throws ImsException {
613 checkAndThrowExceptionIfServiceUnavailable();
614
615 ImsConfig config = getConfigInterface();
616 if (config != null) {
617 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
618 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
619 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
620 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
621 }
622
623 if (turnOn) {
624 turnOnIms();
625 } else if (mContext.getResources().getBoolean(
626 com.android.internal.R.bool.imsServiceAllowTurnOff)) {
627 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms");
628 turnOffIms();
629 }
630 }
631
ram7da5a112014-07-16 20:59:27 +0530632 /**
633 * Used for turning off IMS completely in order to make the device CSFB'ed.
634 * Once turned off, all calls will be over CS.
635 */
636 public void turnOffIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -0700637 checkAndThrowExceptionIfServiceUnavailable();
638
ram7da5a112014-07-16 20:59:27 +0530639 try {
640 mImsService.turnOffIms();
641 } catch (RemoteException e) {
642 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
643 }
644 }
645
646 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700647 * Death recipient class for monitoring IMS service.
648 */
649 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient {
650 @Override
651 public void binderDied() {
652 mImsService = null;
653 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500654 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700655 mEcbm = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700656
657 if (mContext != null) {
Etan Cohend7727462014-07-12 14:54:10 -0700658 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN);
659 intent.putExtra(EXTRA_SUBID, mSubId);
660 mContext.sendBroadcast(new Intent(intent));
Wink Savilleef36ef62014-06-11 08:39:38 -0700661 }
662 }
663 }
664
665 /**
666 * Adapter class for {@link IImsRegistrationListener}.
667 */
668 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub {
669 private int mServiceClass;
670 private ImsConnectionStateListener mListener;
671
672 public ImsRegistrationListenerProxy(int serviceClass,
673 ImsConnectionStateListener listener) {
674 mServiceClass = serviceClass;
675 mListener = listener;
676 }
677
678 public boolean isSameProxy(int serviceClass) {
679 return (mServiceClass == serviceClass);
680 }
681
682 @Override
683 public void registrationConnected() {
684 if (DBG) {
685 log("registrationConnected ::");
686 }
687
688 if (mListener != null) {
689 mListener.onImsConnected();
690 }
691 }
692
693 @Override
694 public void registrationDisconnected() {
695 if (DBG) {
696 log("registrationDisconnected ::");
697 }
698
699 if (mListener != null) {
700 mListener.onImsDisconnected();
701 }
702 }
703
704 @Override
705 public void registrationResumed() {
706 if (DBG) {
707 log("registrationResumed ::");
708 }
709
710 if (mListener != null) {
711 mListener.onImsResumed();
712 }
713 }
714
715 @Override
716 public void registrationSuspended() {
717 if (DBG) {
718 log("registrationSuspended ::");
719 }
720
721 if (mListener != null) {
722 mListener.onImsSuspended();
723 }
724 }
725
726 @Override
727 public void registrationServiceCapabilityChanged(int serviceClass, int event) {
728 log("registrationServiceCapabilityChanged :: serviceClass=" +
729 serviceClass + ", event=" + event);
730
731 if (mListener != null) {
732 mListener.onImsConnected();
733 }
734 }
ram7da5a112014-07-16 20:59:27 +0530735
736 @Override
737 public void registrationFeatureCapabilityChanged(int serviceClass,
738 int[] enabledFeatures, int[] disabledFeatures) {
739 log("registrationFeatureCapabilityChanged :: serviceClass=" +
740 serviceClass);
741 }
742
Wink Savilleef36ef62014-06-11 08:39:38 -0700743 }
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700744 /**
745 * Gets the ECBM interface to request ECBM exit.
746 *
747 * @param serviceId a service id which is obtained from {@link ImsManager#open}
748 * @return the ECBM interface instance
749 * @throws ImsException if getting the ECBM interface results in an error
750 */
751 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException {
752 if (mEcbm == null) {
753 checkAndThrowExceptionIfServiceUnavailable();
754
755 try {
756 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId);
757
758 if (iEcbm == null) {
759 throw new ImsException("getEcbmInterface()",
760 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED);
761 }
762 mEcbm = new ImsEcbm(iEcbm);
763 } catch (RemoteException e) {
764 throw new ImsException("getEcbmInterface()", e,
765 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
766 }
767 }
768 return mEcbm;
769 }
Wink Savilleef36ef62014-06-11 08:39:38 -0700770}