blob: c7c2db2f59fc89dde5b1df1dbd6f103aaf341439 [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;
Tyler Gunn4d128b62016-04-13 15:44:38 -070039import com.android.ims.internal.IImsMultiEndpoint;
Wink Savilleef36ef62014-06-11 08:39:38 -070040import com.android.ims.internal.IImsRegistrationListener;
41import com.android.ims.internal.IImsService;
42import com.android.ims.internal.IImsUt;
43import com.android.ims.internal.ImsCallSession;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -050044import com.android.ims.internal.IImsConfig;
45
Jack Yu2f102bd2015-12-28 15:31:48 -080046import java.io.FileDescriptor;
47import java.io.PrintWriter;
Etan Cohend7727462014-07-12 14:54:10 -070048import java.util.HashMap;
Jack Yu643ffe42016-07-08 14:25:46 -070049import java.util.concurrent.atomic.AtomicBoolean;
Etan Cohend7727462014-07-12 14:54:10 -070050
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
Jack Yu643ffe42016-07-08 14:25:46 -0700188 // Flag indicating data enabled or not. This flag should be in sync with
189 // DcTracker.isDataEnabled(). The flag will be set later during boot up.
190 private AtomicBoolean mDataEnabled = new AtomicBoolean(true);
191
Wink Savilleef36ef62014-06-11 08:39:38 -0700192 /**
193 * Gets a manager instance.
194 *
195 * @param context application context for creating the manager object
Etan Cohenabbd7882014-09-26 22:35:35 -0700196 * @param phoneId the phone ID for the IMS Service
197 * @return the manager instance corresponding to the phoneId
Wink Savilleef36ef62014-06-11 08:39:38 -0700198 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700199 public static ImsManager getInstance(Context context, int phoneId) {
Etan Cohend7727462014-07-12 14:54:10 -0700200 synchronized (sImsManagerInstances) {
Etan Cohenabbd7882014-09-26 22:35:35 -0700201 if (sImsManagerInstances.containsKey(phoneId))
202 return sImsManagerInstances.get(phoneId);
Wink Savilleef36ef62014-06-11 08:39:38 -0700203
Etan Cohenabbd7882014-09-26 22:35:35 -0700204 ImsManager mgr = new ImsManager(context, phoneId);
205 sImsManagerInstances.put(phoneId, mgr);
Etan Cohend7727462014-07-12 14:54:10 -0700206
207 return mgr;
208 }
Wink Savilleef36ef62014-06-11 08:39:38 -0700209 }
210
Etan Cohen45b5f312014-08-19 15:55:08 -0700211 /**
212 * Returns the user configuration of Enhanced 4G LTE Mode setting
213 */
214 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) {
Sungmin Choi2f1af952016-02-01 17:15:35 +0900215 // If user can't edit Enhanced 4G LTE Mode, it assumes Enhanced 4G LTE Mode is always true.
216 // If user changes SIM from editable mode to uneditable mode, need to return true.
217 if (!getBooleanCarrierConfig(context,
218 CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL)) {
219 return true;
220 }
Libin.Tang@motorola.com8a6bf4b2014-10-10 15:02:41 -0500221 int enabled = android.provider.Settings.Global.getInt(
222 context.getContentResolver(),
Etan Cohenb651fa52014-10-22 10:51:29 -0700223 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
Etan Cohena00c9192014-12-23 15:02:29 -0800224 return (enabled == 1) ? true : false;
Etan Cohen45b5f312014-08-19 15:55:08 -0700225 }
226
227 /**
Etan Cohen82f78122014-12-15 10:10:14 -0800228 * Change persistent Enhanced 4G LTE Mode setting
229 */
230 public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {
231 int value = enabled ? 1 : 0;
232 android.provider.Settings.Global.putInt(
233 context.getContentResolver(),
234 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, value);
235
236 if (isNonTtyOrTtyOnVolteEnabled(context)) {
237 ImsManager imsManager = ImsManager.getInstance(context,
238 SubscriptionManager.getDefaultVoicePhoneId());
239 if (imsManager != null) {
240 try {
241 imsManager.setAdvanced4GMode(enabled);
242 } catch (ImsException ie) {
243 // do nothing
244 }
245 }
246 }
247 }
248
249 /**
250 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is
251 * supported.
252 */
253 public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) {
Junda Liue7663c02015-06-23 11:16:26 -0700254 if (getBooleanCarrierConfig(context,
fionaxu5803ef02016-03-08 11:48:48 -0800255 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -0800256 return true;
257 }
258
259 return Settings.Secure.getInt(context.getContentResolver(),
260 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF)
261 == TelecomManager.TTY_MODE_OFF;
262 }
263
264 /**
Etan Cohenea2b5832014-10-23 18:50:35 -0700265 * Returns a platform configuration for VoLTE which may override the user setting.
Etan Cohen45b5f312014-08-19 15:55:08 -0700266 */
Etan Cohenea2b5832014-10-23 18:50:35 -0700267 public static boolean isVolteEnabledByPlatform(Context context) {
Etan Cohenb651fa52014-10-22 10:51:29 -0700268 if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE,
269 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) {
Etan Cohenaf55a402014-09-04 22:34:41 -0700270 return true;
271 }
272
Etan Cohenb5388a32014-11-26 11:57:47 -0800273 return context.getResources().getBoolean(
Junda Liue7663c02015-06-23 11:16:26 -0700274 com.android.internal.R.bool.config_device_volte_available)
275 && getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700276 CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL)
277 && isGbaValid(context);
Etan Cohenb5388a32014-11-26 11:57:47 -0800278 }
279
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700280 /**
Etan Cohenb5388a32014-11-26 11:57:47 -0800281 * Indicates whether VoLTE is provisioned on device
282 */
283 public static boolean isVolteProvisionedOnDevice(Context context) {
Junda Liue7663c02015-06-23 11:16:26 -0700284 if (getBooleanCarrierConfig(context,
285 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
Etan Cohenb5388a32014-11-26 11:57:47 -0800286 ImsManager mgr = ImsManager.getInstance(context,
Jonathan Basserid7133652015-04-07 19:54:24 -0700287 SubscriptionManager.getDefaultVoicePhoneId());
Etan Cohenb5388a32014-11-26 11:57:47 -0800288 if (mgr != null) {
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700289 return mgr.mIsVoLteProvisioned;
Etan Cohenb5388a32014-11-26 11:57:47 -0800290 }
291 }
292
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700293 return true;
294 }
295
296 /**
297 * Indicates whether VoWifi is provisioned on device
298 */
299 public static boolean isWfcProvisionedOnDevice(Context context) {
300 if (getBooleanCarrierConfig(context,
301 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
302 ImsManager mgr = ImsManager.getInstance(context,
303 SubscriptionManager.getDefaultVoicePhoneId());
304 if (mgr != null) {
305 return mgr.mIsWfcProvisioned;
306 }
307 }
308
309 return true;
310 }
311
312 /**
313 * Indicates whether VT is provisioned on device
314 */
315 public static boolean isVtProvisionedOnDevice(Context context) {
316 if (getBooleanCarrierConfig(context,
317 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
318 ImsManager mgr = ImsManager.getInstance(context,
319 SubscriptionManager.getDefaultVoicePhoneId());
320 if (mgr != null) {
321 return mgr.mIsVtProvisioned;
322 }
323 }
324
325 return true;
Etan Cohenb651fa52014-10-22 10:51:29 -0700326 }
327
Etan Cohenea2b5832014-10-23 18:50:35 -0700328 /**
329 * Returns a platform configuration for VT which may override the user setting.
330 *
331 * Note: VT presumes that VoLTE is enabled (these are configuration settings
332 * which must be done correctly).
333 */
Etan Cohenb651fa52014-10-22 10:51:29 -0700334 public static boolean isVtEnabledByPlatform(Context context) {
Etan Cohenea2b5832014-10-23 18:50:35 -0700335 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE,
336 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) {
337 return true;
338 }
339
Etan Cohenb651fa52014-10-22 10:51:29 -0700340 return
341 context.getResources().getBoolean(
342 com.android.internal.R.bool.config_device_vt_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700343 getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700344 CarrierConfigManager.KEY_CARRIER_VT_AVAILABLE_BOOL) &&
345 isGbaValid(context);
Etan Cohen45b5f312014-08-19 15:55:08 -0700346 }
347
Etan Cohena00c9192014-12-23 15:02:29 -0800348 /**
Etan Cohena7d32e82015-05-04 18:02:09 -0700349 * Returns the user configuration of VT setting
350 */
351 public static boolean isVtEnabledByUser(Context context) {
352 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
353 android.provider.Settings.Global.VT_IMS_ENABLED,
354 ImsConfig.FeatureValueConstants.ON);
355 return (enabled == 1) ? true : false;
356 }
357
358 /**
359 * Change persistent VT enabled setting
360 */
361 public static void setVtSetting(Context context, boolean enabled) {
362 int value = enabled ? 1 : 0;
363 android.provider.Settings.Global.putInt(context.getContentResolver(),
364 android.provider.Settings.Global.VT_IMS_ENABLED, value);
365
366 ImsManager imsManager = ImsManager.getInstance(context,
367 SubscriptionManager.getDefaultVoicePhoneId());
368 if (imsManager != null) {
369 try {
370 ImsConfig config = imsManager.getConfigInterface();
371 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
372 TelephonyManager.NETWORK_TYPE_LTE,
373 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800374 : ImsConfig.FeatureValueConstants.OFF,
375 imsManager.mImsConfigListener);
Etan Cohena7d32e82015-05-04 18:02:09 -0700376
377 if (enabled) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700378 log("setVtSetting() : turnOnIms");
Etan Cohena7d32e82015-05-04 18:02:09 -0700379 imsManager.turnOnIms();
Meng Wang9352c432016-06-08 14:22:20 -0700380 } else if (isTurnOffImsAllowedByPlatform(context)
Pavel Zhamaitsiak4ca0cde2015-12-22 16:51:57 -0800381 && (!isVolteEnabledByPlatform(context)
Etan Cohena7d32e82015-05-04 18:02:09 -0700382 || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
383 log("setVtSetting() : imsServiceAllowTurnOff -> turnOffIms");
384 imsManager.turnOffIms();
385 }
386 } catch (ImsException e) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700387 loge("setVtSetting(): ", e);
Etan Cohena7d32e82015-05-04 18:02:09 -0700388 }
389 }
390 }
391
Meng Wang9352c432016-06-08 14:22:20 -0700392 /*
393 * Returns whether turning off ims is allowed by platform.
394 * The platform property may override the carrier config.
395 */
396 private static boolean isTurnOffImsAllowedByPlatform(Context context) {
397 if (SystemProperties.getInt(PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE,
398 PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT) == 1) {
399 return true;
400 }
401 return getBooleanCarrierConfig(context,
402 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL);
403 }
404
Etan Cohena7d32e82015-05-04 18:02:09 -0700405 /**
Etan Cohena00c9192014-12-23 15:02:29 -0800406 * Returns the user configuration of WFC setting
407 */
408 public static boolean isWfcEnabledByUser(Context context) {
409 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
410 android.provider.Settings.Global.WFC_IMS_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -0800411 getBooleanCarrierConfig(context,
412 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL) ?
413 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800414 return (enabled == 1) ? true : false;
415 }
416
417 /**
418 * Change persistent WFC enabled setting
419 */
420 public static void setWfcSetting(Context context, boolean enabled) {
421 int value = enabled ? 1 : 0;
422 android.provider.Settings.Global.putInt(context.getContentResolver(),
423 android.provider.Settings.Global.WFC_IMS_ENABLED, value);
424
425 ImsManager imsManager = ImsManager.getInstance(context,
426 SubscriptionManager.getDefaultVoicePhoneId());
427 if (imsManager != null) {
428 try {
429 ImsConfig config = imsManager.getConfigInterface();
Etan Cohena00c9192014-12-23 15:02:29 -0800430 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
Nathan Harold3a99f782015-07-24 15:02:34 -0700431 TelephonyManager.NETWORK_TYPE_IWLAN,
Etan Cohena00c9192014-12-23 15:02:29 -0800432 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800433 : ImsConfig.FeatureValueConstants.OFF,
434 imsManager.mImsConfigListener);
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800435
436 if (enabled) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700437 log("setWfcSetting() : turnOnIms");
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800438 imsManager.turnOnIms();
Meng Wang9352c432016-06-08 14:22:20 -0700439 } else if (isTurnOffImsAllowedByPlatform(context)
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800440 && (!isVolteEnabledByPlatform(context)
441 || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
442 log("setWfcSetting() : imsServiceAllowTurnOff -> turnOffIms");
443 imsManager.turnOffIms();
444 }
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700445
446 // Force IMS to register over LTE when turning off WFC
447 setWfcModeInternal(context, enabled
448 ? getWfcMode(context)
449 : ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED);
Etan Cohena00c9192014-12-23 15:02:29 -0800450 } catch (ImsException e) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700451 loge("setWfcSetting(): ", e);
Etan Cohena00c9192014-12-23 15:02:29 -0800452 }
453 }
454 }
455
456 /**
457 * Returns the user configuration of WFC modem setting
458 */
459 public static int getWfcMode(Context context) {
460 int setting = android.provider.Settings.Global.getInt(context.getContentResolver(),
fionaxu5803ef02016-03-08 11:48:48 -0800461 android.provider.Settings.Global.WFC_IMS_MODE, getIntCarrierConfig(context,
462 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
Etan Cohena00c9192014-12-23 15:02:29 -0800463 if (DBG) log("getWfcMode - setting=" + setting);
464 return setting;
465 }
466
467 /**
468 * Returns the user configuration of WFC modem setting
469 */
470 public static void setWfcMode(Context context, int wfcMode) {
471 if (DBG) log("setWfcMode - setting=" + wfcMode);
472 android.provider.Settings.Global.putInt(context.getContentResolver(),
473 android.provider.Settings.Global.WFC_IMS_MODE, wfcMode);
474
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700475 setWfcModeInternal(context, wfcMode);
476 }
477
478 private static void setWfcModeInternal(Context context, int wfcMode) {
Etan Cohena00c9192014-12-23 15:02:29 -0800479 final ImsManager imsManager = ImsManager.getInstance(context,
480 SubscriptionManager.getDefaultVoicePhoneId());
481 if (imsManager != null) {
482 final int value = wfcMode;
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700483 Thread thread = new Thread(new Runnable() {
Etan Cohena00c9192014-12-23 15:02:29 -0800484 public void run() {
485 try {
486 imsManager.getConfigInterface().setProvisionedValue(
487 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE,
488 value);
489 } catch (ImsException e) {
490 // do nothing
491 }
492 }
493 });
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700494 thread.start();
Etan Cohena00c9192014-12-23 15:02:29 -0800495 }
496 }
497
498 /**
499 * Returns the user configuration of WFC roaming setting
500 */
501 public static boolean isWfcRoamingEnabledByUser(Context context) {
502 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
503 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -0800504 getBooleanCarrierConfig(context,
505 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ?
506 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800507 return (enabled == 1) ? true : false;
508 }
509
510 /**
511 * Change persistent WFC roaming enabled setting
512 */
513 public static void setWfcRoamingSetting(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800514 android.provider.Settings.Global.putInt(context.getContentResolver(),
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700515 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -0800516 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700517 : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800518
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700519 setWfcRoamingSettingInternal(context, enabled);
520 }
521
522 private static void setWfcRoamingSettingInternal(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800523 final ImsManager imsManager = ImsManager.getInstance(context,
524 SubscriptionManager.getDefaultVoicePhoneId());
525 if (imsManager != null) {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700526 final int value = enabled
527 ? ImsConfig.FeatureValueConstants.ON
528 : ImsConfig.FeatureValueConstants.OFF;
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700529 Thread thread = new Thread(new Runnable() {
Etan Cohena00c9192014-12-23 15:02:29 -0800530 public void run() {
531 try {
532 imsManager.getConfigInterface().setProvisionedValue(
533 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_ROAMING,
534 value);
535 } catch (ImsException e) {
536 // do nothing
537 }
538 }
539 });
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700540 thread.start();
Etan Cohena00c9192014-12-23 15:02:29 -0800541 }
542 }
543
544 /**
545 * Returns a platform configuration for WFC which may override the user
546 * setting. Note: WFC presumes that VoLTE is enabled (these are
547 * configuration settings which must be done correctly).
548 */
549 public static boolean isWfcEnabledByPlatform(Context context) {
550 if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE,
551 PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT) == 1) {
552 return true;
553 }
554
555 return
556 context.getResources().getBoolean(
557 com.android.internal.R.bool.config_device_wfc_ims_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700558 getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700559 CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) &&
560 isGbaValid(context);
561 }
562
563 /**
564 * If carrier requires that IMS is only available if GBA capable SIM is used,
565 * then this function checks GBA bit in EF IST.
566 *
567 * Format of EF IST is defined in 3GPP TS 31.103 (Section 4.2.7).
568 */
569 private static boolean isGbaValid(Context context) {
570 if (getBooleanCarrierConfig(context,
571 CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) {
572 final TelephonyManager telephonyManager = TelephonyManager.getDefault();
573 String efIst = telephonyManager.getIsimIst();
574 if (efIst == null) {
575 loge("ISF is NULL");
576 return true;
577 }
578 boolean result = efIst != null && efIst.length() > 1 &&
579 (0x02 & (byte)efIst.charAt(1)) != 0;
580 if (DBG) log("GBA capable=" + result + ", ISF=" + efIst);
581 return result;
582 }
583 return true;
Etan Cohena00c9192014-12-23 15:02:29 -0800584 }
585
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700586 /**
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700587 * This function should be called when ImsConfig.ACTION_IMS_CONFIG_CHANGED is received.
588 *
589 * We cannot register receiver in ImsManager because this would lead to resource leak.
590 * ImsManager can be created in different processes and it is not notified when that process
591 * is about to be terminated.
592 *
593 * @hide
594 * */
595 public static void onProvisionedValueChanged(Context context, int item, String value) {
596 if (DBG) Rlog.d(TAG, "onProvisionecValueChanged: item=" + item + " val=" + value);
597 ImsManager mgr = ImsManager.getInstance(context,
598 SubscriptionManager.getDefaultVoicePhoneId());
599
600 switch (item) {
601 case ImsConfig.ConfigConstants.VLT_SETTING_ENABLED:
602 mgr.mIsVoLteProvisioned = value.equals("1");
603 if (DBG) Rlog.d(TAG,"mIsVoLteProvisioned = " + mgr.mIsVoLteProvisioned);
604 break;
605
606 case ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED:
607 mgr.mIsWfcProvisioned = value.equals("1");
608 if (DBG) Rlog.d(TAG,"mIsWfcProvisioned = " + mgr.mIsWfcProvisioned);
609 break;
610
Nathan Harolda9fc7f12016-06-30 16:12:14 -0700611 case ImsConfig.ConfigConstants.LVC_SETTING_ENABLED:
612 mgr.mIsVtProvisioned = value.equals("1");
613 if (DBG) Rlog.d(TAG,"mIsVtProvisioned = " + mgr.mIsVtProvisioned);
614 break;
615
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700616 }
617 }
618
619 private class AsyncUpdateProvisionedValues extends AsyncTask<Void, Void, Void> {
620 @Override
621 protected Void doInBackground(Void... params) {
622 // disable on any error
623 mIsVoLteProvisioned = false;
624 mIsWfcProvisioned = false;
625 mIsVtProvisioned = false;
626
627 try {
628 ImsConfig config = getConfigInterface();
629 if (config != null) {
630 mIsVoLteProvisioned = getProvisionedBool(config,
631 ImsConfig.ConfigConstants.VLT_SETTING_ENABLED);
632 if (DBG) Rlog.d(TAG, "mIsVoLteProvisioned = " + mIsVoLteProvisioned);
633
634 mIsWfcProvisioned = getProvisionedBool(config,
635 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED);
636 if (DBG) Rlog.d(TAG, "mIsWfcProvisioned = " + mIsWfcProvisioned);
637
Nathan Harolda9fc7f12016-06-30 16:12:14 -0700638 mIsVtProvisioned = getProvisionedBool(config,
639 ImsConfig.ConfigConstants.LVC_SETTING_ENABLED);
640 if (DBG) Rlog.d(TAG, "mIsVtProvisioned = " + mIsVtProvisioned);
641
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700642 }
643 } catch (ImsException ie) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700644 Rlog.e(TAG, "AsyncUpdateProvisionedValues error: ", ie);
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700645 }
646
647 return null;
648 }
649
650 private boolean getProvisionedBool(ImsConfig config, int item) throws ImsException {
651 return config.getProvisionedValue(item) == ImsConfig.FeatureValueConstants.ON;
652 }
653 }
654
655 /** Asynchronously get VoLTE, WFC, VT provisioning statuses */
656 private void updateProvisionedValues() {
657 if (getBooleanCarrierConfig(mContext,
658 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
659
660 new AsyncUpdateProvisionedValues().execute();
661 }
662 }
663
664 /**
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700665 * Sync carrier config and user settings with ImsConfig.
666 *
667 * @param context for the manager object
668 * @param phoneId phone id
669 * @param force update
670 */
671 public static void updateImsServiceConfig(Context context, int phoneId, boolean force) {
Pavel Zhamaitsiakfc202992016-03-29 18:07:38 -0700672 if (!force) {
673 if (TelephonyManager.getDefault().getSimState() != TelephonyManager.SIM_STATE_READY) {
674 log("updateImsServiceConfig: SIM not ready");
675 // Don't disable IMS if SIM is not ready
676 return;
677 }
678 }
679
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700680 final ImsManager imsManager = ImsManager.getInstance(context, phoneId);
681 if (imsManager != null && (!imsManager.mConfigUpdated || force)) {
682 try {
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700683 imsManager.updateProvisionedValues();
684
Pavel Zhamaitsiakd46779c2016-06-03 10:39:51 -0700685 // TODO: Extend ImsConfig API and set all feature values in single function call.
686
687 // Note: currently the order of updates is set to produce different order of
688 // setFeatureValue() function calls from setAdvanced4GMode(). This is done to
689 // differentiate this code path from vendor code perspective.
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800690 boolean isImsUsed = imsManager.updateVolteFeatureValue();
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800691 isImsUsed |= imsManager.updateWfcFeatureAndProvisionedValues();
Pavel Zhamaitsiakd46779c2016-06-03 10:39:51 -0700692 isImsUsed |= imsManager.updateVideoCallFeatureValue();
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700693
Meng Wang9352c432016-06-08 14:22:20 -0700694 if (isImsUsed || !isTurnOffImsAllowedByPlatform(context)) {
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800695 // Turn on IMS if it is used.
696 // Also, if turning off is not allowed for current carrier,
697 // we need to turn IMS on because it might be turned off before
698 // phone switched to current carrier.
Meng Wangca7d4c42016-06-30 22:05:24 -0700699 log("updateImsServiceConfig: turnOnIms");
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700700 imsManager.turnOnIms();
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800701 } else {
702 // Turn off IMS if it is not used AND turning off is allowed for carrier.
Meng Wangca7d4c42016-06-30 22:05:24 -0700703 log("updateImsServiceConfig: turnOffIms");
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700704 imsManager.turnOffIms();
705 }
706
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700707 imsManager.mConfigUpdated = true;
708 } catch (ImsException e) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700709 loge("updateImsServiceConfig: ", e);
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700710 imsManager.mConfigUpdated = false;
711 }
712 }
713 }
714
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700715 /**
716 * Update VoLTE config
717 * @return whether feature is On
718 * @throws ImsException
719 */
720 private boolean updateVolteFeatureValue() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700721 boolean available = isVolteEnabledByPlatform(mContext);
722 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext);
723 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800724 boolean isFeatureOn = available && enabled && isNonTty;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700725
726 log("updateVolteFeatureValue: available = " + available
727 + ", enabled = " + enabled
728 + ", nonTTY = " + isNonTty);
729
730 getConfigInterface().setFeatureValue(
731 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
732 TelephonyManager.NETWORK_TYPE_LTE,
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800733 isFeatureOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700734 ImsConfig.FeatureValueConstants.ON :
735 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800736 mImsConfigListener);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700737
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800738 return isFeatureOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700739 }
740
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700741 /**
Jack Yu643ffe42016-07-08 14:25:46 -0700742 * Update video call over LTE config
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700743 * @return whether feature is On
744 * @throws ImsException
745 */
746 private boolean updateVideoCallFeatureValue() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700747 boolean available = isVtEnabledByPlatform(mContext);
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700748 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext) &&
Pavel Zhamaitsiak92b54b22016-04-01 15:55:47 -0700749 isVtEnabledByUser(mContext);
Omkar Kolangadec0f450d2016-02-11 20:59:48 +0530750 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
Jack Yu643ffe42016-07-08 14:25:46 -0700751
752 boolean isFeatureOn = available && enabled && isNonTty && mDataEnabled.get();
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700753
754 log("updateVideoCallFeatureValue: available = " + available
755 + ", enabled = " + enabled
Jack Yu643ffe42016-07-08 14:25:46 -0700756 + ", nonTTY = " + isNonTty
757 + ", data enabled = " + mDataEnabled.get());
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700758
759 getConfigInterface().setFeatureValue(
760 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
761 TelephonyManager.NETWORK_TYPE_LTE,
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800762 isFeatureOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700763 ImsConfig.FeatureValueConstants.ON :
764 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800765 mImsConfigListener);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700766
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800767 return isFeatureOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700768 }
769
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700770 /**
771 * Update WFC config
772 * @return whether feature is On
773 * @throws ImsException
774 */
775 private boolean updateWfcFeatureAndProvisionedValues() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700776 boolean available = isWfcEnabledByPlatform(mContext);
777 boolean enabled = isWfcEnabledByUser(mContext);
778 int mode = getWfcMode(mContext);
779 boolean roaming = isWfcRoamingEnabledByUser(mContext);
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800780 boolean isFeatureOn = available && enabled;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700781
782 log("updateWfcFeatureAndProvisionedValues: available = " + available
783 + ", enabled = " + enabled
784 + ", mode = " + mode
785 + ", roaming = " + roaming);
786
787 getConfigInterface().setFeatureValue(
Pavel Zhamaitsiake6f99432015-09-11 10:29:30 -0700788 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
789 TelephonyManager.NETWORK_TYPE_IWLAN,
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800790 isFeatureOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700791 ImsConfig.FeatureValueConstants.ON :
792 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800793 mImsConfigListener);
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700794
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800795 if (!isFeatureOn) {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700796 mode = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED;
797 roaming = false;
798 }
799 setWfcModeInternal(mContext, mode);
800 setWfcRoamingSettingInternal(mContext, roaming);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700801
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800802 return isFeatureOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700803 }
804
Etan Cohenabbd7882014-09-26 22:35:35 -0700805 private ImsManager(Context context, int phoneId) {
Wink Savilleef36ef62014-06-11 08:39:38 -0700806 mContext = context;
Etan Cohenabbd7882014-09-26 22:35:35 -0700807 mPhoneId = phoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700808 createImsService(true);
809 }
810
Etan Cohenf4311122015-02-26 17:47:13 -0800811 /*
812 * Returns a flag indicating whether the IMS service is available.
813 */
814 public boolean isServiceAvailable() {
815 if (mImsService != null) {
816 return true;
817 }
818
819 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
820 if (binder != null) {
821 return true;
822 }
823
824 return false;
825 }
826
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800827 public void setImsConfigListener(ImsConfigListener listener) {
828 mImsConfigListener = listener;
829 }
830
Wink Savilleef36ef62014-06-11 08:39:38 -0700831 /**
832 * Opens the IMS service for making calls and/or receiving generic IMS calls.
833 * The caller may make subsquent calls through {@link #makeCall}.
834 * The IMS service will register the device to the operator's network with the credentials
835 * (from ISIM) periodically in order to receive calls from the operator's network.
836 * When the IMS service receives a new call, it will send out an intent with
837 * the provided action string.
838 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call.
839 *
840 * @param serviceClass a service class specified in {@link ImsServiceClass}
841 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
842 * @param incomingCallPendingIntent When an incoming call is received,
843 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to
844 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE}
845 * as the result code and the intent to fill in the call ID; It cannot be null
846 * @param listener To listen to IMS registration events; It cannot be null
847 * @return identifier (greater than 0) for the specified service
848 * @throws NullPointerException if {@code incomingCallPendingIntent}
849 * or {@code listener} is null
850 * @throws ImsException if calling the IMS service results in an error
851 * @see #getCallId
852 * @see #getServiceId
853 */
854 public int open(int serviceClass, PendingIntent incomingCallPendingIntent,
855 ImsConnectionStateListener listener) throws ImsException {
856 checkAndThrowExceptionIfServiceUnavailable();
857
858 if (incomingCallPendingIntent == null) {
859 throw new NullPointerException("incomingCallPendingIntent can't be null");
860 }
861
862 if (listener == null) {
863 throw new NullPointerException("listener can't be null");
864 }
865
866 int result = 0;
867
868 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700869 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent,
Wink Savilleef36ef62014-06-11 08:39:38 -0700870 createRegistrationListenerProxy(serviceClass, listener));
871 } catch (RemoteException e) {
872 throw new ImsException("open()", e,
873 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
874 }
875
876 if (result <= 0) {
877 // If the return value is a minus value,
878 // it means that an error occurred in the service.
879 // So, it needs to convert to the reason code specified in ImsReasonInfo.
880 throw new ImsException("open()", (result * (-1)));
881 }
882
883 return result;
884 }
885
886 /**
Pavel Zhamaitsiakce410172016-04-15 10:55:56 -0700887 * Adds registration listener to the IMS service.
888 *
889 * @param serviceClass a service class specified in {@link ImsServiceClass}
890 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
891 * @param listener To listen to IMS registration events; It cannot be null
892 * @throws NullPointerException if {@code listener} is null
893 * @throws ImsException if calling the IMS service results in an error
894 */
895 public void addRegistrationListener(int serviceClass, ImsConnectionStateListener listener)
896 throws ImsException {
897 checkAndThrowExceptionIfServiceUnavailable();
898
899 if (listener == null) {
900 throw new NullPointerException("listener can't be null");
901 }
902
903 try {
904 mImsService.addRegistrationListener(mPhoneId, serviceClass,
905 createRegistrationListenerProxy(serviceClass, listener));
906 } catch (RemoteException e) {
907 throw new ImsException("addRegistrationListener()", e,
908 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
909 }
910 }
911
912 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700913 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls.
914 * All the resources that were allocated to the service are also released.
915 *
916 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open}
917 * @throws ImsException if calling the IMS service results in an error
918 */
919 public void close(int serviceId) throws ImsException {
920 checkAndThrowExceptionIfServiceUnavailable();
921
922 try {
923 mImsService.close(serviceId);
924 } catch (RemoteException e) {
925 throw new ImsException("close()", e,
926 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
927 } finally {
928 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500929 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700930 mEcbm = null;
Tyler Gunn4d128b62016-04-13 15:44:38 -0700931 mMultiEndpoint = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700932 }
933 }
934
935 /**
936 * Gets the configuration interface to provision / withdraw the supplementary service settings.
937 *
938 * @param serviceId a service id which is obtained from {@link ImsManager#open}
939 * @return the Ut interface instance
940 * @throws ImsException if getting the Ut interface results in an error
941 */
942 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId)
943 throws ImsException {
944 // FIXME: manage the multiple Ut interfaces based on the service id
945 if (mUt == null) {
946 checkAndThrowExceptionIfServiceUnavailable();
947
948 try {
949 IImsUt iUt = mImsService.getUtInterface(serviceId);
950
951 if (iUt == null) {
952 throw new ImsException("getSupplementaryServiceConfiguration()",
953 ImsReasonInfo.CODE_UT_NOT_SUPPORTED);
954 }
955
956 mUt = new ImsUt(iUt);
957 } catch (RemoteException e) {
958 throw new ImsException("getSupplementaryServiceConfiguration()", e,
959 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
960 }
961 }
962
963 return mUt;
964 }
965
966 /**
967 * Checks if the IMS service has successfully registered to the IMS network
968 * with the specified service & call type.
969 *
970 * @param serviceId a service id which is obtained from {@link ImsManager#open}
971 * @param serviceType a service type that is specified in {@link ImsCallProfile}
972 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
973 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
974 * @param callType a call type that is specified in {@link ImsCallProfile}
975 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
976 * {@link ImsCallProfile#CALL_TYPE_VOICE}
977 * {@link ImsCallProfile#CALL_TYPE_VT}
978 * {@link ImsCallProfile#CALL_TYPE_VS}
979 * @return true if the specified service id is connected to the IMS network;
980 * false otherwise
981 * @throws ImsException if calling the IMS service results in an error
982 */
983 public boolean isConnected(int serviceId, int serviceType, int callType)
984 throws ImsException {
985 checkAndThrowExceptionIfServiceUnavailable();
986
987 try {
988 return mImsService.isConnected(serviceId, serviceType, callType);
989 } catch (RemoteException e) {
990 throw new ImsException("isServiceConnected()", e,
991 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
992 }
993 }
994
995 /**
996 * Checks if the specified IMS service is opend.
997 *
998 * @param serviceId a service id which is obtained from {@link ImsManager#open}
999 * @return true if the specified service id is opened; false otherwise
1000 * @throws ImsException if calling the IMS service results in an error
1001 */
1002 public boolean isOpened(int serviceId) throws ImsException {
1003 checkAndThrowExceptionIfServiceUnavailable();
1004
1005 try {
1006 return mImsService.isOpened(serviceId);
1007 } catch (RemoteException e) {
1008 throw new ImsException("isOpened()", e,
1009 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1010 }
1011 }
1012
1013 /**
1014 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
1015 *
1016 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1017 * @param serviceType a service type that is specified in {@link ImsCallProfile}
1018 * {@link ImsCallProfile#SERVICE_TYPE_NONE}
1019 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
1020 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
1021 * @param callType a call type that is specified in {@link ImsCallProfile}
1022 * {@link ImsCallProfile#CALL_TYPE_VOICE}
1023 * {@link ImsCallProfile#CALL_TYPE_VT}
1024 * {@link ImsCallProfile#CALL_TYPE_VT_TX}
1025 * {@link ImsCallProfile#CALL_TYPE_VT_RX}
1026 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
1027 * {@link ImsCallProfile#CALL_TYPE_VS}
1028 * {@link ImsCallProfile#CALL_TYPE_VS_TX}
1029 * {@link ImsCallProfile#CALL_TYPE_VS_RX}
1030 * @return a {@link ImsCallProfile} object
1031 * @throws ImsException if calling the IMS service results in an error
1032 */
1033 public ImsCallProfile createCallProfile(int serviceId,
1034 int serviceType, int callType) throws ImsException {
1035 checkAndThrowExceptionIfServiceUnavailable();
1036
1037 try {
1038 return mImsService.createCallProfile(serviceId, serviceType, callType);
1039 } catch (RemoteException e) {
1040 throw new ImsException("createCallProfile()", e,
1041 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1042 }
1043 }
1044
1045 /**
1046 * Creates a {@link ImsCall} to make a call.
1047 *
1048 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1049 * @param profile a call profile to make the call
1050 * (it contains service type, call type, media information, etc.)
1051 * @param participants participants to invite the conference call
1052 * @param listener listen to the call events from {@link ImsCall}
1053 * @return a {@link ImsCall} object
1054 * @throws ImsException if calling the IMS service results in an error
1055 */
1056 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees,
1057 ImsCall.Listener listener) throws ImsException {
1058 if (DBG) {
1059 log("makeCall :: serviceId=" + serviceId
fionaxu7b3107c2016-07-06 14:04:06 -07001060 + ", profile=" + profile);
Wink Savilleef36ef62014-06-11 08:39:38 -07001061 }
1062
1063 checkAndThrowExceptionIfServiceUnavailable();
1064
1065 ImsCall call = new ImsCall(mContext, profile);
1066
1067 call.setListener(listener);
1068 ImsCallSession session = createCallSession(serviceId, profile);
1069
1070 if ((callees != null) && (callees.length == 1)) {
1071 call.start(session, callees[0]);
1072 } else {
1073 call.start(session, callees);
1074 }
1075
1076 return call;
1077 }
1078
1079 /**
1080 * Creates a {@link ImsCall} to take an incoming call.
1081 *
1082 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1083 * @param incomingCallIntent the incoming call broadcast intent
1084 * @param listener to listen to the call events from {@link ImsCall}
1085 * @return a {@link ImsCall} object
1086 * @throws ImsException if calling the IMS service results in an error
1087 */
1088 public ImsCall takeCall(int serviceId, Intent incomingCallIntent,
1089 ImsCall.Listener listener) throws ImsException {
1090 if (DBG) {
1091 log("takeCall :: serviceId=" + serviceId
1092 + ", incomingCall=" + incomingCallIntent);
1093 }
1094
1095 checkAndThrowExceptionIfServiceUnavailable();
1096
1097 if (incomingCallIntent == null) {
1098 throw new ImsException("Can't retrieve session with null intent",
1099 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
1100 }
1101
1102 int incomingServiceId = getServiceId(incomingCallIntent);
1103
1104 if (serviceId != incomingServiceId) {
1105 throw new ImsException("Service id is mismatched in the incoming call intent",
1106 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
1107 }
1108
1109 String callId = getCallId(incomingCallIntent);
1110
1111 if (callId == null) {
1112 throw new ImsException("Call ID missing in the incoming call intent",
1113 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
1114 }
1115
1116 try {
1117 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId);
1118
1119 if (session == null) {
1120 throw new ImsException("No pending session for the call",
1121 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL);
1122 }
1123
1124 ImsCall call = new ImsCall(mContext, session.getCallProfile());
1125
1126 call.attachSession(new ImsCallSession(session));
1127 call.setListener(listener);
1128
1129 return call;
1130 } catch (Throwable t) {
1131 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED);
1132 }
1133 }
1134
1135 /**
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001136 * Gets the config interface to get/set service/capability parameters.
1137 *
1138 * @return the ImsConfig instance.
1139 * @throws ImsException if getting the setting interface results in an error.
1140 */
1141 public ImsConfig getConfigInterface() throws ImsException {
1142
1143 if (mConfig == null) {
1144 checkAndThrowExceptionIfServiceUnavailable();
1145
1146 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001147 IImsConfig config = mImsService.getConfigInterface(mPhoneId);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001148 if (config == null) {
1149 throw new ImsException("getConfigInterface()",
1150 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
1151 }
Libin.Tang@motorola.com54953c72014-08-07 15:02:08 -05001152 mConfig = new ImsConfig(config, mContext);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001153 } catch (RemoteException e) {
1154 throw new ImsException("getConfigInterface()", e,
1155 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1156 }
1157 }
1158 if (DBG) log("getConfigInterface(), mConfig= " + mConfig);
1159 return mConfig;
1160 }
1161
Etan Cohen82f78122014-12-15 10:10:14 -08001162 public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete)
Shriram Ganeshc403b7b2014-08-14 14:18:57 +05301163 throws ImsException {
1164
Etan Cohen82f78122014-12-15 10:10:14 -08001165 checkAndThrowExceptionIfServiceUnavailable();
Shriram Ganeshc403b7b2014-08-14 14:18:57 +05301166
Etan Cohen82f78122014-12-15 10:10:14 -08001167 try {
1168 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete);
1169 } catch (RemoteException e) {
1170 throw new ImsException("setTTYMode()", e,
1171 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1172 }
1173
Junda Liue7663c02015-06-23 11:16:26 -07001174 if (!getBooleanCarrierConfig(context,
1175 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -08001176 setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) &&
1177 isEnhanced4gLteModeSettingEnabledByUser(context));
1178 }
Shriram Ganeshc403b7b2014-08-14 14:18:57 +05301179 }
1180
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001181 /**
Junda Liue7663c02015-06-23 11:16:26 -07001182 * Get the boolean config from carrier config manager.
1183 *
1184 * @param context the context to get carrier service
1185 * @param key config key defined in CarrierConfigManager
1186 * @return boolean value of corresponding key.
1187 */
1188 private static boolean getBooleanCarrierConfig(Context context, String key) {
1189 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
1190 Context.CARRIER_CONFIG_SERVICE);
Jonathan Basseri2acea6f2015-07-01 15:00:38 -07001191 PersistableBundle b = null;
Junda Liue7663c02015-06-23 11:16:26 -07001192 if (configManager != null) {
Jonathan Basseri2acea6f2015-07-01 15:00:38 -07001193 b = configManager.getConfig();
1194 }
1195 if (b != null) {
1196 return b.getBoolean(key);
Junda Liue7663c02015-06-23 11:16:26 -07001197 } else {
1198 // Return static default defined in CarrierConfigManager.
1199 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
1200 }
1201 }
1202
1203 /**
fionaxu5803ef02016-03-08 11:48:48 -08001204 * Get the int config from carrier config manager.
1205 *
1206 * @param context the context to get carrier service
1207 * @param key config key defined in CarrierConfigManager
1208 * @return integer value of corresponding key.
1209 */
1210 private static int getIntCarrierConfig(Context context, String key) {
1211 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
1212 Context.CARRIER_CONFIG_SERVICE);
1213 PersistableBundle b = null;
1214 if (configManager != null) {
1215 b = configManager.getConfig();
1216 }
1217 if (b != null) {
1218 return b.getInt(key);
1219 } else {
1220 // Return static default defined in CarrierConfigManager.
1221 return CarrierConfigManager.getDefaultConfig().getInt(key);
1222 }
1223 }
1224
1225 /**
Wink Savilleef36ef62014-06-11 08:39:38 -07001226 * Gets the call ID from the specified incoming call broadcast intent.
1227 *
1228 * @param incomingCallIntent the incoming call broadcast intent
1229 * @return the call ID or null if the intent does not contain it
1230 */
1231 private static String getCallId(Intent incomingCallIntent) {
1232 if (incomingCallIntent == null) {
1233 return null;
1234 }
1235
1236 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
1237 }
1238
1239 /**
1240 * Gets the service type from the specified incoming call broadcast intent.
1241 *
1242 * @param incomingCallIntent the incoming call broadcast intent
1243 * @return the service identifier or -1 if the intent does not contain it
1244 */
1245 private static int getServiceId(Intent incomingCallIntent) {
1246 if (incomingCallIntent == null) {
1247 return (-1);
1248 }
1249
1250 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1);
1251 }
1252
1253 /**
1254 * Binds the IMS service only if the service is not created.
1255 */
1256 private void checkAndThrowExceptionIfServiceUnavailable()
1257 throws ImsException {
1258 if (mImsService == null) {
1259 createImsService(true);
1260
1261 if (mImsService == null) {
1262 throw new ImsException("Service is unavailable",
1263 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1264 }
1265 }
1266 }
1267
Etan Cohenabbd7882014-09-26 22:35:35 -07001268 private static String getImsServiceName(int phoneId) {
1269 // TODO: MSIM implementation needs to decide on service name as a function of phoneId
Etan Cohend7727462014-07-12 14:54:10 -07001270 return IMS_SERVICE;
1271 }
1272
Wink Savilleef36ef62014-06-11 08:39:38 -07001273 /**
1274 * Binds the IMS service to make/receive the call.
1275 */
1276 private void createImsService(boolean checkService) {
1277 if (checkService) {
Etan Cohenabbd7882014-09-26 22:35:35 -07001278 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -07001279
1280 if (binder == null) {
1281 return;
1282 }
1283 }
1284
Etan Cohenabbd7882014-09-26 22:35:35 -07001285 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -07001286
1287 if (b != null) {
1288 try {
1289 b.linkToDeath(mDeathRecipient, 0);
1290 } catch (RemoteException e) {
1291 }
1292 }
1293
1294 mImsService = IImsService.Stub.asInterface(b);
1295 }
1296
1297 /**
1298 * Creates a {@link ImsCallSession} with the specified call profile.
1299 * Use other methods, if applicable, instead of interacting with
1300 * {@link ImsCallSession} directly.
1301 *
1302 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1303 * @param profile a call profile to make the call
1304 */
1305 private ImsCallSession createCallSession(int serviceId,
1306 ImsCallProfile profile) throws ImsException {
1307 try {
1308 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null));
1309 } catch (RemoteException e) {
1310 return null;
1311 }
1312 }
1313
1314 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass,
1315 ImsConnectionStateListener listener) {
1316 ImsRegistrationListenerProxy proxy =
1317 new ImsRegistrationListenerProxy(serviceClass, listener);
1318 return proxy;
1319 }
1320
Etan Cohena00c9192014-12-23 15:02:29 -08001321 private static void log(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001322 Rlog.d(TAG, s);
1323 }
1324
Etan Cohena00c9192014-12-23 15:02:29 -08001325 private static void loge(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001326 Rlog.e(TAG, s);
1327 }
1328
Etan Cohena00c9192014-12-23 15:02:29 -08001329 private static void loge(String s, Throwable t) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001330 Rlog.e(TAG, s, t);
1331 }
1332
1333 /**
ram7da5a112014-07-16 20:59:27 +05301334 * Used for turning on IMS.if its off already
1335 */
Etan Cohen82f78122014-12-15 10:10:14 -08001336 private void turnOnIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001337 checkAndThrowExceptionIfServiceUnavailable();
1338
ram7da5a112014-07-16 20:59:27 +05301339 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001340 mImsService.turnOnIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301341 } catch (RemoteException e) {
1342 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1343 }
1344 }
1345
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001346 private boolean isImsTurnOffAllowed() {
Meng Wang9352c432016-06-08 14:22:20 -07001347 return isTurnOffImsAllowedByPlatform(mContext)
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001348 && (!isWfcEnabledByPlatform(mContext)
1349 || !isWfcEnabledByUser(mContext));
1350 }
1351
Etan Cohen82f78122014-12-15 10:10:14 -08001352 private void setAdvanced4GMode(boolean turnOn) throws ImsException {
Etan Cohencfc784d2014-08-07 18:40:31 -07001353 checkAndThrowExceptionIfServiceUnavailable();
1354
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001355 try {
1356 ImsConfig config = getConfigInterface();
1357 if (config != null && (turnOn || !isImsTurnOffAllowed())) {
1358 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -08001359 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, mImsConfigListener);
Pavel Zhamaitsiakff29b9d2016-04-15 12:16:57 -07001360
1361 if (isVtEnabledByPlatform(mContext)) {
Jack Yu643ffe42016-07-08 14:25:46 -07001362 boolean enableViLte = turnOn && isVtEnabledByUser(mContext) &&
1363 mDataEnabled.get();
Pavel Zhamaitsiakff29b9d2016-04-15 12:16:57 -07001364 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
1365 TelephonyManager.NETWORK_TYPE_LTE,
1366 enableViLte ? 1 : 0,
1367 mImsConfigListener);
1368 }
Etan Cohenb651fa52014-10-22 10:51:29 -07001369 }
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001370 } catch (ImsException e) {
Meng Wangca7d4c42016-06-30 22:05:24 -07001371 loge("setAdvanced4GMode() : ", e);
Etan Cohencfc784d2014-08-07 18:40:31 -07001372 }
Etan Cohencfc784d2014-08-07 18:40:31 -07001373 if (turnOn) {
Meng Wangca7d4c42016-06-30 22:05:24 -07001374 log("setAdvanced4GMode() : turnOnIms");
Etan Cohencfc784d2014-08-07 18:40:31 -07001375 turnOnIms();
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001376 } else if (isImsTurnOffAllowed()) {
Etan Cohencfc784d2014-08-07 18:40:31 -07001377 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms");
1378 turnOffIms();
1379 }
1380 }
1381
ram7da5a112014-07-16 20:59:27 +05301382 /**
1383 * Used for turning off IMS completely in order to make the device CSFB'ed.
1384 * Once turned off, all calls will be over CS.
1385 */
Etan Cohen82f78122014-12-15 10:10:14 -08001386 private void turnOffIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001387 checkAndThrowExceptionIfServiceUnavailable();
1388
ram7da5a112014-07-16 20:59:27 +05301389 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001390 mImsService.turnOffIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301391 } catch (RemoteException e) {
1392 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1393 }
1394 }
1395
1396 /**
Wink Savilleef36ef62014-06-11 08:39:38 -07001397 * Death recipient class for monitoring IMS service.
1398 */
1399 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient {
1400 @Override
1401 public void binderDied() {
1402 mImsService = null;
1403 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001404 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001405 mEcbm = null;
Tyler Gunn4d128b62016-04-13 15:44:38 -07001406 mMultiEndpoint = null;
Wink Savilleef36ef62014-06-11 08:39:38 -07001407
1408 if (mContext != null) {
Etan Cohend7727462014-07-12 14:54:10 -07001409 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN);
Etan Cohenabbd7882014-09-26 22:35:35 -07001410 intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
Etan Cohend7727462014-07-12 14:54:10 -07001411 mContext.sendBroadcast(new Intent(intent));
Wink Savilleef36ef62014-06-11 08:39:38 -07001412 }
1413 }
1414 }
1415
1416 /**
1417 * Adapter class for {@link IImsRegistrationListener}.
1418 */
1419 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub {
1420 private int mServiceClass;
1421 private ImsConnectionStateListener mListener;
1422
1423 public ImsRegistrationListenerProxy(int serviceClass,
1424 ImsConnectionStateListener listener) {
1425 mServiceClass = serviceClass;
1426 mListener = listener;
1427 }
1428
1429 public boolean isSameProxy(int serviceClass) {
1430 return (mServiceClass == serviceClass);
1431 }
1432
Omkar Kolangadea7ced642015-05-04 17:55:13 -07001433 @Deprecated
Wink Savilleef36ef62014-06-11 08:39:38 -07001434 public void registrationConnected() {
1435 if (DBG) {
1436 log("registrationConnected ::");
1437 }
1438
1439 if (mListener != null) {
1440 mListener.onImsConnected();
1441 }
1442 }
1443
Omkar Kolangadea7ced642015-05-04 17:55:13 -07001444 @Deprecated
Rekha Kumar14631742015-02-04 10:47:00 -08001445 public void registrationProgressing() {
Wink Savilleef36ef62014-06-11 08:39:38 -07001446 if (DBG) {
Rekha Kumar14631742015-02-04 10:47:00 -08001447 log("registrationProgressing ::");
Wink Savilleef36ef62014-06-11 08:39:38 -07001448 }
1449
1450 if (mListener != null) {
Rekha Kumar14631742015-02-04 10:47:00 -08001451 mListener.onImsProgressing();
1452 }
1453 }
1454
1455 @Override
Omkar Kolangadea7ced642015-05-04 17:55:13 -07001456 public void registrationConnectedWithRadioTech(int imsRadioTech) {
1457 // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY
1458 // values in ServiceState.java.
1459 if (DBG) {
1460 log("registrationConnectedWithRadioTech :: imsRadioTech=" + imsRadioTech);
1461 }
1462
1463 if (mListener != null) {
1464 mListener.onImsConnected();
1465 }
1466 }
1467
1468 @Override
1469 public void registrationProgressingWithRadioTech(int imsRadioTech) {
1470 // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY
1471 // values in ServiceState.java.
1472 if (DBG) {
1473 log("registrationProgressingWithRadioTech :: imsRadioTech=" + imsRadioTech);
1474 }
1475
1476 if (mListener != null) {
1477 mListener.onImsProgressing();
1478 }
1479 }
1480
1481 @Override
Rekha Kumar14631742015-02-04 10:47:00 -08001482 public void registrationDisconnected(ImsReasonInfo imsReasonInfo) {
1483 if (DBG) {
1484 log("registrationDisconnected :: imsReasonInfo" + imsReasonInfo);
1485 }
1486
1487 if (mListener != null) {
1488 mListener.onImsDisconnected(imsReasonInfo);
Wink Savilleef36ef62014-06-11 08:39:38 -07001489 }
1490 }
1491
1492 @Override
1493 public void registrationResumed() {
1494 if (DBG) {
1495 log("registrationResumed ::");
1496 }
1497
1498 if (mListener != null) {
1499 mListener.onImsResumed();
1500 }
1501 }
1502
1503 @Override
1504 public void registrationSuspended() {
1505 if (DBG) {
1506 log("registrationSuspended ::");
1507 }
1508
1509 if (mListener != null) {
1510 mListener.onImsSuspended();
1511 }
1512 }
1513
1514 @Override
1515 public void registrationServiceCapabilityChanged(int serviceClass, int event) {
1516 log("registrationServiceCapabilityChanged :: serviceClass=" +
1517 serviceClass + ", event=" + event);
1518
1519 if (mListener != null) {
1520 mListener.onImsConnected();
1521 }
1522 }
ram7da5a112014-07-16 20:59:27 +05301523
1524 @Override
1525 public void registrationFeatureCapabilityChanged(int serviceClass,
1526 int[] enabledFeatures, int[] disabledFeatures) {
1527 log("registrationFeatureCapabilityChanged :: serviceClass=" +
1528 serviceClass);
Libin.Tang@motorola.come2296782014-08-19 14:20:01 -05001529 if (mListener != null) {
1530 mListener.onFeatureCapabilityChanged(serviceClass,
1531 enabledFeatures, disabledFeatures);
1532 }
ram7da5a112014-07-16 20:59:27 +05301533 }
1534
Shriram Ganeshd3adfad2015-05-31 10:06:15 -07001535 @Override
1536 public void voiceMessageCountUpdate(int count) {
1537 log("voiceMessageCountUpdate :: count=" + count);
1538
1539 if (mListener != null) {
1540 mListener.onVoiceMessageCountChanged(count);
1541 }
1542 }
1543
Pavel Zhamaitsiak4de9cbb2016-02-11 17:21:05 -08001544 @Override
1545 public void registrationAssociatedUriChanged(Uri[] uris) {
1546 if (DBG) log("registrationAssociatedUriChanged ::");
1547
1548 if (mListener != null) {
1549 mListener.registrationAssociatedUriChanged(uris);
1550 }
1551 }
Wink Savilleef36ef62014-06-11 08:39:38 -07001552 }
Tyler Gunn4d128b62016-04-13 15:44:38 -07001553
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001554 /**
1555 * Gets the ECBM interface to request ECBM exit.
1556 *
1557 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1558 * @return the ECBM interface instance
1559 * @throws ImsException if getting the ECBM interface results in an error
1560 */
1561 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException {
1562 if (mEcbm == null) {
1563 checkAndThrowExceptionIfServiceUnavailable();
1564
1565 try {
1566 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId);
1567
1568 if (iEcbm == null) {
1569 throw new ImsException("getEcbmInterface()",
1570 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED);
1571 }
1572 mEcbm = new ImsEcbm(iEcbm);
1573 } catch (RemoteException e) {
1574 throw new ImsException("getEcbmInterface()", e,
1575 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1576 }
1577 }
1578 return mEcbm;
1579 }
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001580
1581 /**
Tyler Gunn4d128b62016-04-13 15:44:38 -07001582 * Gets the Multi-Endpoint interface to subscribe to multi-enpoint notifications..
1583 *
1584 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1585 * @return the multi-endpoint interface instance
1586 * @throws ImsException if getting the multi-endpoint interface results in an error
1587 */
1588 public ImsMultiEndpoint getMultiEndpointInterface(int serviceId) throws ImsException {
1589 if (mMultiEndpoint == null) {
1590 checkAndThrowExceptionIfServiceUnavailable();
1591
1592 try {
1593 IImsMultiEndpoint iImsMultiEndpoint = mImsService.getMultiEndpointInterface(
1594 serviceId);
1595
1596 if (iImsMultiEndpoint == null) {
1597 throw new ImsException("getMultiEndpointInterface()",
1598 ImsReasonInfo.CODE_MULTIENDPOINT_NOT_SUPPORTED);
1599 }
1600 mMultiEndpoint = new ImsMultiEndpoint(iImsMultiEndpoint);
1601 } catch (RemoteException e) {
1602 throw new ImsException("getMultiEndpointInterface()", e,
1603 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1604 }
1605 }
1606 return mMultiEndpoint;
1607 }
1608
1609 /**
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001610 * Resets ImsManager settings back to factory defaults.
1611 *
1612 * @hide
1613 */
1614 public static void factoryReset(Context context) {
1615 // Set VoLTE to default
1616 android.provider.Settings.Global.putInt(context.getContentResolver(),
1617 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED,
1618 ImsConfig.FeatureValueConstants.ON);
1619
1620 // Set VoWiFi to default
1621 android.provider.Settings.Global.putInt(context.getContentResolver(),
1622 android.provider.Settings.Global.WFC_IMS_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -08001623 getBooleanCarrierConfig(context,
1624 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL) ?
1625 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001626
1627 // Set VoWiFi mode to default
1628 android.provider.Settings.Global.putInt(context.getContentResolver(),
1629 android.provider.Settings.Global.WFC_IMS_MODE,
fionaxu5803ef02016-03-08 11:48:48 -08001630 getIntCarrierConfig(context,
1631 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001632
1633 // Set VoWiFi roaming to default
1634 android.provider.Settings.Global.putInt(context.getContentResolver(),
1635 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -08001636 getBooleanCarrierConfig(context,
1637 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ?
1638 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001639
1640 // Set VT to default
Pavel Zhamaitsiak92b54b22016-04-01 15:55:47 -07001641 android.provider.Settings.Global.putInt(context.getContentResolver(),
1642 android.provider.Settings.Global.VT_IMS_ENABLED,
1643 ImsConfig.FeatureValueConstants.ON);
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001644
1645 // Push settings to ImsConfig
1646 ImsManager.updateImsServiceConfig(context,
1647 SubscriptionManager.getDefaultVoicePhoneId(), true);
1648 }
Jack Yu2f102bd2015-12-28 15:31:48 -08001649
Jack Yu643ffe42016-07-08 14:25:46 -07001650 /**
1651 * Set data enabled/disabled flag.
1652 * @param enabled True if data is enabled, otherwise disabled.
1653 */
1654 public void setDataEnabled(boolean enabled) {
1655 log("setDataEnabled: " + enabled);
1656 mDataEnabled.set(enabled);
1657 }
1658
Jack Yu2f102bd2015-12-28 15:31:48 -08001659 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1660 pw.println("ImsManager:");
1661 pw.println(" mPhoneId = " + mPhoneId);
1662 pw.println(" mConfigUpdated = " + mConfigUpdated);
1663 pw.println(" mImsService = " + mImsService);
Jack Yu643ffe42016-07-08 14:25:46 -07001664 pw.println(" mDataEnabled = " + mDataEnabled.get());
Jack Yu2f102bd2015-12-28 15:31:48 -08001665
1666 pw.println(" isGbaValid = " + isGbaValid(mContext));
1667 pw.println(" isImsTurnOffAllowed = " + isImsTurnOffAllowed());
1668 pw.println(" isNonTtyOrTtyOnVolteEnabled = " + isNonTtyOrTtyOnVolteEnabled(mContext));
1669
1670 pw.println(" isVolteEnabledByPlatform = " + isVolteEnabledByPlatform(mContext));
1671 pw.println(" isVolteProvisionedOnDevice = " + isVolteProvisionedOnDevice(mContext));
1672 pw.println(" isEnhanced4gLteModeSettingEnabledByUser = " +
1673 isEnhanced4gLteModeSettingEnabledByUser(mContext));
1674 pw.println(" isVtEnabledByPlatform = " + isVtEnabledByPlatform(mContext));
1675 pw.println(" isVtEnabledByUser = " + isVtEnabledByUser(mContext));
1676
1677 pw.println(" isWfcEnabledByPlatform = " + isWfcEnabledByPlatform(mContext));
1678 pw.println(" isWfcEnabledByUser = " + isWfcEnabledByUser(mContext));
1679 pw.println(" getWfcMode = " + getWfcMode(mContext));
1680 pw.println(" isWfcRoamingEnabledByUser = " + isWfcRoamingEnabledByUser(mContext));
1681
pkanwar10d18832016-07-12 08:50:01 -07001682 pw.println(" isVtProvisionedOnDevice = " + isVtProvisionedOnDevice(mContext));
1683 pw.println(" isWfcProvisionedOnDevice = " + isWfcProvisionedOnDevice(mContext));
Jack Yu2f102bd2015-12-28 15:31:48 -08001684 pw.flush();
1685 }
Wink Savilleef36ef62014-06-11 08:39:38 -07001686}