blob: ecc05e8b1a6c4700544e01d791dca9a8df6a2760 [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;
Pavel Zhamaitsiak4de9cbb2016-02-11 17:21:05 -080022import android.net.Uri;
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -070023import android.os.AsyncTask;
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;
Etan Cohen82f78122014-12-15 10:10:14 -080030import android.provider.Settings;
31import android.telecom.TelecomManager;
Junda Liue7663c02015-06-23 11:16:26 -070032import android.telephony.CarrierConfigManager;
Wink Savilleef36ef62014-06-11 08:39:38 -070033import android.telephony.Rlog;
Etan Cohen82f78122014-12-15 10:10:14 -080034import android.telephony.SubscriptionManager;
Etan Cohencfc784d2014-08-07 18:40:31 -070035import android.telephony.TelephonyManager;
Wink Savilleef36ef62014-06-11 08:39:38 -070036
37import com.android.ims.internal.IImsCallSession;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -070038import com.android.ims.internal.IImsEcbm;
39import com.android.ims.internal.IImsEcbmListener;
Tyler Gunn4d128b62016-04-13 15:44:38 -070040import com.android.ims.internal.IImsMultiEndpoint;
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
Jack Yu2f102bd2015-12-28 15:31:48 -080047import java.io.FileDescriptor;
48import java.io.PrintWriter;
Etan Cohend7727462014-07-12 14:54:10 -070049import java.util.HashMap;
50
Wink Savilleef36ef62014-06-11 08:39:38 -070051/**
52 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
53 * the operator's IMS network. This class is the starting point for any IMS actions.
54 * You can acquire an instance of it with {@link #getInstance getInstance()}.</p>
55 * <p>The APIs in this class allows you to:</p>
56 *
57 * @hide
58 */
59public class ImsManager {
Etan Cohen19604c02014-08-11 14:32:57 -070060
Etan Cohenaf55a402014-09-04 22:34:41 -070061 /*
62 * Debug flag to override configuration flag
63 */
Etan Cohenb651fa52014-10-22 10:51:29 -070064 public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr";
65 public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohenea2b5832014-10-23 18:50:35 -070066 public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr";
67 public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohena00c9192014-12-23 15:02:29 -080068 public static final String PROPERTY_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr";
69 public static final int PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT = 0;
Meng Wang9352c432016-06-08 14:22:20 -070070 public static final String PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE = "persist.dbg.allow_ims_off";
71 public static final int PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT = 0;
Etan Cohenaf55a402014-09-04 22:34:41 -070072
Wink Savilleef36ef62014-06-11 08:39:38 -070073 /**
74 * For accessing the IMS related service.
75 * Internal use only.
76 * @hide
77 */
Etan Cohend7727462014-07-12 14:54:10 -070078 private static final String IMS_SERVICE = "ims";
Wink Savilleef36ef62014-06-11 08:39:38 -070079
80 /**
81 * The result code to be sent back with the incoming call {@link PendingIntent}.
82 * @see #open(PendingIntent, ImsConnectionStateListener)
83 */
84 public static final int INCOMING_CALL_RESULT_CODE = 101;
85
86 /**
87 * Key to retrieve the call ID from an incoming call intent.
88 * @see #open(PendingIntent, ImsConnectionStateListener)
89 */
90 public static final String EXTRA_CALL_ID = "android:imsCallID";
91
92 /**
93 * Action to broadcast when ImsService is up.
94 * Internal use only.
95 * @hide
96 */
97 public static final String ACTION_IMS_SERVICE_UP =
98 "com.android.ims.IMS_SERVICE_UP";
99
100 /**
101 * Action to broadcast when ImsService is down.
102 * Internal use only.
103 * @hide
104 */
105 public static final String ACTION_IMS_SERVICE_DOWN =
106 "com.android.ims.IMS_SERVICE_DOWN";
107
108 /**
Pavel Zhamaitsiak0c2f15c2015-03-12 15:37:54 -0700109 * Action to broadcast when ImsService registration fails.
110 * Internal use only.
111 * @hide
112 */
113 public static final String ACTION_IMS_REGISTRATION_ERROR =
114 "com.android.ims.REGISTRATION_ERROR";
115
116 /**
Etan Cohend7727462014-07-12 14:54:10 -0700117 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
Etan Cohenabbd7882014-09-26 22:35:35 -0700118 * A long value; the phone ID corresponding to the IMS service coming up or down.
Etan Cohend7727462014-07-12 14:54:10 -0700119 * Internal use only.
120 * @hide
121 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700122 public static final String EXTRA_PHONE_ID = "android:phone_id";
Etan Cohend7727462014-07-12 14:54:10 -0700123
124 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700125 * Action for the incoming call intent for the Phone app.
126 * Internal use only.
127 * @hide
128 */
129 public static final String ACTION_IMS_INCOMING_CALL =
130 "com.android.ims.IMS_INCOMING_CALL";
131
132 /**
133 * Part of the ACTION_IMS_INCOMING_CALL intents.
134 * An integer value; service identifier obtained from {@link ImsManager#open}.
135 * Internal use only.
136 * @hide
137 */
138 public static final String EXTRA_SERVICE_ID = "android:imsServiceId";
139
140 /**
141 * Part of the ACTION_IMS_INCOMING_CALL intents.
142 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD.
143 * The value "true" indicates that the incoming call is for USSD.
144 * Internal use only.
145 * @hide
146 */
147 public static final String EXTRA_USSD = "android:ussd";
148
Shriram Ganeshd3adfad2015-05-31 10:06:15 -0700149 /**
150 * Part of the ACTION_IMS_INCOMING_CALL intents.
151 * A boolean value; Flag to indicate whether the call is an unknown
152 * dialing call. Such calls are originated by sending commands (like
153 * AT commands) directly to modem without Android involvement.
154 * Even though they are not incoming calls, they are propagated
155 * to Phone app using same ACTION_IMS_INCOMING_CALL intent.
156 * Internal use only.
157 * @hide
158 */
Anju Mathapati9c033792015-06-16 16:33:16 -0700159 public static final String EXTRA_IS_UNKNOWN_CALL = "android:isUnknown";
Shriram Ganeshd3adfad2015-05-31 10:06:15 -0700160
Wink Savilleef36ef62014-06-11 08:39:38 -0700161 private static final String TAG = "ImsManager";
162 private static final boolean DBG = true;
163
Wink Saville1e5a38a2014-10-23 10:24:46 -0700164 private static HashMap<Integer, ImsManager> sImsManagerInstances =
165 new HashMap<Integer, ImsManager>();
Etan Cohend7727462014-07-12 14:54:10 -0700166
Wink Savilleef36ef62014-06-11 08:39:38 -0700167 private Context mContext;
Etan Cohenabbd7882014-09-26 22:35:35 -0700168 private int mPhoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700169 private IImsService mImsService = null;
170 private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient();
171 // Ut interface for the supplementary service configuration
172 private ImsUt mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500173 // Interface to get/set ims config items
174 private ImsConfig mConfig = null;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700175 private boolean mConfigUpdated = false;
Wink Savilleef36ef62014-06-11 08:39:38 -0700176
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800177 private ImsConfigListener mImsConfigListener;
178
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700179 // ECBM interface
180 private ImsEcbm mEcbm = null;
181
Tyler Gunn4d128b62016-04-13 15:44:38 -0700182 private ImsMultiEndpoint mMultiEndpoint = null;
183
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700184 private boolean mIsVoLteProvisioned = true;
185 private boolean mIsWfcProvisioned = true;
186 private boolean mIsVtProvisioned = true;
187
Wink Savilleef36ef62014-06-11 08:39:38 -0700188 /**
189 * Gets a manager instance.
190 *
191 * @param context application context for creating the manager object
Etan Cohenabbd7882014-09-26 22:35:35 -0700192 * @param phoneId the phone ID for the IMS Service
193 * @return the manager instance corresponding to the phoneId
Wink Savilleef36ef62014-06-11 08:39:38 -0700194 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700195 public static ImsManager getInstance(Context context, int phoneId) {
Etan Cohend7727462014-07-12 14:54:10 -0700196 synchronized (sImsManagerInstances) {
Etan Cohenabbd7882014-09-26 22:35:35 -0700197 if (sImsManagerInstances.containsKey(phoneId))
198 return sImsManagerInstances.get(phoneId);
Wink Savilleef36ef62014-06-11 08:39:38 -0700199
Etan Cohenabbd7882014-09-26 22:35:35 -0700200 ImsManager mgr = new ImsManager(context, phoneId);
201 sImsManagerInstances.put(phoneId, mgr);
Etan Cohend7727462014-07-12 14:54:10 -0700202
203 return mgr;
204 }
Wink Savilleef36ef62014-06-11 08:39:38 -0700205 }
206
Etan Cohen45b5f312014-08-19 15:55:08 -0700207 /**
208 * Returns the user configuration of Enhanced 4G LTE Mode setting
209 */
210 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) {
Sungmin Choi2f1af952016-02-01 17:15:35 +0900211 // If user can't edit Enhanced 4G LTE Mode, it assumes Enhanced 4G LTE Mode is always true.
212 // If user changes SIM from editable mode to uneditable mode, need to return true.
213 if (!getBooleanCarrierConfig(context,
214 CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL)) {
215 return true;
216 }
Libin.Tang@motorola.com8a6bf4b2014-10-10 15:02:41 -0500217 int enabled = android.provider.Settings.Global.getInt(
218 context.getContentResolver(),
Etan Cohenb651fa52014-10-22 10:51:29 -0700219 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
Etan Cohena00c9192014-12-23 15:02:29 -0800220 return (enabled == 1) ? true : false;
Etan Cohen45b5f312014-08-19 15:55:08 -0700221 }
222
223 /**
Etan Cohen82f78122014-12-15 10:10:14 -0800224 * Change persistent Enhanced 4G LTE Mode setting
225 */
226 public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {
227 int value = enabled ? 1 : 0;
228 android.provider.Settings.Global.putInt(
229 context.getContentResolver(),
230 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, value);
231
232 if (isNonTtyOrTtyOnVolteEnabled(context)) {
233 ImsManager imsManager = ImsManager.getInstance(context,
234 SubscriptionManager.getDefaultVoicePhoneId());
235 if (imsManager != null) {
236 try {
237 imsManager.setAdvanced4GMode(enabled);
238 } catch (ImsException ie) {
239 // do nothing
240 }
241 }
242 }
243 }
244
245 /**
246 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is
247 * supported.
248 */
249 public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) {
Junda Liue7663c02015-06-23 11:16:26 -0700250 if (getBooleanCarrierConfig(context,
fionaxu5803ef02016-03-08 11:48:48 -0800251 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -0800252 return true;
253 }
254
255 return Settings.Secure.getInt(context.getContentResolver(),
256 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF)
257 == TelecomManager.TTY_MODE_OFF;
258 }
259
260 /**
Etan Cohenea2b5832014-10-23 18:50:35 -0700261 * Returns a platform configuration for VoLTE which may override the user setting.
Etan Cohen45b5f312014-08-19 15:55:08 -0700262 */
Etan Cohenea2b5832014-10-23 18:50:35 -0700263 public static boolean isVolteEnabledByPlatform(Context context) {
Etan Cohenb651fa52014-10-22 10:51:29 -0700264 if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE,
265 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) {
Etan Cohenaf55a402014-09-04 22:34:41 -0700266 return true;
267 }
268
Etan Cohenb5388a32014-11-26 11:57:47 -0800269 return context.getResources().getBoolean(
Junda Liue7663c02015-06-23 11:16:26 -0700270 com.android.internal.R.bool.config_device_volte_available)
271 && getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700272 CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL)
273 && isGbaValid(context);
Etan Cohenb5388a32014-11-26 11:57:47 -0800274 }
275
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700276 /**
Etan Cohenb5388a32014-11-26 11:57:47 -0800277 * Indicates whether VoLTE is provisioned on device
278 */
279 public static boolean isVolteProvisionedOnDevice(Context context) {
Junda Liue7663c02015-06-23 11:16:26 -0700280 if (getBooleanCarrierConfig(context,
281 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
Etan Cohenb5388a32014-11-26 11:57:47 -0800282 ImsManager mgr = ImsManager.getInstance(context,
Jonathan Basserid7133652015-04-07 19:54:24 -0700283 SubscriptionManager.getDefaultVoicePhoneId());
Etan Cohenb5388a32014-11-26 11:57:47 -0800284 if (mgr != null) {
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700285 return mgr.mIsVoLteProvisioned;
Etan Cohenb5388a32014-11-26 11:57:47 -0800286 }
287 }
288
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700289 return true;
290 }
291
292 /**
293 * Indicates whether VoWifi is provisioned on device
294 */
295 public static boolean isWfcProvisionedOnDevice(Context context) {
296 if (getBooleanCarrierConfig(context,
297 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
298 ImsManager mgr = ImsManager.getInstance(context,
299 SubscriptionManager.getDefaultVoicePhoneId());
300 if (mgr != null) {
301 return mgr.mIsWfcProvisioned;
302 }
303 }
304
305 return true;
306 }
307
308 /**
309 * Indicates whether VT is provisioned on device
310 */
311 public static boolean isVtProvisionedOnDevice(Context context) {
312 if (getBooleanCarrierConfig(context,
313 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
314 ImsManager mgr = ImsManager.getInstance(context,
315 SubscriptionManager.getDefaultVoicePhoneId());
316 if (mgr != null) {
317 return mgr.mIsVtProvisioned;
318 }
319 }
320
321 return true;
Etan Cohenb651fa52014-10-22 10:51:29 -0700322 }
323
Etan Cohenea2b5832014-10-23 18:50:35 -0700324 /**
325 * Returns a platform configuration for VT which may override the user setting.
326 *
327 * Note: VT presumes that VoLTE is enabled (these are configuration settings
328 * which must be done correctly).
329 */
Etan Cohenb651fa52014-10-22 10:51:29 -0700330 public static boolean isVtEnabledByPlatform(Context context) {
Etan Cohenea2b5832014-10-23 18:50:35 -0700331 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE,
332 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) {
333 return true;
334 }
335
Etan Cohenb651fa52014-10-22 10:51:29 -0700336 return
337 context.getResources().getBoolean(
338 com.android.internal.R.bool.config_device_vt_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700339 getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700340 CarrierConfigManager.KEY_CARRIER_VT_AVAILABLE_BOOL) &&
341 isGbaValid(context);
Etan Cohen45b5f312014-08-19 15:55:08 -0700342 }
343
Etan Cohena00c9192014-12-23 15:02:29 -0800344 /**
Etan Cohena7d32e82015-05-04 18:02:09 -0700345 * Returns the user configuration of VT setting
346 */
347 public static boolean isVtEnabledByUser(Context context) {
348 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
349 android.provider.Settings.Global.VT_IMS_ENABLED,
350 ImsConfig.FeatureValueConstants.ON);
351 return (enabled == 1) ? true : false;
352 }
353
354 /**
355 * Change persistent VT enabled setting
356 */
357 public static void setVtSetting(Context context, boolean enabled) {
358 int value = enabled ? 1 : 0;
359 android.provider.Settings.Global.putInt(context.getContentResolver(),
360 android.provider.Settings.Global.VT_IMS_ENABLED, value);
361
362 ImsManager imsManager = ImsManager.getInstance(context,
363 SubscriptionManager.getDefaultVoicePhoneId());
364 if (imsManager != null) {
365 try {
366 ImsConfig config = imsManager.getConfigInterface();
367 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
368 TelephonyManager.NETWORK_TYPE_LTE,
369 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800370 : ImsConfig.FeatureValueConstants.OFF,
371 imsManager.mImsConfigListener);
Etan Cohena7d32e82015-05-04 18:02:09 -0700372
373 if (enabled) {
374 imsManager.turnOnIms();
Meng Wang9352c432016-06-08 14:22:20 -0700375 } else if (isTurnOffImsAllowedByPlatform(context)
Pavel Zhamaitsiak4ca0cde2015-12-22 16:51:57 -0800376 && (!isVolteEnabledByPlatform(context)
Etan Cohena7d32e82015-05-04 18:02:09 -0700377 || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
378 log("setVtSetting() : imsServiceAllowTurnOff -> turnOffIms");
379 imsManager.turnOffIms();
380 }
381 } catch (ImsException e) {
382 loge("setVtSetting(): " + e);
383 }
384 }
385 }
386
Meng Wang9352c432016-06-08 14:22:20 -0700387 /*
388 * Returns whether turning off ims is allowed by platform.
389 * The platform property may override the carrier config.
390 */
391 private static boolean isTurnOffImsAllowedByPlatform(Context context) {
392 if (SystemProperties.getInt(PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE,
393 PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT) == 1) {
394 return true;
395 }
396 return getBooleanCarrierConfig(context,
397 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL);
398 }
399
Etan Cohena7d32e82015-05-04 18:02:09 -0700400 /**
Etan Cohena00c9192014-12-23 15:02:29 -0800401 * Returns the user configuration of WFC setting
402 */
403 public static boolean isWfcEnabledByUser(Context context) {
404 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
405 android.provider.Settings.Global.WFC_IMS_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -0800406 getBooleanCarrierConfig(context,
407 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL) ?
408 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800409 return (enabled == 1) ? true : false;
410 }
411
412 /**
413 * Change persistent WFC enabled setting
414 */
415 public static void setWfcSetting(Context context, boolean enabled) {
416 int value = enabled ? 1 : 0;
417 android.provider.Settings.Global.putInt(context.getContentResolver(),
418 android.provider.Settings.Global.WFC_IMS_ENABLED, value);
419
420 ImsManager imsManager = ImsManager.getInstance(context,
421 SubscriptionManager.getDefaultVoicePhoneId());
422 if (imsManager != null) {
423 try {
424 ImsConfig config = imsManager.getConfigInterface();
Etan Cohena00c9192014-12-23 15:02:29 -0800425 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
Nathan Harold3a99f782015-07-24 15:02:34 -0700426 TelephonyManager.NETWORK_TYPE_IWLAN,
Etan Cohena00c9192014-12-23 15:02:29 -0800427 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800428 : ImsConfig.FeatureValueConstants.OFF,
429 imsManager.mImsConfigListener);
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800430
431 if (enabled) {
432 imsManager.turnOnIms();
Meng Wang9352c432016-06-08 14:22:20 -0700433 } else if (isTurnOffImsAllowedByPlatform(context)
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800434 && (!isVolteEnabledByPlatform(context)
435 || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
436 log("setWfcSetting() : imsServiceAllowTurnOff -> turnOffIms");
437 imsManager.turnOffIms();
438 }
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700439
440 // Force IMS to register over LTE when turning off WFC
441 setWfcModeInternal(context, enabled
442 ? getWfcMode(context)
443 : ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED);
Etan Cohena00c9192014-12-23 15:02:29 -0800444 } catch (ImsException e) {
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800445 loge("setWfcSetting(): " + e);
Etan Cohena00c9192014-12-23 15:02:29 -0800446 }
447 }
448 }
449
450 /**
451 * Returns the user configuration of WFC modem setting
452 */
453 public static int getWfcMode(Context context) {
454 int setting = android.provider.Settings.Global.getInt(context.getContentResolver(),
fionaxu5803ef02016-03-08 11:48:48 -0800455 android.provider.Settings.Global.WFC_IMS_MODE, getIntCarrierConfig(context,
456 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
Etan Cohena00c9192014-12-23 15:02:29 -0800457 if (DBG) log("getWfcMode - setting=" + setting);
458 return setting;
459 }
460
461 /**
462 * Returns the user configuration of WFC modem setting
463 */
464 public static void setWfcMode(Context context, int wfcMode) {
465 if (DBG) log("setWfcMode - setting=" + wfcMode);
466 android.provider.Settings.Global.putInt(context.getContentResolver(),
467 android.provider.Settings.Global.WFC_IMS_MODE, wfcMode);
468
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700469 setWfcModeInternal(context, wfcMode);
470 }
471
472 private static void setWfcModeInternal(Context context, int wfcMode) {
Etan Cohena00c9192014-12-23 15:02:29 -0800473 final ImsManager imsManager = ImsManager.getInstance(context,
474 SubscriptionManager.getDefaultVoicePhoneId());
475 if (imsManager != null) {
476 final int value = wfcMode;
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700477 Thread thread = new Thread(new Runnable() {
Etan Cohena00c9192014-12-23 15:02:29 -0800478 public void run() {
479 try {
480 imsManager.getConfigInterface().setProvisionedValue(
481 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE,
482 value);
483 } catch (ImsException e) {
484 // do nothing
485 }
486 }
487 });
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700488 thread.start();
Etan Cohena00c9192014-12-23 15:02:29 -0800489 }
490 }
491
492 /**
493 * Returns the user configuration of WFC roaming setting
494 */
495 public static boolean isWfcRoamingEnabledByUser(Context context) {
496 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
497 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -0800498 getBooleanCarrierConfig(context,
499 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ?
500 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800501 return (enabled == 1) ? true : false;
502 }
503
504 /**
505 * Change persistent WFC roaming enabled setting
506 */
507 public static void setWfcRoamingSetting(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800508 android.provider.Settings.Global.putInt(context.getContentResolver(),
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700509 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -0800510 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700511 : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800512
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700513 setWfcRoamingSettingInternal(context, enabled);
514 }
515
516 private static void setWfcRoamingSettingInternal(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800517 final ImsManager imsManager = ImsManager.getInstance(context,
518 SubscriptionManager.getDefaultVoicePhoneId());
519 if (imsManager != null) {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700520 final int value = enabled
521 ? ImsConfig.FeatureValueConstants.ON
522 : ImsConfig.FeatureValueConstants.OFF;
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700523 Thread thread = new Thread(new Runnable() {
Etan Cohena00c9192014-12-23 15:02:29 -0800524 public void run() {
525 try {
526 imsManager.getConfigInterface().setProvisionedValue(
527 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_ROAMING,
528 value);
529 } catch (ImsException e) {
530 // do nothing
531 }
532 }
533 });
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700534 thread.start();
Etan Cohena00c9192014-12-23 15:02:29 -0800535 }
536 }
537
538 /**
539 * Returns a platform configuration for WFC which may override the user
540 * setting. Note: WFC presumes that VoLTE is enabled (these are
541 * configuration settings which must be done correctly).
542 */
543 public static boolean isWfcEnabledByPlatform(Context context) {
544 if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE,
545 PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT) == 1) {
546 return true;
547 }
548
549 return
550 context.getResources().getBoolean(
551 com.android.internal.R.bool.config_device_wfc_ims_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700552 getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700553 CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) &&
554 isGbaValid(context);
555 }
556
557 /**
558 * If carrier requires that IMS is only available if GBA capable SIM is used,
559 * then this function checks GBA bit in EF IST.
560 *
561 * Format of EF IST is defined in 3GPP TS 31.103 (Section 4.2.7).
562 */
563 private static boolean isGbaValid(Context context) {
564 if (getBooleanCarrierConfig(context,
565 CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) {
566 final TelephonyManager telephonyManager = TelephonyManager.getDefault();
567 String efIst = telephonyManager.getIsimIst();
568 if (efIst == null) {
569 loge("ISF is NULL");
570 return true;
571 }
572 boolean result = efIst != null && efIst.length() > 1 &&
573 (0x02 & (byte)efIst.charAt(1)) != 0;
574 if (DBG) log("GBA capable=" + result + ", ISF=" + efIst);
575 return result;
576 }
577 return true;
Etan Cohena00c9192014-12-23 15:02:29 -0800578 }
579
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700580 /**
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700581 * This function should be called when ImsConfig.ACTION_IMS_CONFIG_CHANGED is received.
582 *
583 * We cannot register receiver in ImsManager because this would lead to resource leak.
584 * ImsManager can be created in different processes and it is not notified when that process
585 * is about to be terminated.
586 *
587 * @hide
588 * */
589 public static void onProvisionedValueChanged(Context context, int item, String value) {
590 if (DBG) Rlog.d(TAG, "onProvisionecValueChanged: item=" + item + " val=" + value);
591 ImsManager mgr = ImsManager.getInstance(context,
592 SubscriptionManager.getDefaultVoicePhoneId());
593
594 switch (item) {
595 case ImsConfig.ConfigConstants.VLT_SETTING_ENABLED:
596 mgr.mIsVoLteProvisioned = value.equals("1");
597 if (DBG) Rlog.d(TAG,"mIsVoLteProvisioned = " + mgr.mIsVoLteProvisioned);
598 break;
599
600 case ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED:
601 mgr.mIsWfcProvisioned = value.equals("1");
602 if (DBG) Rlog.d(TAG,"mIsWfcProvisioned = " + mgr.mIsWfcProvisioned);
603 break;
604
605 // TODO: Update mIsVtProvisioned when VT provisioning become available
606 }
607 }
608
609 private class AsyncUpdateProvisionedValues extends AsyncTask<Void, Void, Void> {
610 @Override
611 protected Void doInBackground(Void... params) {
612 // disable on any error
613 mIsVoLteProvisioned = false;
614 mIsWfcProvisioned = false;
615 mIsVtProvisioned = false;
616
617 try {
618 ImsConfig config = getConfigInterface();
619 if (config != null) {
620 mIsVoLteProvisioned = getProvisionedBool(config,
621 ImsConfig.ConfigConstants.VLT_SETTING_ENABLED);
622 if (DBG) Rlog.d(TAG, "mIsVoLteProvisioned = " + mIsVoLteProvisioned);
623
624 mIsWfcProvisioned = getProvisionedBool(config,
625 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED);
626 if (DBG) Rlog.d(TAG, "mIsWfcProvisioned = " + mIsWfcProvisioned);
627
628 // TODO: Update mIsVtProvisioned when VT provisioning become available
629 }
630 } catch (ImsException ie) {
631 Rlog.e(TAG, "AsyncUpdateProvisionedValues error: " + ie);
632 }
633
634 return null;
635 }
636
637 private boolean getProvisionedBool(ImsConfig config, int item) throws ImsException {
638 return config.getProvisionedValue(item) == ImsConfig.FeatureValueConstants.ON;
639 }
640 }
641
642 /** Asynchronously get VoLTE, WFC, VT provisioning statuses */
643 private void updateProvisionedValues() {
644 if (getBooleanCarrierConfig(mContext,
645 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
646
647 new AsyncUpdateProvisionedValues().execute();
648 }
649 }
650
651 /**
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700652 * Sync carrier config and user settings with ImsConfig.
653 *
654 * @param context for the manager object
655 * @param phoneId phone id
656 * @param force update
657 */
658 public static void updateImsServiceConfig(Context context, int phoneId, boolean force) {
Pavel Zhamaitsiakfc202992016-03-29 18:07:38 -0700659 if (!force) {
660 if (TelephonyManager.getDefault().getSimState() != TelephonyManager.SIM_STATE_READY) {
661 log("updateImsServiceConfig: SIM not ready");
662 // Don't disable IMS if SIM is not ready
663 return;
664 }
665 }
666
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700667 final ImsManager imsManager = ImsManager.getInstance(context, phoneId);
668 if (imsManager != null && (!imsManager.mConfigUpdated || force)) {
669 try {
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700670 imsManager.updateProvisionedValues();
671
Pavel Zhamaitsiakd46779c2016-06-03 10:39:51 -0700672 // TODO: Extend ImsConfig API and set all feature values in single function call.
673
674 // Note: currently the order of updates is set to produce different order of
675 // setFeatureValue() function calls from setAdvanced4GMode(). This is done to
676 // differentiate this code path from vendor code perspective.
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800677 boolean isImsUsed = imsManager.updateVolteFeatureValue();
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800678 isImsUsed |= imsManager.updateWfcFeatureAndProvisionedValues();
Pavel Zhamaitsiakd46779c2016-06-03 10:39:51 -0700679 isImsUsed |= imsManager.updateVideoCallFeatureValue();
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700680
Meng Wang9352c432016-06-08 14:22:20 -0700681 if (isImsUsed || !isTurnOffImsAllowedByPlatform(context)) {
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800682 // Turn on IMS if it is used.
683 // Also, if turning off is not allowed for current carrier,
684 // we need to turn IMS on because it might be turned off before
685 // phone switched to current carrier.
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700686 imsManager.turnOnIms();
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800687 } else {
688 // Turn off IMS if it is not used AND turning off is allowed for carrier.
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700689 imsManager.turnOffIms();
690 }
691
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700692 imsManager.mConfigUpdated = true;
693 } catch (ImsException e) {
694 loge("updateImsServiceConfig: " + e);
695 imsManager.mConfigUpdated = false;
696 }
697 }
698 }
699
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700700 /**
701 * Update VoLTE config
702 * @return whether feature is On
703 * @throws ImsException
704 */
705 private boolean updateVolteFeatureValue() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700706 boolean available = isVolteEnabledByPlatform(mContext);
707 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext);
708 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800709 boolean isFeatureOn = available && enabled && isNonTty;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700710
711 log("updateVolteFeatureValue: available = " + available
712 + ", enabled = " + enabled
713 + ", nonTTY = " + isNonTty);
714
715 getConfigInterface().setFeatureValue(
716 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
717 TelephonyManager.NETWORK_TYPE_LTE,
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800718 isFeatureOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700719 ImsConfig.FeatureValueConstants.ON :
720 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800721 mImsConfigListener);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700722
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800723 return isFeatureOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700724 }
725
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700726 /**
727 * Update VC config
728 * @return whether feature is On
729 * @throws ImsException
730 */
731 private boolean updateVideoCallFeatureValue() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700732 boolean available = isVtEnabledByPlatform(mContext);
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700733 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext) &&
Pavel Zhamaitsiak92b54b22016-04-01 15:55:47 -0700734 isVtEnabledByUser(mContext);
Omkar Kolangadec0f450d2016-02-11 20:59:48 +0530735 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800736 boolean isFeatureOn = available && enabled && isNonTty;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700737
738 log("updateVideoCallFeatureValue: available = " + available
739 + ", enabled = " + enabled
740 + ", nonTTY = " + isNonTty);
741
742 getConfigInterface().setFeatureValue(
743 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
744 TelephonyManager.NETWORK_TYPE_LTE,
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800745 isFeatureOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700746 ImsConfig.FeatureValueConstants.ON :
747 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800748 mImsConfigListener);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700749
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800750 return isFeatureOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700751 }
752
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700753 /**
754 * Update WFC config
755 * @return whether feature is On
756 * @throws ImsException
757 */
758 private boolean updateWfcFeatureAndProvisionedValues() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700759 boolean available = isWfcEnabledByPlatform(mContext);
760 boolean enabled = isWfcEnabledByUser(mContext);
761 int mode = getWfcMode(mContext);
762 boolean roaming = isWfcRoamingEnabledByUser(mContext);
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800763 boolean isFeatureOn = available && enabled;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700764
765 log("updateWfcFeatureAndProvisionedValues: available = " + available
766 + ", enabled = " + enabled
767 + ", mode = " + mode
768 + ", roaming = " + roaming);
769
770 getConfigInterface().setFeatureValue(
Pavel Zhamaitsiake6f99432015-09-11 10:29:30 -0700771 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
772 TelephonyManager.NETWORK_TYPE_IWLAN,
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800773 isFeatureOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700774 ImsConfig.FeatureValueConstants.ON :
775 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800776 mImsConfigListener);
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700777
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800778 if (!isFeatureOn) {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700779 mode = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED;
780 roaming = false;
781 }
782 setWfcModeInternal(mContext, mode);
783 setWfcRoamingSettingInternal(mContext, roaming);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700784
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800785 return isFeatureOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700786 }
787
Etan Cohenabbd7882014-09-26 22:35:35 -0700788 private ImsManager(Context context, int phoneId) {
Wink Savilleef36ef62014-06-11 08:39:38 -0700789 mContext = context;
Etan Cohenabbd7882014-09-26 22:35:35 -0700790 mPhoneId = phoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700791 createImsService(true);
792 }
793
Etan Cohenf4311122015-02-26 17:47:13 -0800794 /*
795 * Returns a flag indicating whether the IMS service is available.
796 */
797 public boolean isServiceAvailable() {
798 if (mImsService != null) {
799 return true;
800 }
801
802 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
803 if (binder != null) {
804 return true;
805 }
806
807 return false;
808 }
809
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800810 public void setImsConfigListener(ImsConfigListener listener) {
811 mImsConfigListener = listener;
812 }
813
Wink Savilleef36ef62014-06-11 08:39:38 -0700814 /**
815 * Opens the IMS service for making calls and/or receiving generic IMS calls.
816 * The caller may make subsquent calls through {@link #makeCall}.
817 * The IMS service will register the device to the operator's network with the credentials
818 * (from ISIM) periodically in order to receive calls from the operator's network.
819 * When the IMS service receives a new call, it will send out an intent with
820 * the provided action string.
821 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call.
822 *
823 * @param serviceClass a service class specified in {@link ImsServiceClass}
824 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
825 * @param incomingCallPendingIntent When an incoming call is received,
826 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to
827 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE}
828 * as the result code and the intent to fill in the call ID; It cannot be null
829 * @param listener To listen to IMS registration events; It cannot be null
830 * @return identifier (greater than 0) for the specified service
831 * @throws NullPointerException if {@code incomingCallPendingIntent}
832 * or {@code listener} is null
833 * @throws ImsException if calling the IMS service results in an error
834 * @see #getCallId
835 * @see #getServiceId
836 */
837 public int open(int serviceClass, PendingIntent incomingCallPendingIntent,
838 ImsConnectionStateListener listener) throws ImsException {
839 checkAndThrowExceptionIfServiceUnavailable();
840
841 if (incomingCallPendingIntent == null) {
842 throw new NullPointerException("incomingCallPendingIntent can't be null");
843 }
844
845 if (listener == null) {
846 throw new NullPointerException("listener can't be null");
847 }
848
849 int result = 0;
850
851 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700852 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent,
Wink Savilleef36ef62014-06-11 08:39:38 -0700853 createRegistrationListenerProxy(serviceClass, listener));
854 } catch (RemoteException e) {
855 throw new ImsException("open()", e,
856 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
857 }
858
859 if (result <= 0) {
860 // If the return value is a minus value,
861 // it means that an error occurred in the service.
862 // So, it needs to convert to the reason code specified in ImsReasonInfo.
863 throw new ImsException("open()", (result * (-1)));
864 }
865
866 return result;
867 }
868
869 /**
Pavel Zhamaitsiakce410172016-04-15 10:55:56 -0700870 * Adds registration listener to the IMS service.
871 *
872 * @param serviceClass a service class specified in {@link ImsServiceClass}
873 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
874 * @param listener To listen to IMS registration events; It cannot be null
875 * @throws NullPointerException if {@code listener} is null
876 * @throws ImsException if calling the IMS service results in an error
877 */
878 public void addRegistrationListener(int serviceClass, ImsConnectionStateListener listener)
879 throws ImsException {
880 checkAndThrowExceptionIfServiceUnavailable();
881
882 if (listener == null) {
883 throw new NullPointerException("listener can't be null");
884 }
885
886 try {
887 mImsService.addRegistrationListener(mPhoneId, serviceClass,
888 createRegistrationListenerProxy(serviceClass, listener));
889 } catch (RemoteException e) {
890 throw new ImsException("addRegistrationListener()", e,
891 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
892 }
893 }
894
895 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700896 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls.
897 * All the resources that were allocated to the service are also released.
898 *
899 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open}
900 * @throws ImsException if calling the IMS service results in an error
901 */
902 public void close(int serviceId) throws ImsException {
903 checkAndThrowExceptionIfServiceUnavailable();
904
905 try {
906 mImsService.close(serviceId);
907 } catch (RemoteException e) {
908 throw new ImsException("close()", e,
909 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
910 } finally {
911 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500912 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700913 mEcbm = null;
Tyler Gunn4d128b62016-04-13 15:44:38 -0700914 mMultiEndpoint = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700915 }
916 }
917
918 /**
919 * Gets the configuration interface to provision / withdraw the supplementary service settings.
920 *
921 * @param serviceId a service id which is obtained from {@link ImsManager#open}
922 * @return the Ut interface instance
923 * @throws ImsException if getting the Ut interface results in an error
924 */
925 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId)
926 throws ImsException {
927 // FIXME: manage the multiple Ut interfaces based on the service id
928 if (mUt == null) {
929 checkAndThrowExceptionIfServiceUnavailable();
930
931 try {
932 IImsUt iUt = mImsService.getUtInterface(serviceId);
933
934 if (iUt == null) {
935 throw new ImsException("getSupplementaryServiceConfiguration()",
936 ImsReasonInfo.CODE_UT_NOT_SUPPORTED);
937 }
938
939 mUt = new ImsUt(iUt);
940 } catch (RemoteException e) {
941 throw new ImsException("getSupplementaryServiceConfiguration()", e,
942 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
943 }
944 }
945
946 return mUt;
947 }
948
949 /**
950 * Checks if the IMS service has successfully registered to the IMS network
951 * with the specified service & call type.
952 *
953 * @param serviceId a service id which is obtained from {@link ImsManager#open}
954 * @param serviceType a service type that is specified in {@link ImsCallProfile}
955 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
956 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
957 * @param callType a call type that is specified in {@link ImsCallProfile}
958 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
959 * {@link ImsCallProfile#CALL_TYPE_VOICE}
960 * {@link ImsCallProfile#CALL_TYPE_VT}
961 * {@link ImsCallProfile#CALL_TYPE_VS}
962 * @return true if the specified service id is connected to the IMS network;
963 * false otherwise
964 * @throws ImsException if calling the IMS service results in an error
965 */
966 public boolean isConnected(int serviceId, int serviceType, int callType)
967 throws ImsException {
968 checkAndThrowExceptionIfServiceUnavailable();
969
970 try {
971 return mImsService.isConnected(serviceId, serviceType, callType);
972 } catch (RemoteException e) {
973 throw new ImsException("isServiceConnected()", e,
974 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
975 }
976 }
977
978 /**
979 * Checks if the specified IMS service is opend.
980 *
981 * @param serviceId a service id which is obtained from {@link ImsManager#open}
982 * @return true if the specified service id is opened; false otherwise
983 * @throws ImsException if calling the IMS service results in an error
984 */
985 public boolean isOpened(int serviceId) throws ImsException {
986 checkAndThrowExceptionIfServiceUnavailable();
987
988 try {
989 return mImsService.isOpened(serviceId);
990 } catch (RemoteException e) {
991 throw new ImsException("isOpened()", e,
992 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
993 }
994 }
995
996 /**
997 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
998 *
999 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1000 * @param serviceType a service type that is specified in {@link ImsCallProfile}
1001 * {@link ImsCallProfile#SERVICE_TYPE_NONE}
1002 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
1003 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
1004 * @param callType a call type that is specified in {@link ImsCallProfile}
1005 * {@link ImsCallProfile#CALL_TYPE_VOICE}
1006 * {@link ImsCallProfile#CALL_TYPE_VT}
1007 * {@link ImsCallProfile#CALL_TYPE_VT_TX}
1008 * {@link ImsCallProfile#CALL_TYPE_VT_RX}
1009 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
1010 * {@link ImsCallProfile#CALL_TYPE_VS}
1011 * {@link ImsCallProfile#CALL_TYPE_VS_TX}
1012 * {@link ImsCallProfile#CALL_TYPE_VS_RX}
1013 * @return a {@link ImsCallProfile} object
1014 * @throws ImsException if calling the IMS service results in an error
1015 */
1016 public ImsCallProfile createCallProfile(int serviceId,
1017 int serviceType, int callType) throws ImsException {
1018 checkAndThrowExceptionIfServiceUnavailable();
1019
1020 try {
1021 return mImsService.createCallProfile(serviceId, serviceType, callType);
1022 } catch (RemoteException e) {
1023 throw new ImsException("createCallProfile()", e,
1024 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1025 }
1026 }
1027
1028 /**
1029 * Creates a {@link ImsCall} to make a call.
1030 *
1031 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1032 * @param profile a call profile to make the call
1033 * (it contains service type, call type, media information, etc.)
1034 * @param participants participants to invite the conference call
1035 * @param listener listen to the call events from {@link ImsCall}
1036 * @return a {@link ImsCall} object
1037 * @throws ImsException if calling the IMS service results in an error
1038 */
1039 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees,
1040 ImsCall.Listener listener) throws ImsException {
1041 if (DBG) {
1042 log("makeCall :: serviceId=" + serviceId
1043 + ", profile=" + profile + ", callees=" + callees);
1044 }
1045
1046 checkAndThrowExceptionIfServiceUnavailable();
1047
1048 ImsCall call = new ImsCall(mContext, profile);
1049
1050 call.setListener(listener);
1051 ImsCallSession session = createCallSession(serviceId, profile);
1052
1053 if ((callees != null) && (callees.length == 1)) {
1054 call.start(session, callees[0]);
1055 } else {
1056 call.start(session, callees);
1057 }
1058
1059 return call;
1060 }
1061
1062 /**
1063 * Creates a {@link ImsCall} to take an incoming call.
1064 *
1065 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1066 * @param incomingCallIntent the incoming call broadcast intent
1067 * @param listener to listen to the call events from {@link ImsCall}
1068 * @return a {@link ImsCall} object
1069 * @throws ImsException if calling the IMS service results in an error
1070 */
1071 public ImsCall takeCall(int serviceId, Intent incomingCallIntent,
1072 ImsCall.Listener listener) throws ImsException {
1073 if (DBG) {
1074 log("takeCall :: serviceId=" + serviceId
1075 + ", incomingCall=" + incomingCallIntent);
1076 }
1077
1078 checkAndThrowExceptionIfServiceUnavailable();
1079
1080 if (incomingCallIntent == null) {
1081 throw new ImsException("Can't retrieve session with null intent",
1082 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
1083 }
1084
1085 int incomingServiceId = getServiceId(incomingCallIntent);
1086
1087 if (serviceId != incomingServiceId) {
1088 throw new ImsException("Service id is mismatched in the incoming call intent",
1089 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
1090 }
1091
1092 String callId = getCallId(incomingCallIntent);
1093
1094 if (callId == null) {
1095 throw new ImsException("Call ID missing in the incoming call intent",
1096 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
1097 }
1098
1099 try {
1100 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId);
1101
1102 if (session == null) {
1103 throw new ImsException("No pending session for the call",
1104 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL);
1105 }
1106
1107 ImsCall call = new ImsCall(mContext, session.getCallProfile());
1108
1109 call.attachSession(new ImsCallSession(session));
1110 call.setListener(listener);
1111
1112 return call;
1113 } catch (Throwable t) {
1114 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED);
1115 }
1116 }
1117
1118 /**
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001119 * Gets the config interface to get/set service/capability parameters.
1120 *
1121 * @return the ImsConfig instance.
1122 * @throws ImsException if getting the setting interface results in an error.
1123 */
1124 public ImsConfig getConfigInterface() throws ImsException {
1125
1126 if (mConfig == null) {
1127 checkAndThrowExceptionIfServiceUnavailable();
1128
1129 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001130 IImsConfig config = mImsService.getConfigInterface(mPhoneId);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001131 if (config == null) {
1132 throw new ImsException("getConfigInterface()",
1133 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
1134 }
Libin.Tang@motorola.com54953c72014-08-07 15:02:08 -05001135 mConfig = new ImsConfig(config, mContext);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001136 } catch (RemoteException e) {
1137 throw new ImsException("getConfigInterface()", e,
1138 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1139 }
1140 }
1141 if (DBG) log("getConfigInterface(), mConfig= " + mConfig);
1142 return mConfig;
1143 }
1144
Etan Cohen82f78122014-12-15 10:10:14 -08001145 public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete)
Shriram Ganeshc403b7b2014-08-14 14:18:57 +05301146 throws ImsException {
1147
Etan Cohen82f78122014-12-15 10:10:14 -08001148 checkAndThrowExceptionIfServiceUnavailable();
Shriram Ganeshc403b7b2014-08-14 14:18:57 +05301149
Etan Cohen82f78122014-12-15 10:10:14 -08001150 try {
1151 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete);
1152 } catch (RemoteException e) {
1153 throw new ImsException("setTTYMode()", e,
1154 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1155 }
1156
Junda Liue7663c02015-06-23 11:16:26 -07001157 if (!getBooleanCarrierConfig(context,
1158 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -08001159 setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) &&
1160 isEnhanced4gLteModeSettingEnabledByUser(context));
1161 }
Shriram Ganeshc403b7b2014-08-14 14:18:57 +05301162 }
1163
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001164 /**
Junda Liue7663c02015-06-23 11:16:26 -07001165 * Get the boolean config from carrier config manager.
1166 *
1167 * @param context the context to get carrier service
1168 * @param key config key defined in CarrierConfigManager
1169 * @return boolean value of corresponding key.
1170 */
1171 private static boolean getBooleanCarrierConfig(Context context, String key) {
1172 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
1173 Context.CARRIER_CONFIG_SERVICE);
Jonathan Basseri2acea6f2015-07-01 15:00:38 -07001174 PersistableBundle b = null;
Junda Liue7663c02015-06-23 11:16:26 -07001175 if (configManager != null) {
Jonathan Basseri2acea6f2015-07-01 15:00:38 -07001176 b = configManager.getConfig();
1177 }
1178 if (b != null) {
1179 return b.getBoolean(key);
Junda Liue7663c02015-06-23 11:16:26 -07001180 } else {
1181 // Return static default defined in CarrierConfigManager.
1182 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
1183 }
1184 }
1185
1186 /**
fionaxu5803ef02016-03-08 11:48:48 -08001187 * Get the int config from carrier config manager.
1188 *
1189 * @param context the context to get carrier service
1190 * @param key config key defined in CarrierConfigManager
1191 * @return integer value of corresponding key.
1192 */
1193 private static int getIntCarrierConfig(Context context, String key) {
1194 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
1195 Context.CARRIER_CONFIG_SERVICE);
1196 PersistableBundle b = null;
1197 if (configManager != null) {
1198 b = configManager.getConfig();
1199 }
1200 if (b != null) {
1201 return b.getInt(key);
1202 } else {
1203 // Return static default defined in CarrierConfigManager.
1204 return CarrierConfigManager.getDefaultConfig().getInt(key);
1205 }
1206 }
1207
1208 /**
Wink Savilleef36ef62014-06-11 08:39:38 -07001209 * Gets the call ID from the specified incoming call broadcast intent.
1210 *
1211 * @param incomingCallIntent the incoming call broadcast intent
1212 * @return the call ID or null if the intent does not contain it
1213 */
1214 private static String getCallId(Intent incomingCallIntent) {
1215 if (incomingCallIntent == null) {
1216 return null;
1217 }
1218
1219 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
1220 }
1221
1222 /**
1223 * Gets the service type from the specified incoming call broadcast intent.
1224 *
1225 * @param incomingCallIntent the incoming call broadcast intent
1226 * @return the service identifier or -1 if the intent does not contain it
1227 */
1228 private static int getServiceId(Intent incomingCallIntent) {
1229 if (incomingCallIntent == null) {
1230 return (-1);
1231 }
1232
1233 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1);
1234 }
1235
1236 /**
1237 * Binds the IMS service only if the service is not created.
1238 */
1239 private void checkAndThrowExceptionIfServiceUnavailable()
1240 throws ImsException {
1241 if (mImsService == null) {
1242 createImsService(true);
1243
1244 if (mImsService == null) {
1245 throw new ImsException("Service is unavailable",
1246 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1247 }
1248 }
1249 }
1250
Etan Cohenabbd7882014-09-26 22:35:35 -07001251 private static String getImsServiceName(int phoneId) {
1252 // TODO: MSIM implementation needs to decide on service name as a function of phoneId
Etan Cohend7727462014-07-12 14:54:10 -07001253 return IMS_SERVICE;
1254 }
1255
Wink Savilleef36ef62014-06-11 08:39:38 -07001256 /**
1257 * Binds the IMS service to make/receive the call.
1258 */
1259 private void createImsService(boolean checkService) {
1260 if (checkService) {
Etan Cohenabbd7882014-09-26 22:35:35 -07001261 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -07001262
1263 if (binder == null) {
1264 return;
1265 }
1266 }
1267
Etan Cohenabbd7882014-09-26 22:35:35 -07001268 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -07001269
1270 if (b != null) {
1271 try {
1272 b.linkToDeath(mDeathRecipient, 0);
1273 } catch (RemoteException e) {
1274 }
1275 }
1276
1277 mImsService = IImsService.Stub.asInterface(b);
1278 }
1279
1280 /**
1281 * Creates a {@link ImsCallSession} with the specified call profile.
1282 * Use other methods, if applicable, instead of interacting with
1283 * {@link ImsCallSession} directly.
1284 *
1285 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1286 * @param profile a call profile to make the call
1287 */
1288 private ImsCallSession createCallSession(int serviceId,
1289 ImsCallProfile profile) throws ImsException {
1290 try {
1291 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null));
1292 } catch (RemoteException e) {
1293 return null;
1294 }
1295 }
1296
1297 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass,
1298 ImsConnectionStateListener listener) {
1299 ImsRegistrationListenerProxy proxy =
1300 new ImsRegistrationListenerProxy(serviceClass, listener);
1301 return proxy;
1302 }
1303
Etan Cohena00c9192014-12-23 15:02:29 -08001304 private static void log(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001305 Rlog.d(TAG, s);
1306 }
1307
Etan Cohena00c9192014-12-23 15:02:29 -08001308 private static void loge(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001309 Rlog.e(TAG, s);
1310 }
1311
Etan Cohena00c9192014-12-23 15:02:29 -08001312 private static void loge(String s, Throwable t) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001313 Rlog.e(TAG, s, t);
1314 }
1315
1316 /**
ram7da5a112014-07-16 20:59:27 +05301317 * Used for turning on IMS.if its off already
1318 */
Etan Cohen82f78122014-12-15 10:10:14 -08001319 private void turnOnIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001320 checkAndThrowExceptionIfServiceUnavailable();
1321
ram7da5a112014-07-16 20:59:27 +05301322 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001323 mImsService.turnOnIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301324 } catch (RemoteException e) {
1325 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1326 }
1327 }
1328
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001329 private boolean isImsTurnOffAllowed() {
Meng Wang9352c432016-06-08 14:22:20 -07001330 return isTurnOffImsAllowedByPlatform(mContext)
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001331 && (!isWfcEnabledByPlatform(mContext)
1332 || !isWfcEnabledByUser(mContext));
1333 }
1334
Etan Cohen82f78122014-12-15 10:10:14 -08001335 private void setAdvanced4GMode(boolean turnOn) throws ImsException {
Etan Cohencfc784d2014-08-07 18:40:31 -07001336 checkAndThrowExceptionIfServiceUnavailable();
1337
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001338 try {
1339 ImsConfig config = getConfigInterface();
1340 if (config != null && (turnOn || !isImsTurnOffAllowed())) {
1341 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -08001342 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, mImsConfigListener);
Pavel Zhamaitsiakff29b9d2016-04-15 12:16:57 -07001343
1344 if (isVtEnabledByPlatform(mContext)) {
1345 boolean enableViLte = turnOn && isVtEnabledByUser(mContext);
1346 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
1347 TelephonyManager.NETWORK_TYPE_LTE,
1348 enableViLte ? 1 : 0,
1349 mImsConfigListener);
1350 }
Etan Cohenb651fa52014-10-22 10:51:29 -07001351 }
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001352 } catch (ImsException e) {
1353 log("setAdvanced4GMode() : " + e);
Etan Cohencfc784d2014-08-07 18:40:31 -07001354 }
Etan Cohencfc784d2014-08-07 18:40:31 -07001355 if (turnOn) {
1356 turnOnIms();
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001357 } else if (isImsTurnOffAllowed()) {
Etan Cohencfc784d2014-08-07 18:40:31 -07001358 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms");
1359 turnOffIms();
1360 }
1361 }
1362
ram7da5a112014-07-16 20:59:27 +05301363 /**
1364 * Used for turning off IMS completely in order to make the device CSFB'ed.
1365 * Once turned off, all calls will be over CS.
1366 */
Etan Cohen82f78122014-12-15 10:10:14 -08001367 private void turnOffIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001368 checkAndThrowExceptionIfServiceUnavailable();
1369
ram7da5a112014-07-16 20:59:27 +05301370 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001371 mImsService.turnOffIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301372 } catch (RemoteException e) {
1373 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1374 }
1375 }
1376
1377 /**
Wink Savilleef36ef62014-06-11 08:39:38 -07001378 * Death recipient class for monitoring IMS service.
1379 */
1380 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient {
1381 @Override
1382 public void binderDied() {
1383 mImsService = null;
1384 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001385 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001386 mEcbm = null;
Tyler Gunn4d128b62016-04-13 15:44:38 -07001387 mMultiEndpoint = null;
Wink Savilleef36ef62014-06-11 08:39:38 -07001388
1389 if (mContext != null) {
Etan Cohend7727462014-07-12 14:54:10 -07001390 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN);
Etan Cohenabbd7882014-09-26 22:35:35 -07001391 intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
Etan Cohend7727462014-07-12 14:54:10 -07001392 mContext.sendBroadcast(new Intent(intent));
Wink Savilleef36ef62014-06-11 08:39:38 -07001393 }
1394 }
1395 }
1396
1397 /**
1398 * Adapter class for {@link IImsRegistrationListener}.
1399 */
1400 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub {
1401 private int mServiceClass;
1402 private ImsConnectionStateListener mListener;
1403
1404 public ImsRegistrationListenerProxy(int serviceClass,
1405 ImsConnectionStateListener listener) {
1406 mServiceClass = serviceClass;
1407 mListener = listener;
1408 }
1409
1410 public boolean isSameProxy(int serviceClass) {
1411 return (mServiceClass == serviceClass);
1412 }
1413
Omkar Kolangadea7ced642015-05-04 17:55:13 -07001414 @Deprecated
Wink Savilleef36ef62014-06-11 08:39:38 -07001415 public void registrationConnected() {
1416 if (DBG) {
1417 log("registrationConnected ::");
1418 }
1419
1420 if (mListener != null) {
1421 mListener.onImsConnected();
1422 }
1423 }
1424
Omkar Kolangadea7ced642015-05-04 17:55:13 -07001425 @Deprecated
Rekha Kumar14631742015-02-04 10:47:00 -08001426 public void registrationProgressing() {
Wink Savilleef36ef62014-06-11 08:39:38 -07001427 if (DBG) {
Rekha Kumar14631742015-02-04 10:47:00 -08001428 log("registrationProgressing ::");
Wink Savilleef36ef62014-06-11 08:39:38 -07001429 }
1430
1431 if (mListener != null) {
Rekha Kumar14631742015-02-04 10:47:00 -08001432 mListener.onImsProgressing();
1433 }
1434 }
1435
1436 @Override
Omkar Kolangadea7ced642015-05-04 17:55:13 -07001437 public void registrationConnectedWithRadioTech(int imsRadioTech) {
1438 // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY
1439 // values in ServiceState.java.
1440 if (DBG) {
1441 log("registrationConnectedWithRadioTech :: imsRadioTech=" + imsRadioTech);
1442 }
1443
1444 if (mListener != null) {
1445 mListener.onImsConnected();
1446 }
1447 }
1448
1449 @Override
1450 public void registrationProgressingWithRadioTech(int imsRadioTech) {
1451 // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY
1452 // values in ServiceState.java.
1453 if (DBG) {
1454 log("registrationProgressingWithRadioTech :: imsRadioTech=" + imsRadioTech);
1455 }
1456
1457 if (mListener != null) {
1458 mListener.onImsProgressing();
1459 }
1460 }
1461
1462 @Override
Rekha Kumar14631742015-02-04 10:47:00 -08001463 public void registrationDisconnected(ImsReasonInfo imsReasonInfo) {
1464 if (DBG) {
1465 log("registrationDisconnected :: imsReasonInfo" + imsReasonInfo);
1466 }
1467
1468 if (mListener != null) {
1469 mListener.onImsDisconnected(imsReasonInfo);
Wink Savilleef36ef62014-06-11 08:39:38 -07001470 }
1471 }
1472
1473 @Override
1474 public void registrationResumed() {
1475 if (DBG) {
1476 log("registrationResumed ::");
1477 }
1478
1479 if (mListener != null) {
1480 mListener.onImsResumed();
1481 }
1482 }
1483
1484 @Override
1485 public void registrationSuspended() {
1486 if (DBG) {
1487 log("registrationSuspended ::");
1488 }
1489
1490 if (mListener != null) {
1491 mListener.onImsSuspended();
1492 }
1493 }
1494
1495 @Override
1496 public void registrationServiceCapabilityChanged(int serviceClass, int event) {
1497 log("registrationServiceCapabilityChanged :: serviceClass=" +
1498 serviceClass + ", event=" + event);
1499
1500 if (mListener != null) {
1501 mListener.onImsConnected();
1502 }
1503 }
ram7da5a112014-07-16 20:59:27 +05301504
1505 @Override
1506 public void registrationFeatureCapabilityChanged(int serviceClass,
1507 int[] enabledFeatures, int[] disabledFeatures) {
1508 log("registrationFeatureCapabilityChanged :: serviceClass=" +
1509 serviceClass);
Libin.Tang@motorola.come2296782014-08-19 14:20:01 -05001510 if (mListener != null) {
1511 mListener.onFeatureCapabilityChanged(serviceClass,
1512 enabledFeatures, disabledFeatures);
1513 }
ram7da5a112014-07-16 20:59:27 +05301514 }
1515
Shriram Ganeshd3adfad2015-05-31 10:06:15 -07001516 @Override
1517 public void voiceMessageCountUpdate(int count) {
1518 log("voiceMessageCountUpdate :: count=" + count);
1519
1520 if (mListener != null) {
1521 mListener.onVoiceMessageCountChanged(count);
1522 }
1523 }
1524
Pavel Zhamaitsiak4de9cbb2016-02-11 17:21:05 -08001525 @Override
1526 public void registrationAssociatedUriChanged(Uri[] uris) {
1527 if (DBG) log("registrationAssociatedUriChanged ::");
1528
1529 if (mListener != null) {
1530 mListener.registrationAssociatedUriChanged(uris);
1531 }
1532 }
Wink Savilleef36ef62014-06-11 08:39:38 -07001533 }
Tyler Gunn4d128b62016-04-13 15:44:38 -07001534
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001535 /**
1536 * Gets the ECBM interface to request ECBM exit.
1537 *
1538 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1539 * @return the ECBM interface instance
1540 * @throws ImsException if getting the ECBM interface results in an error
1541 */
1542 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException {
1543 if (mEcbm == null) {
1544 checkAndThrowExceptionIfServiceUnavailable();
1545
1546 try {
1547 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId);
1548
1549 if (iEcbm == null) {
1550 throw new ImsException("getEcbmInterface()",
1551 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED);
1552 }
1553 mEcbm = new ImsEcbm(iEcbm);
1554 } catch (RemoteException e) {
1555 throw new ImsException("getEcbmInterface()", e,
1556 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1557 }
1558 }
1559 return mEcbm;
1560 }
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001561
1562 /**
Tyler Gunn4d128b62016-04-13 15:44:38 -07001563 * Gets the Multi-Endpoint interface to subscribe to multi-enpoint notifications..
1564 *
1565 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1566 * @return the multi-endpoint interface instance
1567 * @throws ImsException if getting the multi-endpoint interface results in an error
1568 */
1569 public ImsMultiEndpoint getMultiEndpointInterface(int serviceId) throws ImsException {
1570 if (mMultiEndpoint == null) {
1571 checkAndThrowExceptionIfServiceUnavailable();
1572
1573 try {
1574 IImsMultiEndpoint iImsMultiEndpoint = mImsService.getMultiEndpointInterface(
1575 serviceId);
1576
1577 if (iImsMultiEndpoint == null) {
1578 throw new ImsException("getMultiEndpointInterface()",
1579 ImsReasonInfo.CODE_MULTIENDPOINT_NOT_SUPPORTED);
1580 }
1581 mMultiEndpoint = new ImsMultiEndpoint(iImsMultiEndpoint);
1582 } catch (RemoteException e) {
1583 throw new ImsException("getMultiEndpointInterface()", e,
1584 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1585 }
1586 }
1587 return mMultiEndpoint;
1588 }
1589
1590 /**
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001591 * Resets ImsManager settings back to factory defaults.
1592 *
1593 * @hide
1594 */
1595 public static void factoryReset(Context context) {
1596 // Set VoLTE to default
1597 android.provider.Settings.Global.putInt(context.getContentResolver(),
1598 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED,
1599 ImsConfig.FeatureValueConstants.ON);
1600
1601 // Set VoWiFi to default
1602 android.provider.Settings.Global.putInt(context.getContentResolver(),
1603 android.provider.Settings.Global.WFC_IMS_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -08001604 getBooleanCarrierConfig(context,
1605 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL) ?
1606 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001607
1608 // Set VoWiFi mode to default
1609 android.provider.Settings.Global.putInt(context.getContentResolver(),
1610 android.provider.Settings.Global.WFC_IMS_MODE,
fionaxu5803ef02016-03-08 11:48:48 -08001611 getIntCarrierConfig(context,
1612 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001613
1614 // Set VoWiFi roaming to default
1615 android.provider.Settings.Global.putInt(context.getContentResolver(),
1616 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -08001617 getBooleanCarrierConfig(context,
1618 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ?
1619 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001620
1621 // Set VT to default
Pavel Zhamaitsiak92b54b22016-04-01 15:55:47 -07001622 android.provider.Settings.Global.putInt(context.getContentResolver(),
1623 android.provider.Settings.Global.VT_IMS_ENABLED,
1624 ImsConfig.FeatureValueConstants.ON);
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001625
1626 // Push settings to ImsConfig
1627 ImsManager.updateImsServiceConfig(context,
1628 SubscriptionManager.getDefaultVoicePhoneId(), true);
1629 }
Jack Yu2f102bd2015-12-28 15:31:48 -08001630
1631 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1632 pw.println("ImsManager:");
1633 pw.println(" mPhoneId = " + mPhoneId);
1634 pw.println(" mConfigUpdated = " + mConfigUpdated);
1635 pw.println(" mImsService = " + mImsService);
1636
1637 pw.println(" isGbaValid = " + isGbaValid(mContext));
1638 pw.println(" isImsTurnOffAllowed = " + isImsTurnOffAllowed());
1639 pw.println(" isNonTtyOrTtyOnVolteEnabled = " + isNonTtyOrTtyOnVolteEnabled(mContext));
1640
1641 pw.println(" isVolteEnabledByPlatform = " + isVolteEnabledByPlatform(mContext));
1642 pw.println(" isVolteProvisionedOnDevice = " + isVolteProvisionedOnDevice(mContext));
1643 pw.println(" isEnhanced4gLteModeSettingEnabledByUser = " +
1644 isEnhanced4gLteModeSettingEnabledByUser(mContext));
1645 pw.println(" isVtEnabledByPlatform = " + isVtEnabledByPlatform(mContext));
1646 pw.println(" isVtEnabledByUser = " + isVtEnabledByUser(mContext));
1647
1648 pw.println(" isWfcEnabledByPlatform = " + isWfcEnabledByPlatform(mContext));
1649 pw.println(" isWfcEnabledByUser = " + isWfcEnabledByUser(mContext));
1650 pw.println(" getWfcMode = " + getWfcMode(mContext));
1651 pw.println(" isWfcRoamingEnabledByUser = " + isWfcRoamingEnabledByUser(mContext));
1652
1653 pw.flush();
1654 }
Wink Savilleef36ef62014-06-11 08:39:38 -07001655}