blob: 2ca2b191990bf62eeb1af1ccaab1364a1ad91af5 [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;
Etan Cohena00c9192014-12-23 15:02:29 -080020import android.app.QueuedWork;
Wink Savilleef36ef62014-06-11 08:39:38 -070021import android.content.Context;
22import android.content.Intent;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -070023import android.content.SharedPreferences;
Wink Savilleef36ef62014-06-11 08:39:38 -070024import android.os.IBinder;
Wink Savilleef36ef62014-06-11 08:39:38 -070025import android.os.Message;
Jonathan Basseri2acea6f2015-07-01 15:00:38 -070026import android.os.PersistableBundle;
Wink Savilleef36ef62014-06-11 08:39:38 -070027import android.os.RemoteException;
28import android.os.ServiceManager;
Etan Cohenaf55a402014-09-04 22:34:41 -070029import android.os.SystemProperties;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -070030import android.preference.PreferenceManager;
Etan Cohen82f78122014-12-15 10:10:14 -080031import android.provider.Settings;
32import android.telecom.TelecomManager;
Junda Liue7663c02015-06-23 11:16:26 -070033import android.telephony.CarrierConfigManager;
Wink Savilleef36ef62014-06-11 08:39:38 -070034import android.telephony.Rlog;
Etan Cohen82f78122014-12-15 10:10:14 -080035import android.telephony.SubscriptionManager;
Etan Cohencfc784d2014-08-07 18:40:31 -070036import android.telephony.TelephonyManager;
Wink Savilleef36ef62014-06-11 08:39:38 -070037
38import com.android.ims.internal.IImsCallSession;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -070039import com.android.ims.internal.IImsEcbm;
40import com.android.ims.internal.IImsEcbmListener;
Wink Savilleef36ef62014-06-11 08:39:38 -070041import com.android.ims.internal.IImsRegistrationListener;
42import com.android.ims.internal.IImsService;
43import com.android.ims.internal.IImsUt;
44import com.android.ims.internal.ImsCallSession;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -050045import com.android.ims.internal.IImsConfig;
46
Etan Cohend7727462014-07-12 14:54:10 -070047import java.util.HashMap;
48
Wink Savilleef36ef62014-06-11 08:39:38 -070049/**
50 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
51 * the operator's IMS network. This class is the starting point for any IMS actions.
52 * You can acquire an instance of it with {@link #getInstance getInstance()}.</p>
53 * <p>The APIs in this class allows you to:</p>
54 *
55 * @hide
56 */
57public class ImsManager {
Etan Cohen19604c02014-08-11 14:32:57 -070058
Etan Cohenaf55a402014-09-04 22:34:41 -070059 /*
60 * Debug flag to override configuration flag
61 */
Etan Cohenb651fa52014-10-22 10:51:29 -070062 public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr";
63 public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohenea2b5832014-10-23 18:50:35 -070064 public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr";
65 public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohena00c9192014-12-23 15:02:29 -080066 public static final String PROPERTY_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr";
67 public static final int PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohenaf55a402014-09-04 22:34:41 -070068
Wink Savilleef36ef62014-06-11 08:39:38 -070069 /**
70 * For accessing the IMS related service.
71 * Internal use only.
72 * @hide
73 */
Etan Cohend7727462014-07-12 14:54:10 -070074 private static final String IMS_SERVICE = "ims";
Wink Savilleef36ef62014-06-11 08:39:38 -070075
76 /**
77 * The result code to be sent back with the incoming call {@link PendingIntent}.
78 * @see #open(PendingIntent, ImsConnectionStateListener)
79 */
80 public static final int INCOMING_CALL_RESULT_CODE = 101;
81
82 /**
83 * Key to retrieve the call ID from an incoming call intent.
84 * @see #open(PendingIntent, ImsConnectionStateListener)
85 */
86 public static final String EXTRA_CALL_ID = "android:imsCallID";
87
88 /**
89 * Action to broadcast when ImsService is up.
90 * Internal use only.
91 * @hide
92 */
93 public static final String ACTION_IMS_SERVICE_UP =
94 "com.android.ims.IMS_SERVICE_UP";
95
96 /**
97 * Action to broadcast when ImsService is down.
98 * Internal use only.
99 * @hide
100 */
101 public static final String ACTION_IMS_SERVICE_DOWN =
102 "com.android.ims.IMS_SERVICE_DOWN";
103
104 /**
Pavel Zhamaitsiak0c2f15c2015-03-12 15:37:54 -0700105 * Action to broadcast when ImsService registration fails.
106 * Internal use only.
107 * @hide
108 */
109 public static final String ACTION_IMS_REGISTRATION_ERROR =
110 "com.android.ims.REGISTRATION_ERROR";
111
112 /**
Etan Cohend7727462014-07-12 14:54:10 -0700113 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
Etan Cohenabbd7882014-09-26 22:35:35 -0700114 * A long value; the phone ID corresponding to the IMS service coming up or down.
Etan Cohend7727462014-07-12 14:54:10 -0700115 * Internal use only.
116 * @hide
117 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700118 public static final String EXTRA_PHONE_ID = "android:phone_id";
Etan Cohend7727462014-07-12 14:54:10 -0700119
120 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700121 * Action for the incoming call intent for the Phone app.
122 * Internal use only.
123 * @hide
124 */
125 public static final String ACTION_IMS_INCOMING_CALL =
126 "com.android.ims.IMS_INCOMING_CALL";
127
128 /**
129 * Part of the ACTION_IMS_INCOMING_CALL intents.
130 * An integer value; service identifier obtained from {@link ImsManager#open}.
131 * Internal use only.
132 * @hide
133 */
134 public static final String EXTRA_SERVICE_ID = "android:imsServiceId";
135
136 /**
137 * Part of the ACTION_IMS_INCOMING_CALL intents.
138 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD.
139 * The value "true" indicates that the incoming call is for USSD.
140 * Internal use only.
141 * @hide
142 */
143 public static final String EXTRA_USSD = "android:ussd";
144
Shriram Ganeshd3adfad2015-05-31 10:06:15 -0700145 /**
146 * Part of the ACTION_IMS_INCOMING_CALL intents.
147 * A boolean value; Flag to indicate whether the call is an unknown
148 * dialing call. Such calls are originated by sending commands (like
149 * AT commands) directly to modem without Android involvement.
150 * Even though they are not incoming calls, they are propagated
151 * to Phone app using same ACTION_IMS_INCOMING_CALL intent.
152 * Internal use only.
153 * @hide
154 */
Anju Mathapati9c033792015-06-16 16:33:16 -0700155 public static final String EXTRA_IS_UNKNOWN_CALL = "android:isUnknown";
Shriram Ganeshd3adfad2015-05-31 10:06:15 -0700156
Wink Savilleef36ef62014-06-11 08:39:38 -0700157 private static final String TAG = "ImsManager";
158 private static final boolean DBG = true;
159
Wink Saville1e5a38a2014-10-23 10:24:46 -0700160 private static HashMap<Integer, ImsManager> sImsManagerInstances =
161 new HashMap<Integer, ImsManager>();
Etan Cohend7727462014-07-12 14:54:10 -0700162
Wink Savilleef36ef62014-06-11 08:39:38 -0700163 private Context mContext;
Etan Cohenabbd7882014-09-26 22:35:35 -0700164 private int mPhoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700165 private IImsService mImsService = null;
166 private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient();
167 // Ut interface for the supplementary service configuration
168 private ImsUt mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500169 // Interface to get/set ims config items
170 private ImsConfig mConfig = null;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700171 private boolean mConfigUpdated = false;
172 private static final String PREF_ENABLE_VIDEO_CALLING_KEY = "enable_video_calling";
Wink Savilleef36ef62014-06-11 08:39:38 -0700173
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700174 // ECBM interface
175 private ImsEcbm mEcbm = null;
176
Wink Savilleef36ef62014-06-11 08:39:38 -0700177 /**
178 * Gets a manager instance.
179 *
180 * @param context application context for creating the manager object
Etan Cohenabbd7882014-09-26 22:35:35 -0700181 * @param phoneId the phone ID for the IMS Service
182 * @return the manager instance corresponding to the phoneId
Wink Savilleef36ef62014-06-11 08:39:38 -0700183 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700184 public static ImsManager getInstance(Context context, int phoneId) {
Etan Cohend7727462014-07-12 14:54:10 -0700185 synchronized (sImsManagerInstances) {
Etan Cohenabbd7882014-09-26 22:35:35 -0700186 if (sImsManagerInstances.containsKey(phoneId))
187 return sImsManagerInstances.get(phoneId);
Wink Savilleef36ef62014-06-11 08:39:38 -0700188
Etan Cohenabbd7882014-09-26 22:35:35 -0700189 ImsManager mgr = new ImsManager(context, phoneId);
190 sImsManagerInstances.put(phoneId, mgr);
Etan Cohend7727462014-07-12 14:54:10 -0700191
192 return mgr;
193 }
Wink Savilleef36ef62014-06-11 08:39:38 -0700194 }
195
Etan Cohen45b5f312014-08-19 15:55:08 -0700196 /**
197 * Returns the user configuration of Enhanced 4G LTE Mode setting
198 */
199 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) {
Libin.Tang@motorola.com8a6bf4b2014-10-10 15:02:41 -0500200 int enabled = android.provider.Settings.Global.getInt(
201 context.getContentResolver(),
Etan Cohenb651fa52014-10-22 10:51:29 -0700202 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
Etan Cohena00c9192014-12-23 15:02:29 -0800203 return (enabled == 1) ? true : false;
Etan Cohen45b5f312014-08-19 15:55:08 -0700204 }
205
206 /**
Etan Cohen82f78122014-12-15 10:10:14 -0800207 * Change persistent Enhanced 4G LTE Mode setting
208 */
209 public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {
210 int value = enabled ? 1 : 0;
211 android.provider.Settings.Global.putInt(
212 context.getContentResolver(),
213 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, value);
214
215 if (isNonTtyOrTtyOnVolteEnabled(context)) {
216 ImsManager imsManager = ImsManager.getInstance(context,
217 SubscriptionManager.getDefaultVoicePhoneId());
218 if (imsManager != null) {
219 try {
220 imsManager.setAdvanced4GMode(enabled);
221 } catch (ImsException ie) {
222 // do nothing
223 }
224 }
225 }
226 }
227
228 /**
229 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is
230 * supported.
231 */
232 public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) {
Junda Liue7663c02015-06-23 11:16:26 -0700233 if (getBooleanCarrierConfig(context,
234 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -0800235 return true;
236 }
237
238 return Settings.Secure.getInt(context.getContentResolver(),
239 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF)
240 == TelecomManager.TTY_MODE_OFF;
241 }
242
243 /**
Etan Cohenea2b5832014-10-23 18:50:35 -0700244 * Returns a platform configuration for VoLTE which may override the user setting.
Etan Cohen45b5f312014-08-19 15:55:08 -0700245 */
Etan Cohenea2b5832014-10-23 18:50:35 -0700246 public static boolean isVolteEnabledByPlatform(Context context) {
Etan Cohenb651fa52014-10-22 10:51:29 -0700247 if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE,
248 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) {
Etan Cohenaf55a402014-09-04 22:34:41 -0700249 return true;
250 }
251
Etan Cohenb5388a32014-11-26 11:57:47 -0800252 return context.getResources().getBoolean(
Junda Liue7663c02015-06-23 11:16:26 -0700253 com.android.internal.R.bool.config_device_volte_available)
254 && getBooleanCarrierConfig(context,
Junda Liu7e16d5d2015-07-22 12:23:46 -0700255 CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL);
Etan Cohenb5388a32014-11-26 11:57:47 -0800256 }
257
258 /*
259 * Indicates whether VoLTE is provisioned on device
260 */
261 public static boolean isVolteProvisionedOnDevice(Context context) {
262 boolean isProvisioned = true;
Junda Liue7663c02015-06-23 11:16:26 -0700263 if (getBooleanCarrierConfig(context,
264 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
Etan Cohenb5388a32014-11-26 11:57:47 -0800265 isProvisioned = false; // disable on any error
266 ImsManager mgr = ImsManager.getInstance(context,
Jonathan Basserid7133652015-04-07 19:54:24 -0700267 SubscriptionManager.getDefaultVoicePhoneId());
Etan Cohenb5388a32014-11-26 11:57:47 -0800268 if (mgr != null) {
269 try {
270 ImsConfig config = mgr.getConfigInterface();
271 if (config != null) {
272 isProvisioned = config.getVolteProvisioned();
273 }
274 } catch (ImsException ie) {
275 // do nothing
276 }
277 }
278 }
279
280 return isProvisioned;
Etan Cohenb651fa52014-10-22 10:51:29 -0700281 }
282
Etan Cohenea2b5832014-10-23 18:50:35 -0700283 /**
284 * Returns a platform configuration for VT which may override the user setting.
285 *
286 * Note: VT presumes that VoLTE is enabled (these are configuration settings
287 * which must be done correctly).
288 */
Etan Cohenb651fa52014-10-22 10:51:29 -0700289 public static boolean isVtEnabledByPlatform(Context context) {
Etan Cohenea2b5832014-10-23 18:50:35 -0700290 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE,
291 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) {
292 return true;
293 }
294
Etan Cohenb651fa52014-10-22 10:51:29 -0700295 return
296 context.getResources().getBoolean(
297 com.android.internal.R.bool.config_device_vt_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700298 getBooleanCarrierConfig(context,
299 CarrierConfigManager.KEY_CARRIER_VT_AVAILABLE_BOOL);
Etan Cohen45b5f312014-08-19 15:55:08 -0700300 }
301
Etan Cohena00c9192014-12-23 15:02:29 -0800302 /**
303 * Returns the user configuration of WFC setting
304 */
305 public static boolean isWfcEnabledByUser(Context context) {
306 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
307 android.provider.Settings.Global.WFC_IMS_ENABLED,
Pavel Zhamaitsiakeb13a592015-04-27 09:44:33 -0700308 ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800309 return (enabled == 1) ? true : false;
310 }
311
312 /**
313 * Change persistent WFC enabled setting
314 */
315 public static void setWfcSetting(Context context, boolean enabled) {
316 int value = enabled ? 1 : 0;
317 android.provider.Settings.Global.putInt(context.getContentResolver(),
318 android.provider.Settings.Global.WFC_IMS_ENABLED, value);
319
320 ImsManager imsManager = ImsManager.getInstance(context,
321 SubscriptionManager.getDefaultVoicePhoneId());
322 if (imsManager != null) {
323 try {
324 ImsConfig config = imsManager.getConfigInterface();
Etan Cohena00c9192014-12-23 15:02:29 -0800325 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
Nathan Harold3a99f782015-07-24 15:02:34 -0700326 TelephonyManager.NETWORK_TYPE_IWLAN,
Etan Cohena00c9192014-12-23 15:02:29 -0800327 enabled ? ImsConfig.FeatureValueConstants.ON
328 : ImsConfig.FeatureValueConstants.OFF, null);
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800329
330 if (enabled) {
331 imsManager.turnOnIms();
Junda Liue7663c02015-06-23 11:16:26 -0700332 } else if (getBooleanCarrierConfig(context,
333 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL)
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800334 && (!isVolteEnabledByPlatform(context)
335 || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
336 log("setWfcSetting() : imsServiceAllowTurnOff -> turnOffIms");
337 imsManager.turnOffIms();
338 }
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700339
340 // Force IMS to register over LTE when turning off WFC
341 setWfcModeInternal(context, enabled
342 ? getWfcMode(context)
343 : ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED);
Etan Cohena00c9192014-12-23 15:02:29 -0800344 } catch (ImsException e) {
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800345 loge("setWfcSetting(): " + e);
Etan Cohena00c9192014-12-23 15:02:29 -0800346 }
347 }
348 }
349
350 /**
351 * Returns the user configuration of WFC modem setting
352 */
353 public static int getWfcMode(Context context) {
354 int setting = android.provider.Settings.Global.getInt(context.getContentResolver(),
355 android.provider.Settings.Global.WFC_IMS_MODE,
356 ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED);
357 if (DBG) log("getWfcMode - setting=" + setting);
358 return setting;
359 }
360
361 /**
362 * Returns the user configuration of WFC modem setting
363 */
364 public static void setWfcMode(Context context, int wfcMode) {
365 if (DBG) log("setWfcMode - setting=" + wfcMode);
366 android.provider.Settings.Global.putInt(context.getContentResolver(),
367 android.provider.Settings.Global.WFC_IMS_MODE, wfcMode);
368
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700369 setWfcModeInternal(context, wfcMode);
370 }
371
372 private static void setWfcModeInternal(Context context, int wfcMode) {
Etan Cohena00c9192014-12-23 15:02:29 -0800373 final ImsManager imsManager = ImsManager.getInstance(context,
374 SubscriptionManager.getDefaultVoicePhoneId());
375 if (imsManager != null) {
376 final int value = wfcMode;
377 QueuedWork.singleThreadExecutor().submit(new Runnable() {
378 public void run() {
379 try {
380 imsManager.getConfigInterface().setProvisionedValue(
381 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE,
382 value);
383 } catch (ImsException e) {
384 // do nothing
385 }
386 }
387 });
388 }
389 }
390
391 /**
392 * Returns the user configuration of WFC roaming setting
393 */
394 public static boolean isWfcRoamingEnabledByUser(Context context) {
395 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
396 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
Pavel Zhamaitsiak28c84002015-03-10 16:42:01 -0700397 ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800398 return (enabled == 1) ? true : false;
399 }
400
401 /**
402 * Change persistent WFC roaming enabled setting
403 */
404 public static void setWfcRoamingSetting(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800405 android.provider.Settings.Global.putInt(context.getContentResolver(),
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700406 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
407 enabled
408 ? ImsConfig.FeatureValueConstants.ON
409 : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800410
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700411 setWfcRoamingSettingInternal(context, enabled);
412 }
413
414 private static void setWfcRoamingSettingInternal(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800415 final ImsManager imsManager = ImsManager.getInstance(context,
416 SubscriptionManager.getDefaultVoicePhoneId());
417 if (imsManager != null) {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700418 final int value = enabled
419 ? ImsConfig.FeatureValueConstants.ON
420 : ImsConfig.FeatureValueConstants.OFF;
Etan Cohena00c9192014-12-23 15:02:29 -0800421 QueuedWork.singleThreadExecutor().submit(new Runnable() {
422 public void run() {
423 try {
424 imsManager.getConfigInterface().setProvisionedValue(
425 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_ROAMING,
426 value);
427 } catch (ImsException e) {
428 // do nothing
429 }
430 }
431 });
432 }
433 }
434
435 /**
436 * Returns a platform configuration for WFC which may override the user
437 * setting. Note: WFC presumes that VoLTE is enabled (these are
438 * configuration settings which must be done correctly).
439 */
440 public static boolean isWfcEnabledByPlatform(Context context) {
441 if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE,
442 PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT) == 1) {
443 return true;
444 }
445
446 return
447 context.getResources().getBoolean(
448 com.android.internal.R.bool.config_device_wfc_ims_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700449 getBooleanCarrierConfig(context,
450 CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL);
Etan Cohena00c9192014-12-23 15:02:29 -0800451 }
452
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700453 /**
454 * Sync carrier config and user settings with ImsConfig.
455 *
456 * @param context for the manager object
457 * @param phoneId phone id
458 * @param force update
459 */
460 public static void updateImsServiceConfig(Context context, int phoneId, boolean force) {
461 final ImsManager imsManager = ImsManager.getInstance(context, phoneId);
462 if (imsManager != null && (!imsManager.mConfigUpdated || force)) {
463 try {
464 imsManager.updateVolteFeatureValue();
465 imsManager.updateVideoCallFeatureValue();
466 imsManager.updateWfcFeatureAndProvisionedValues();
467 imsManager.mConfigUpdated = true;
468 } catch (ImsException e) {
469 loge("updateImsServiceConfig: " + e);
470 imsManager.mConfigUpdated = false;
471 }
472 }
473 }
474
475 private void updateVolteFeatureValue() throws ImsException {
476 boolean available = isVolteEnabledByPlatform(mContext);
477 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext);
478 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
479
480 log("updateVolteFeatureValue: available = " + available
481 + ", enabled = " + enabled
482 + ", nonTTY = " + isNonTty);
483
484 getConfigInterface().setFeatureValue(
485 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
486 TelephonyManager.NETWORK_TYPE_LTE,
487 (available && enabled && isNonTty) ?
488 ImsConfig.FeatureValueConstants.ON :
489 ImsConfig.FeatureValueConstants.OFF,
490 null);
491 }
492
493 private void updateVideoCallFeatureValue() throws ImsException {
494 boolean available = isVtEnabledByPlatform(mContext);
495 SharedPreferences sharedPrefs =
496 PreferenceManager.getDefaultSharedPreferences(mContext);
497 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext) &&
498 sharedPrefs.getBoolean(PREF_ENABLE_VIDEO_CALLING_KEY, true);
499 boolean isNonTty = Settings.Secure.getInt(mContext.getContentResolver(),
500 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF)
501 == TelecomManager.TTY_MODE_OFF;
502
503 log("updateVideoCallFeatureValue: available = " + available
504 + ", enabled = " + enabled
505 + ", nonTTY = " + isNonTty);
506
507 getConfigInterface().setFeatureValue(
508 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
509 TelephonyManager.NETWORK_TYPE_LTE,
510 (available && enabled && isNonTty) ?
511 ImsConfig.FeatureValueConstants.ON :
512 ImsConfig.FeatureValueConstants.OFF,
513 null);
514 }
515
516 private void updateWfcFeatureAndProvisionedValues() throws ImsException {
517 boolean available = isWfcEnabledByPlatform(mContext);
518 boolean enabled = isWfcEnabledByUser(mContext);
519 int mode = getWfcMode(mContext);
520 boolean roaming = isWfcRoamingEnabledByUser(mContext);
521
522 log("updateWfcFeatureAndProvisionedValues: available = " + available
523 + ", enabled = " + enabled
524 + ", mode = " + mode
525 + ", roaming = " + roaming);
526
527 getConfigInterface().setFeatureValue(
528 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
529 TelephonyManager.NETWORK_TYPE_LTE,
530 (available && enabled) ?
531 ImsConfig.FeatureValueConstants.ON :
532 ImsConfig.FeatureValueConstants.OFF,
533 null);
534
535 if (!available || !enabled) {
536 mode = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED;
537 roaming = false;
538 }
539 setWfcModeInternal(mContext, mode);
540 setWfcRoamingSettingInternal(mContext, roaming);
541 }
542
Etan Cohenabbd7882014-09-26 22:35:35 -0700543 private ImsManager(Context context, int phoneId) {
Wink Savilleef36ef62014-06-11 08:39:38 -0700544 mContext = context;
Etan Cohenabbd7882014-09-26 22:35:35 -0700545 mPhoneId = phoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700546 createImsService(true);
547 }
548
Etan Cohenf4311122015-02-26 17:47:13 -0800549 /*
550 * Returns a flag indicating whether the IMS service is available.
551 */
552 public boolean isServiceAvailable() {
553 if (mImsService != null) {
554 return true;
555 }
556
557 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
558 if (binder != null) {
559 return true;
560 }
561
562 return false;
563 }
564
Wink Savilleef36ef62014-06-11 08:39:38 -0700565 /**
566 * Opens the IMS service for making calls and/or receiving generic IMS calls.
567 * The caller may make subsquent calls through {@link #makeCall}.
568 * The IMS service will register the device to the operator's network with the credentials
569 * (from ISIM) periodically in order to receive calls from the operator's network.
570 * When the IMS service receives a new call, it will send out an intent with
571 * the provided action string.
572 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call.
573 *
574 * @param serviceClass a service class specified in {@link ImsServiceClass}
575 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
576 * @param incomingCallPendingIntent When an incoming call is received,
577 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to
578 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE}
579 * as the result code and the intent to fill in the call ID; It cannot be null
580 * @param listener To listen to IMS registration events; It cannot be null
581 * @return identifier (greater than 0) for the specified service
582 * @throws NullPointerException if {@code incomingCallPendingIntent}
583 * or {@code listener} is null
584 * @throws ImsException if calling the IMS service results in an error
585 * @see #getCallId
586 * @see #getServiceId
587 */
588 public int open(int serviceClass, PendingIntent incomingCallPendingIntent,
589 ImsConnectionStateListener listener) throws ImsException {
590 checkAndThrowExceptionIfServiceUnavailable();
591
592 if (incomingCallPendingIntent == null) {
593 throw new NullPointerException("incomingCallPendingIntent can't be null");
594 }
595
596 if (listener == null) {
597 throw new NullPointerException("listener can't be null");
598 }
599
600 int result = 0;
601
602 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700603 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent,
Wink Savilleef36ef62014-06-11 08:39:38 -0700604 createRegistrationListenerProxy(serviceClass, listener));
605 } catch (RemoteException e) {
606 throw new ImsException("open()", e,
607 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
608 }
609
610 if (result <= 0) {
611 // If the return value is a minus value,
612 // it means that an error occurred in the service.
613 // So, it needs to convert to the reason code specified in ImsReasonInfo.
614 throw new ImsException("open()", (result * (-1)));
615 }
616
617 return result;
618 }
619
620 /**
621 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls.
622 * All the resources that were allocated to the service are also released.
623 *
624 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open}
625 * @throws ImsException if calling the IMS service results in an error
626 */
627 public void close(int serviceId) throws ImsException {
628 checkAndThrowExceptionIfServiceUnavailable();
629
630 try {
631 mImsService.close(serviceId);
632 } catch (RemoteException e) {
633 throw new ImsException("close()", e,
634 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
635 } finally {
636 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500637 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700638 mEcbm = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700639 }
640 }
641
642 /**
643 * Gets the configuration interface to provision / withdraw the supplementary service settings.
644 *
645 * @param serviceId a service id which is obtained from {@link ImsManager#open}
646 * @return the Ut interface instance
647 * @throws ImsException if getting the Ut interface results in an error
648 */
649 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId)
650 throws ImsException {
651 // FIXME: manage the multiple Ut interfaces based on the service id
652 if (mUt == null) {
653 checkAndThrowExceptionIfServiceUnavailable();
654
655 try {
656 IImsUt iUt = mImsService.getUtInterface(serviceId);
657
658 if (iUt == null) {
659 throw new ImsException("getSupplementaryServiceConfiguration()",
660 ImsReasonInfo.CODE_UT_NOT_SUPPORTED);
661 }
662
663 mUt = new ImsUt(iUt);
664 } catch (RemoteException e) {
665 throw new ImsException("getSupplementaryServiceConfiguration()", e,
666 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
667 }
668 }
669
670 return mUt;
671 }
672
673 /**
674 * Checks if the IMS service has successfully registered to the IMS network
675 * with the specified service & call type.
676 *
677 * @param serviceId a service id which is obtained from {@link ImsManager#open}
678 * @param serviceType a service type that is specified in {@link ImsCallProfile}
679 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
680 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
681 * @param callType a call type that is specified in {@link ImsCallProfile}
682 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
683 * {@link ImsCallProfile#CALL_TYPE_VOICE}
684 * {@link ImsCallProfile#CALL_TYPE_VT}
685 * {@link ImsCallProfile#CALL_TYPE_VS}
686 * @return true if the specified service id is connected to the IMS network;
687 * false otherwise
688 * @throws ImsException if calling the IMS service results in an error
689 */
690 public boolean isConnected(int serviceId, int serviceType, int callType)
691 throws ImsException {
692 checkAndThrowExceptionIfServiceUnavailable();
693
694 try {
695 return mImsService.isConnected(serviceId, serviceType, callType);
696 } catch (RemoteException e) {
697 throw new ImsException("isServiceConnected()", e,
698 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
699 }
700 }
701
702 /**
703 * Checks if the specified IMS service is opend.
704 *
705 * @param serviceId a service id which is obtained from {@link ImsManager#open}
706 * @return true if the specified service id is opened; false otherwise
707 * @throws ImsException if calling the IMS service results in an error
708 */
709 public boolean isOpened(int serviceId) throws ImsException {
710 checkAndThrowExceptionIfServiceUnavailable();
711
712 try {
713 return mImsService.isOpened(serviceId);
714 } catch (RemoteException e) {
715 throw new ImsException("isOpened()", e,
716 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
717 }
718 }
719
720 /**
721 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
722 *
723 * @param serviceId a service id which is obtained from {@link ImsManager#open}
724 * @param serviceType a service type that is specified in {@link ImsCallProfile}
725 * {@link ImsCallProfile#SERVICE_TYPE_NONE}
726 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
727 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
728 * @param callType a call type that is specified in {@link ImsCallProfile}
729 * {@link ImsCallProfile#CALL_TYPE_VOICE}
730 * {@link ImsCallProfile#CALL_TYPE_VT}
731 * {@link ImsCallProfile#CALL_TYPE_VT_TX}
732 * {@link ImsCallProfile#CALL_TYPE_VT_RX}
733 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
734 * {@link ImsCallProfile#CALL_TYPE_VS}
735 * {@link ImsCallProfile#CALL_TYPE_VS_TX}
736 * {@link ImsCallProfile#CALL_TYPE_VS_RX}
737 * @return a {@link ImsCallProfile} object
738 * @throws ImsException if calling the IMS service results in an error
739 */
740 public ImsCallProfile createCallProfile(int serviceId,
741 int serviceType, int callType) throws ImsException {
742 checkAndThrowExceptionIfServiceUnavailable();
743
744 try {
745 return mImsService.createCallProfile(serviceId, serviceType, callType);
746 } catch (RemoteException e) {
747 throw new ImsException("createCallProfile()", e,
748 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
749 }
750 }
751
752 /**
753 * Creates a {@link ImsCall} to make a call.
754 *
755 * @param serviceId a service id which is obtained from {@link ImsManager#open}
756 * @param profile a call profile to make the call
757 * (it contains service type, call type, media information, etc.)
758 * @param participants participants to invite the conference call
759 * @param listener listen to the call events from {@link ImsCall}
760 * @return a {@link ImsCall} object
761 * @throws ImsException if calling the IMS service results in an error
762 */
763 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees,
764 ImsCall.Listener listener) throws ImsException {
765 if (DBG) {
766 log("makeCall :: serviceId=" + serviceId
767 + ", profile=" + profile + ", callees=" + callees);
768 }
769
770 checkAndThrowExceptionIfServiceUnavailable();
771
772 ImsCall call = new ImsCall(mContext, profile);
773
774 call.setListener(listener);
775 ImsCallSession session = createCallSession(serviceId, profile);
776
777 if ((callees != null) && (callees.length == 1)) {
778 call.start(session, callees[0]);
779 } else {
780 call.start(session, callees);
781 }
782
783 return call;
784 }
785
786 /**
787 * Creates a {@link ImsCall} to take an incoming call.
788 *
789 * @param serviceId a service id which is obtained from {@link ImsManager#open}
790 * @param incomingCallIntent the incoming call broadcast intent
791 * @param listener to listen to the call events from {@link ImsCall}
792 * @return a {@link ImsCall} object
793 * @throws ImsException if calling the IMS service results in an error
794 */
795 public ImsCall takeCall(int serviceId, Intent incomingCallIntent,
796 ImsCall.Listener listener) throws ImsException {
797 if (DBG) {
798 log("takeCall :: serviceId=" + serviceId
799 + ", incomingCall=" + incomingCallIntent);
800 }
801
802 checkAndThrowExceptionIfServiceUnavailable();
803
804 if (incomingCallIntent == null) {
805 throw new ImsException("Can't retrieve session with null intent",
806 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
807 }
808
809 int incomingServiceId = getServiceId(incomingCallIntent);
810
811 if (serviceId != incomingServiceId) {
812 throw new ImsException("Service id is mismatched in the incoming call intent",
813 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
814 }
815
816 String callId = getCallId(incomingCallIntent);
817
818 if (callId == null) {
819 throw new ImsException("Call ID missing in the incoming call intent",
820 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
821 }
822
823 try {
824 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId);
825
826 if (session == null) {
827 throw new ImsException("No pending session for the call",
828 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL);
829 }
830
831 ImsCall call = new ImsCall(mContext, session.getCallProfile());
832
833 call.attachSession(new ImsCallSession(session));
834 call.setListener(listener);
835
836 return call;
837 } catch (Throwable t) {
838 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED);
839 }
840 }
841
842 /**
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500843 * Gets the config interface to get/set service/capability parameters.
844 *
845 * @return the ImsConfig instance.
846 * @throws ImsException if getting the setting interface results in an error.
847 */
848 public ImsConfig getConfigInterface() throws ImsException {
849
850 if (mConfig == null) {
851 checkAndThrowExceptionIfServiceUnavailable();
852
853 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700854 IImsConfig config = mImsService.getConfigInterface(mPhoneId);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500855 if (config == null) {
856 throw new ImsException("getConfigInterface()",
857 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
858 }
Libin.Tang@motorola.com54953c72014-08-07 15:02:08 -0500859 mConfig = new ImsConfig(config, mContext);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500860 } catch (RemoteException e) {
861 throw new ImsException("getConfigInterface()", e,
862 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
863 }
864 }
865 if (DBG) log("getConfigInterface(), mConfig= " + mConfig);
866 return mConfig;
867 }
868
Etan Cohen82f78122014-12-15 10:10:14 -0800869 public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete)
Shriram Ganeshc403b7b2014-08-14 14:18:57 +0530870 throws ImsException {
871
Etan Cohen82f78122014-12-15 10:10:14 -0800872 checkAndThrowExceptionIfServiceUnavailable();
Shriram Ganeshc403b7b2014-08-14 14:18:57 +0530873
Etan Cohen82f78122014-12-15 10:10:14 -0800874 try {
875 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete);
876 } catch (RemoteException e) {
877 throw new ImsException("setTTYMode()", e,
878 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
879 }
880
Junda Liue7663c02015-06-23 11:16:26 -0700881 if (!getBooleanCarrierConfig(context,
882 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -0800883 setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) &&
884 isEnhanced4gLteModeSettingEnabledByUser(context));
885 }
Shriram Ganeshc403b7b2014-08-14 14:18:57 +0530886 }
887
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500888 /**
Junda Liue7663c02015-06-23 11:16:26 -0700889 * Get the boolean config from carrier config manager.
890 *
891 * @param context the context to get carrier service
892 * @param key config key defined in CarrierConfigManager
893 * @return boolean value of corresponding key.
894 */
895 private static boolean getBooleanCarrierConfig(Context context, String key) {
896 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
897 Context.CARRIER_CONFIG_SERVICE);
Jonathan Basseri2acea6f2015-07-01 15:00:38 -0700898 PersistableBundle b = null;
Junda Liue7663c02015-06-23 11:16:26 -0700899 if (configManager != null) {
Jonathan Basseri2acea6f2015-07-01 15:00:38 -0700900 b = configManager.getConfig();
901 }
902 if (b != null) {
903 return b.getBoolean(key);
Junda Liue7663c02015-06-23 11:16:26 -0700904 } else {
905 // Return static default defined in CarrierConfigManager.
906 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
907 }
908 }
909
910 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700911 * Gets the call ID from the specified incoming call broadcast intent.
912 *
913 * @param incomingCallIntent the incoming call broadcast intent
914 * @return the call ID or null if the intent does not contain it
915 */
916 private static String getCallId(Intent incomingCallIntent) {
917 if (incomingCallIntent == null) {
918 return null;
919 }
920
921 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
922 }
923
924 /**
925 * Gets the service type from the specified incoming call broadcast intent.
926 *
927 * @param incomingCallIntent the incoming call broadcast intent
928 * @return the service identifier or -1 if the intent does not contain it
929 */
930 private static int getServiceId(Intent incomingCallIntent) {
931 if (incomingCallIntent == null) {
932 return (-1);
933 }
934
935 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1);
936 }
937
938 /**
939 * Binds the IMS service only if the service is not created.
940 */
941 private void checkAndThrowExceptionIfServiceUnavailable()
942 throws ImsException {
943 if (mImsService == null) {
944 createImsService(true);
945
946 if (mImsService == null) {
947 throw new ImsException("Service is unavailable",
948 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
949 }
950 }
951 }
952
Etan Cohenabbd7882014-09-26 22:35:35 -0700953 private static String getImsServiceName(int phoneId) {
954 // TODO: MSIM implementation needs to decide on service name as a function of phoneId
Etan Cohend7727462014-07-12 14:54:10 -0700955 return IMS_SERVICE;
956 }
957
Wink Savilleef36ef62014-06-11 08:39:38 -0700958 /**
959 * Binds the IMS service to make/receive the call.
960 */
961 private void createImsService(boolean checkService) {
962 if (checkService) {
Etan Cohenabbd7882014-09-26 22:35:35 -0700963 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -0700964
965 if (binder == null) {
966 return;
967 }
968 }
969
Etan Cohenabbd7882014-09-26 22:35:35 -0700970 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -0700971
972 if (b != null) {
973 try {
974 b.linkToDeath(mDeathRecipient, 0);
975 } catch (RemoteException e) {
976 }
977 }
978
979 mImsService = IImsService.Stub.asInterface(b);
980 }
981
982 /**
983 * Creates a {@link ImsCallSession} with the specified call profile.
984 * Use other methods, if applicable, instead of interacting with
985 * {@link ImsCallSession} directly.
986 *
987 * @param serviceId a service id which is obtained from {@link ImsManager#open}
988 * @param profile a call profile to make the call
989 */
990 private ImsCallSession createCallSession(int serviceId,
991 ImsCallProfile profile) throws ImsException {
992 try {
993 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null));
994 } catch (RemoteException e) {
995 return null;
996 }
997 }
998
999 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass,
1000 ImsConnectionStateListener listener) {
1001 ImsRegistrationListenerProxy proxy =
1002 new ImsRegistrationListenerProxy(serviceClass, listener);
1003 return proxy;
1004 }
1005
Etan Cohena00c9192014-12-23 15:02:29 -08001006 private static void log(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001007 Rlog.d(TAG, s);
1008 }
1009
Etan Cohena00c9192014-12-23 15:02:29 -08001010 private static void loge(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001011 Rlog.e(TAG, s);
1012 }
1013
Etan Cohena00c9192014-12-23 15:02:29 -08001014 private static void loge(String s, Throwable t) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001015 Rlog.e(TAG, s, t);
1016 }
1017
1018 /**
ram7da5a112014-07-16 20:59:27 +05301019 * Used for turning on IMS.if its off already
1020 */
Etan Cohen82f78122014-12-15 10:10:14 -08001021 private void turnOnIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001022 checkAndThrowExceptionIfServiceUnavailable();
1023
ram7da5a112014-07-16 20:59:27 +05301024 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001025 mImsService.turnOnIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301026 } catch (RemoteException e) {
1027 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1028 }
1029 }
1030
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001031 private boolean isImsTurnOffAllowed() {
1032 return getBooleanCarrierConfig(mContext,
1033 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL)
1034 && (!isWfcEnabledByPlatform(mContext)
1035 || !isWfcEnabledByUser(mContext));
1036 }
1037
Etan Cohen82f78122014-12-15 10:10:14 -08001038 private void setAdvanced4GMode(boolean turnOn) throws ImsException {
Etan Cohencfc784d2014-08-07 18:40:31 -07001039 checkAndThrowExceptionIfServiceUnavailable();
1040
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001041 try {
1042 ImsConfig config = getConfigInterface();
1043 if (config != null && (turnOn || !isImsTurnOffAllowed())) {
1044 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
Etan Cohenb651fa52014-10-22 10:51:29 -07001045 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001046 if (isVtEnabledByPlatform(mContext)) {
1047 // TODO: once VT is available on platform:
1048 // - replace the '1' with the current user configuration of VT.
1049 // - separate exception checks for setFeatureValue() failures for VoLTE and VT.
1050 // I.e. if VoLTE fails still try to configure VT.
1051 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
1052 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
1053 }
Etan Cohenb651fa52014-10-22 10:51:29 -07001054 }
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001055 } catch (ImsException e) {
1056 log("setAdvanced4GMode() : " + e);
Etan Cohencfc784d2014-08-07 18:40:31 -07001057 }
Etan Cohencfc784d2014-08-07 18:40:31 -07001058 if (turnOn) {
1059 turnOnIms();
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001060 } else if (isImsTurnOffAllowed()) {
Etan Cohencfc784d2014-08-07 18:40:31 -07001061 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms");
1062 turnOffIms();
1063 }
1064 }
1065
ram7da5a112014-07-16 20:59:27 +05301066 /**
1067 * Used for turning off IMS completely in order to make the device CSFB'ed.
1068 * Once turned off, all calls will be over CS.
1069 */
Etan Cohen82f78122014-12-15 10:10:14 -08001070 private void turnOffIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001071 checkAndThrowExceptionIfServiceUnavailable();
1072
ram7da5a112014-07-16 20:59:27 +05301073 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001074 mImsService.turnOffIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301075 } catch (RemoteException e) {
1076 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1077 }
1078 }
1079
1080 /**
Wink Savilleef36ef62014-06-11 08:39:38 -07001081 * Death recipient class for monitoring IMS service.
1082 */
1083 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient {
1084 @Override
1085 public void binderDied() {
1086 mImsService = null;
1087 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001088 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001089 mEcbm = null;
Wink Savilleef36ef62014-06-11 08:39:38 -07001090
1091 if (mContext != null) {
Etan Cohend7727462014-07-12 14:54:10 -07001092 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN);
Etan Cohenabbd7882014-09-26 22:35:35 -07001093 intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
Etan Cohend7727462014-07-12 14:54:10 -07001094 mContext.sendBroadcast(new Intent(intent));
Wink Savilleef36ef62014-06-11 08:39:38 -07001095 }
1096 }
1097 }
1098
1099 /**
1100 * Adapter class for {@link IImsRegistrationListener}.
1101 */
1102 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub {
1103 private int mServiceClass;
1104 private ImsConnectionStateListener mListener;
1105
1106 public ImsRegistrationListenerProxy(int serviceClass,
1107 ImsConnectionStateListener listener) {
1108 mServiceClass = serviceClass;
1109 mListener = listener;
1110 }
1111
1112 public boolean isSameProxy(int serviceClass) {
1113 return (mServiceClass == serviceClass);
1114 }
1115
1116 @Override
1117 public void registrationConnected() {
1118 if (DBG) {
1119 log("registrationConnected ::");
1120 }
1121
1122 if (mListener != null) {
1123 mListener.onImsConnected();
1124 }
1125 }
1126
1127 @Override
Rekha Kumar14631742015-02-04 10:47:00 -08001128 public void registrationProgressing() {
Wink Savilleef36ef62014-06-11 08:39:38 -07001129 if (DBG) {
Rekha Kumar14631742015-02-04 10:47:00 -08001130 log("registrationProgressing ::");
Wink Savilleef36ef62014-06-11 08:39:38 -07001131 }
1132
1133 if (mListener != null) {
Rekha Kumar14631742015-02-04 10:47:00 -08001134 mListener.onImsProgressing();
1135 }
1136 }
1137
1138 @Override
1139 public void registrationDisconnected(ImsReasonInfo imsReasonInfo) {
1140 if (DBG) {
1141 log("registrationDisconnected :: imsReasonInfo" + imsReasonInfo);
1142 }
1143
1144 if (mListener != null) {
1145 mListener.onImsDisconnected(imsReasonInfo);
Wink Savilleef36ef62014-06-11 08:39:38 -07001146 }
1147 }
1148
1149 @Override
1150 public void registrationResumed() {
1151 if (DBG) {
1152 log("registrationResumed ::");
1153 }
1154
1155 if (mListener != null) {
1156 mListener.onImsResumed();
1157 }
1158 }
1159
1160 @Override
1161 public void registrationSuspended() {
1162 if (DBG) {
1163 log("registrationSuspended ::");
1164 }
1165
1166 if (mListener != null) {
1167 mListener.onImsSuspended();
1168 }
1169 }
1170
1171 @Override
1172 public void registrationServiceCapabilityChanged(int serviceClass, int event) {
1173 log("registrationServiceCapabilityChanged :: serviceClass=" +
1174 serviceClass + ", event=" + event);
1175
1176 if (mListener != null) {
1177 mListener.onImsConnected();
1178 }
1179 }
ram7da5a112014-07-16 20:59:27 +05301180
1181 @Override
1182 public void registrationFeatureCapabilityChanged(int serviceClass,
1183 int[] enabledFeatures, int[] disabledFeatures) {
1184 log("registrationFeatureCapabilityChanged :: serviceClass=" +
1185 serviceClass);
Libin.Tang@motorola.come2296782014-08-19 14:20:01 -05001186 if (mListener != null) {
1187 mListener.onFeatureCapabilityChanged(serviceClass,
1188 enabledFeatures, disabledFeatures);
1189 }
ram7da5a112014-07-16 20:59:27 +05301190 }
1191
Shriram Ganeshd3adfad2015-05-31 10:06:15 -07001192 @Override
1193 public void voiceMessageCountUpdate(int count) {
1194 log("voiceMessageCountUpdate :: count=" + count);
1195
1196 if (mListener != null) {
1197 mListener.onVoiceMessageCountChanged(count);
1198 }
1199 }
1200
Wink Savilleef36ef62014-06-11 08:39:38 -07001201 }
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001202 /**
1203 * Gets the ECBM interface to request ECBM exit.
1204 *
1205 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1206 * @return the ECBM interface instance
1207 * @throws ImsException if getting the ECBM interface results in an error
1208 */
1209 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException {
1210 if (mEcbm == null) {
1211 checkAndThrowExceptionIfServiceUnavailable();
1212
1213 try {
1214 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId);
1215
1216 if (iEcbm == null) {
1217 throw new ImsException("getEcbmInterface()",
1218 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED);
1219 }
1220 mEcbm = new ImsEcbm(iEcbm);
1221 } catch (RemoteException e) {
1222 throw new ImsException("getEcbmInterface()", e,
1223 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1224 }
1225 }
1226 return mEcbm;
1227 }
Wink Savilleef36ef62014-06-11 08:39:38 -07001228}