blob: 22e0f44777c44685a7159920c9c00bf56e2e7b47 [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;
49
Wink Savilleef36ef62014-06-11 08:39:38 -070050/**
51 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
52 * the operator's IMS network. This class is the starting point for any IMS actions.
53 * You can acquire an instance of it with {@link #getInstance getInstance()}.</p>
54 * <p>The APIs in this class allows you to:</p>
55 *
56 * @hide
57 */
58public class ImsManager {
Etan Cohen19604c02014-08-11 14:32:57 -070059
Etan Cohenaf55a402014-09-04 22:34:41 -070060 /*
61 * Debug flag to override configuration flag
62 */
Etan Cohenb651fa52014-10-22 10:51:29 -070063 public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr";
64 public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohenea2b5832014-10-23 18:50:35 -070065 public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr";
66 public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohena00c9192014-12-23 15:02:29 -080067 public static final String PROPERTY_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr";
68 public static final int PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT = 0;
Meng Wang9352c432016-06-08 14:22:20 -070069 public static final String PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE = "persist.dbg.allow_ims_off";
70 public static final int PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT = 0;
Etan Cohenaf55a402014-09-04 22:34:41 -070071
Wink Savilleef36ef62014-06-11 08:39:38 -070072 /**
73 * For accessing the IMS related service.
74 * Internal use only.
75 * @hide
76 */
Etan Cohend7727462014-07-12 14:54:10 -070077 private static final String IMS_SERVICE = "ims";
Wink Savilleef36ef62014-06-11 08:39:38 -070078
79 /**
80 * The result code to be sent back with the incoming call {@link PendingIntent}.
81 * @see #open(PendingIntent, ImsConnectionStateListener)
82 */
83 public static final int INCOMING_CALL_RESULT_CODE = 101;
84
85 /**
86 * Key to retrieve the call ID from an incoming call intent.
87 * @see #open(PendingIntent, ImsConnectionStateListener)
88 */
89 public static final String EXTRA_CALL_ID = "android:imsCallID";
90
91 /**
92 * Action to broadcast when ImsService is up.
93 * Internal use only.
94 * @hide
95 */
96 public static final String ACTION_IMS_SERVICE_UP =
97 "com.android.ims.IMS_SERVICE_UP";
98
99 /**
100 * Action to broadcast when ImsService is down.
101 * Internal use only.
102 * @hide
103 */
104 public static final String ACTION_IMS_SERVICE_DOWN =
105 "com.android.ims.IMS_SERVICE_DOWN";
106
107 /**
Pavel Zhamaitsiak0c2f15c2015-03-12 15:37:54 -0700108 * Action to broadcast when ImsService registration fails.
109 * Internal use only.
110 * @hide
111 */
112 public static final String ACTION_IMS_REGISTRATION_ERROR =
113 "com.android.ims.REGISTRATION_ERROR";
114
115 /**
Etan Cohend7727462014-07-12 14:54:10 -0700116 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
Etan Cohenabbd7882014-09-26 22:35:35 -0700117 * A long value; the phone ID corresponding to the IMS service coming up or down.
Etan Cohend7727462014-07-12 14:54:10 -0700118 * Internal use only.
119 * @hide
120 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700121 public static final String EXTRA_PHONE_ID = "android:phone_id";
Etan Cohend7727462014-07-12 14:54:10 -0700122
123 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700124 * Action for the incoming call intent for the Phone app.
125 * Internal use only.
126 * @hide
127 */
128 public static final String ACTION_IMS_INCOMING_CALL =
129 "com.android.ims.IMS_INCOMING_CALL";
130
131 /**
132 * Part of the ACTION_IMS_INCOMING_CALL intents.
133 * An integer value; service identifier obtained from {@link ImsManager#open}.
134 * Internal use only.
135 * @hide
136 */
137 public static final String EXTRA_SERVICE_ID = "android:imsServiceId";
138
139 /**
140 * Part of the ACTION_IMS_INCOMING_CALL intents.
141 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD.
142 * The value "true" indicates that the incoming call is for USSD.
143 * Internal use only.
144 * @hide
145 */
146 public static final String EXTRA_USSD = "android:ussd";
147
Shriram Ganeshd3adfad2015-05-31 10:06:15 -0700148 /**
149 * Part of the ACTION_IMS_INCOMING_CALL intents.
150 * A boolean value; Flag to indicate whether the call is an unknown
151 * dialing call. Such calls are originated by sending commands (like
152 * AT commands) directly to modem without Android involvement.
153 * Even though they are not incoming calls, they are propagated
154 * to Phone app using same ACTION_IMS_INCOMING_CALL intent.
155 * Internal use only.
156 * @hide
157 */
Anju Mathapati9c033792015-06-16 16:33:16 -0700158 public static final String EXTRA_IS_UNKNOWN_CALL = "android:isUnknown";
Shriram Ganeshd3adfad2015-05-31 10:06:15 -0700159
Wink Savilleef36ef62014-06-11 08:39:38 -0700160 private static final String TAG = "ImsManager";
161 private static final boolean DBG = true;
162
Wink Saville1e5a38a2014-10-23 10:24:46 -0700163 private static HashMap<Integer, ImsManager> sImsManagerInstances =
164 new HashMap<Integer, ImsManager>();
Etan Cohend7727462014-07-12 14:54:10 -0700165
Wink Savilleef36ef62014-06-11 08:39:38 -0700166 private Context mContext;
Etan Cohenabbd7882014-09-26 22:35:35 -0700167 private int mPhoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700168 private IImsService mImsService = null;
169 private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient();
170 // Ut interface for the supplementary service configuration
171 private ImsUt mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500172 // Interface to get/set ims config items
173 private ImsConfig mConfig = null;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700174 private boolean mConfigUpdated = false;
Wink Savilleef36ef62014-06-11 08:39:38 -0700175
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800176 private ImsConfigListener mImsConfigListener;
177
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700178 // ECBM interface
179 private ImsEcbm mEcbm = null;
180
Tyler Gunn4d128b62016-04-13 15:44:38 -0700181 private ImsMultiEndpoint mMultiEndpoint = null;
182
Amit Mahajan24f7b162016-07-21 16:33:53 -0700183 // SystemProperties used as cache
184 private static final String VOLTE_PROVISIONED_PROP = "net.lte.ims.volte.provisioned";
185 private static final String WFC_PROVISIONED_PROP = "net.lte.ims.wfc.provisioned";
186 private static final String VT_PROVISIONED_PROP = "net.lte.ims.vt.provisioned";
Jack Yu643ffe42016-07-08 14:25:46 -0700187 // Flag indicating data enabled or not. This flag should be in sync with
188 // DcTracker.isDataEnabled(). The flag will be set later during boot up.
Amit Mahajan24f7b162016-07-21 16:33:53 -0700189 private static final String DATA_ENABLED_PROP = "net.lte.ims.data.enabled";
190
191 public static final String TRUE = "true";
192 public static final String FALSE = "false";
Jack Yu643ffe42016-07-08 14:25:46 -0700193
Wink Savilleef36ef62014-06-11 08:39:38 -0700194 /**
195 * Gets a manager instance.
196 *
197 * @param context application context for creating the manager object
Etan Cohenabbd7882014-09-26 22:35:35 -0700198 * @param phoneId the phone ID for the IMS Service
199 * @return the manager instance corresponding to the phoneId
Wink Savilleef36ef62014-06-11 08:39:38 -0700200 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700201 public static ImsManager getInstance(Context context, int phoneId) {
Etan Cohend7727462014-07-12 14:54:10 -0700202 synchronized (sImsManagerInstances) {
Etan Cohenabbd7882014-09-26 22:35:35 -0700203 if (sImsManagerInstances.containsKey(phoneId))
204 return sImsManagerInstances.get(phoneId);
Wink Savilleef36ef62014-06-11 08:39:38 -0700205
Etan Cohenabbd7882014-09-26 22:35:35 -0700206 ImsManager mgr = new ImsManager(context, phoneId);
207 sImsManagerInstances.put(phoneId, mgr);
Etan Cohend7727462014-07-12 14:54:10 -0700208
209 return mgr;
210 }
Wink Savilleef36ef62014-06-11 08:39:38 -0700211 }
212
Etan Cohen45b5f312014-08-19 15:55:08 -0700213 /**
214 * Returns the user configuration of Enhanced 4G LTE Mode setting
215 */
216 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) {
Sungmin Choi2f1af952016-02-01 17:15:35 +0900217 // If user can't edit Enhanced 4G LTE Mode, it assumes Enhanced 4G LTE Mode is always true.
218 // If user changes SIM from editable mode to uneditable mode, need to return true.
219 if (!getBooleanCarrierConfig(context,
220 CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL)) {
221 return true;
222 }
Libin.Tang@motorola.com8a6bf4b2014-10-10 15:02:41 -0500223 int enabled = android.provider.Settings.Global.getInt(
224 context.getContentResolver(),
Etan Cohenb651fa52014-10-22 10:51:29 -0700225 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
Etan Cohena00c9192014-12-23 15:02:29 -0800226 return (enabled == 1) ? true : false;
Etan Cohen45b5f312014-08-19 15:55:08 -0700227 }
228
229 /**
Etan Cohen82f78122014-12-15 10:10:14 -0800230 * Change persistent Enhanced 4G LTE Mode setting
231 */
232 public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {
233 int value = enabled ? 1 : 0;
234 android.provider.Settings.Global.putInt(
235 context.getContentResolver(),
236 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, value);
237
238 if (isNonTtyOrTtyOnVolteEnabled(context)) {
239 ImsManager imsManager = ImsManager.getInstance(context,
240 SubscriptionManager.getDefaultVoicePhoneId());
241 if (imsManager != null) {
242 try {
243 imsManager.setAdvanced4GMode(enabled);
244 } catch (ImsException ie) {
245 // do nothing
246 }
247 }
248 }
249 }
250
251 /**
252 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is
253 * supported.
254 */
255 public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) {
Junda Liue7663c02015-06-23 11:16:26 -0700256 if (getBooleanCarrierConfig(context,
fionaxu5803ef02016-03-08 11:48:48 -0800257 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -0800258 return true;
259 }
260
261 return Settings.Secure.getInt(context.getContentResolver(),
262 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF)
263 == TelecomManager.TTY_MODE_OFF;
264 }
265
266 /**
Etan Cohenea2b5832014-10-23 18:50:35 -0700267 * Returns a platform configuration for VoLTE which may override the user setting.
Etan Cohen45b5f312014-08-19 15:55:08 -0700268 */
Etan Cohenea2b5832014-10-23 18:50:35 -0700269 public static boolean isVolteEnabledByPlatform(Context context) {
Etan Cohenb651fa52014-10-22 10:51:29 -0700270 if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE,
271 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) {
Etan Cohenaf55a402014-09-04 22:34:41 -0700272 return true;
273 }
274
Etan Cohenb5388a32014-11-26 11:57:47 -0800275 return context.getResources().getBoolean(
Junda Liue7663c02015-06-23 11:16:26 -0700276 com.android.internal.R.bool.config_device_volte_available)
277 && getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700278 CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL)
279 && isGbaValid(context);
Etan Cohenb5388a32014-11-26 11:57:47 -0800280 }
281
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700282 /**
Etan Cohenb5388a32014-11-26 11:57:47 -0800283 * Indicates whether VoLTE is provisioned on device
284 */
285 public static boolean isVolteProvisionedOnDevice(Context context) {
Junda Liue7663c02015-06-23 11:16:26 -0700286 if (getBooleanCarrierConfig(context,
287 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
Etan Cohenb5388a32014-11-26 11:57:47 -0800288 ImsManager mgr = ImsManager.getInstance(context,
Jonathan Basserid7133652015-04-07 19:54:24 -0700289 SubscriptionManager.getDefaultVoicePhoneId());
Etan Cohenb5388a32014-11-26 11:57:47 -0800290 if (mgr != null) {
Amit Mahajan24f7b162016-07-21 16:33:53 -0700291 return mgr.isVolteProvisioned();
Etan Cohenb5388a32014-11-26 11:57:47 -0800292 }
293 }
294
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700295 return true;
296 }
297
298 /**
299 * Indicates whether VoWifi is provisioned on device
300 */
301 public static boolean isWfcProvisionedOnDevice(Context context) {
302 if (getBooleanCarrierConfig(context,
303 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
304 ImsManager mgr = ImsManager.getInstance(context,
305 SubscriptionManager.getDefaultVoicePhoneId());
306 if (mgr != null) {
Amit Mahajan24f7b162016-07-21 16:33:53 -0700307 return mgr.isWfcProvisioned();
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700308 }
309 }
310
311 return true;
312 }
313
314 /**
315 * Indicates whether VT is provisioned on device
316 */
317 public static boolean isVtProvisionedOnDevice(Context context) {
318 if (getBooleanCarrierConfig(context,
319 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
320 ImsManager mgr = ImsManager.getInstance(context,
321 SubscriptionManager.getDefaultVoicePhoneId());
322 if (mgr != null) {
Amit Mahajan24f7b162016-07-21 16:33:53 -0700323 return mgr.isVtProvisioned();
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700324 }
325 }
326
327 return true;
Etan Cohenb651fa52014-10-22 10:51:29 -0700328 }
329
Etan Cohenea2b5832014-10-23 18:50:35 -0700330 /**
331 * Returns a platform configuration for VT which may override the user setting.
332 *
333 * Note: VT presumes that VoLTE is enabled (these are configuration settings
334 * which must be done correctly).
335 */
Etan Cohenb651fa52014-10-22 10:51:29 -0700336 public static boolean isVtEnabledByPlatform(Context context) {
Etan Cohenea2b5832014-10-23 18:50:35 -0700337 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE,
338 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) {
339 return true;
340 }
341
Etan Cohenb651fa52014-10-22 10:51:29 -0700342 return
343 context.getResources().getBoolean(
344 com.android.internal.R.bool.config_device_vt_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700345 getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700346 CarrierConfigManager.KEY_CARRIER_VT_AVAILABLE_BOOL) &&
347 isGbaValid(context);
Etan Cohen45b5f312014-08-19 15:55:08 -0700348 }
349
Etan Cohena00c9192014-12-23 15:02:29 -0800350 /**
Etan Cohena7d32e82015-05-04 18:02:09 -0700351 * Returns the user configuration of VT setting
352 */
353 public static boolean isVtEnabledByUser(Context context) {
354 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
355 android.provider.Settings.Global.VT_IMS_ENABLED,
356 ImsConfig.FeatureValueConstants.ON);
357 return (enabled == 1) ? true : false;
358 }
359
360 /**
361 * Change persistent VT enabled setting
362 */
363 public static void setVtSetting(Context context, boolean enabled) {
364 int value = enabled ? 1 : 0;
365 android.provider.Settings.Global.putInt(context.getContentResolver(),
366 android.provider.Settings.Global.VT_IMS_ENABLED, value);
367
368 ImsManager imsManager = ImsManager.getInstance(context,
369 SubscriptionManager.getDefaultVoicePhoneId());
370 if (imsManager != null) {
371 try {
372 ImsConfig config = imsManager.getConfigInterface();
373 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
374 TelephonyManager.NETWORK_TYPE_LTE,
375 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800376 : ImsConfig.FeatureValueConstants.OFF,
377 imsManager.mImsConfigListener);
Etan Cohena7d32e82015-05-04 18:02:09 -0700378
379 if (enabled) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700380 log("setVtSetting() : turnOnIms");
Etan Cohena7d32e82015-05-04 18:02:09 -0700381 imsManager.turnOnIms();
Meng Wang9352c432016-06-08 14:22:20 -0700382 } else if (isTurnOffImsAllowedByPlatform(context)
Pavel Zhamaitsiak4ca0cde2015-12-22 16:51:57 -0800383 && (!isVolteEnabledByPlatform(context)
Etan Cohena7d32e82015-05-04 18:02:09 -0700384 || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
385 log("setVtSetting() : imsServiceAllowTurnOff -> turnOffIms");
386 imsManager.turnOffIms();
387 }
388 } catch (ImsException e) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700389 loge("setVtSetting(): ", e);
Etan Cohena7d32e82015-05-04 18:02:09 -0700390 }
391 }
392 }
393
Meng Wang9352c432016-06-08 14:22:20 -0700394 /*
395 * Returns whether turning off ims is allowed by platform.
396 * The platform property may override the carrier config.
397 */
398 private static boolean isTurnOffImsAllowedByPlatform(Context context) {
399 if (SystemProperties.getInt(PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE,
400 PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT) == 1) {
401 return true;
402 }
403 return getBooleanCarrierConfig(context,
404 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL);
405 }
406
Etan Cohena7d32e82015-05-04 18:02:09 -0700407 /**
Etan Cohena00c9192014-12-23 15:02:29 -0800408 * Returns the user configuration of WFC setting
409 */
410 public static boolean isWfcEnabledByUser(Context context) {
411 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
412 android.provider.Settings.Global.WFC_IMS_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -0800413 getBooleanCarrierConfig(context,
414 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL) ?
415 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800416 return (enabled == 1) ? true : false;
417 }
418
419 /**
420 * Change persistent WFC enabled setting
421 */
422 public static void setWfcSetting(Context context, boolean enabled) {
423 int value = enabled ? 1 : 0;
424 android.provider.Settings.Global.putInt(context.getContentResolver(),
425 android.provider.Settings.Global.WFC_IMS_ENABLED, value);
426
427 ImsManager imsManager = ImsManager.getInstance(context,
428 SubscriptionManager.getDefaultVoicePhoneId());
429 if (imsManager != null) {
430 try {
431 ImsConfig config = imsManager.getConfigInterface();
Etan Cohena00c9192014-12-23 15:02:29 -0800432 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
Nathan Harold3a99f782015-07-24 15:02:34 -0700433 TelephonyManager.NETWORK_TYPE_IWLAN,
Etan Cohena00c9192014-12-23 15:02:29 -0800434 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800435 : ImsConfig.FeatureValueConstants.OFF,
436 imsManager.mImsConfigListener);
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800437
438 if (enabled) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700439 log("setWfcSetting() : turnOnIms");
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800440 imsManager.turnOnIms();
Meng Wang9352c432016-06-08 14:22:20 -0700441 } else if (isTurnOffImsAllowedByPlatform(context)
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800442 && (!isVolteEnabledByPlatform(context)
443 || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
444 log("setWfcSetting() : imsServiceAllowTurnOff -> turnOffIms");
445 imsManager.turnOffIms();
446 }
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700447
448 // Force IMS to register over LTE when turning off WFC
449 setWfcModeInternal(context, enabled
450 ? getWfcMode(context)
451 : ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED);
Etan Cohena00c9192014-12-23 15:02:29 -0800452 } catch (ImsException e) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700453 loge("setWfcSetting(): ", e);
Etan Cohena00c9192014-12-23 15:02:29 -0800454 }
455 }
456 }
457
458 /**
459 * Returns the user configuration of WFC modem setting
460 */
461 public static int getWfcMode(Context context) {
462 int setting = android.provider.Settings.Global.getInt(context.getContentResolver(),
fionaxu5803ef02016-03-08 11:48:48 -0800463 android.provider.Settings.Global.WFC_IMS_MODE, getIntCarrierConfig(context,
464 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
Etan Cohena00c9192014-12-23 15:02:29 -0800465 if (DBG) log("getWfcMode - setting=" + setting);
466 return setting;
467 }
468
469 /**
470 * Returns the user configuration of WFC modem setting
471 */
472 public static void setWfcMode(Context context, int wfcMode) {
473 if (DBG) log("setWfcMode - setting=" + wfcMode);
474 android.provider.Settings.Global.putInt(context.getContentResolver(),
475 android.provider.Settings.Global.WFC_IMS_MODE, wfcMode);
476
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700477 setWfcModeInternal(context, wfcMode);
478 }
479
480 private static void setWfcModeInternal(Context context, int wfcMode) {
Etan Cohena00c9192014-12-23 15:02:29 -0800481 final ImsManager imsManager = ImsManager.getInstance(context,
482 SubscriptionManager.getDefaultVoicePhoneId());
483 if (imsManager != null) {
484 final int value = wfcMode;
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700485 Thread thread = new Thread(new Runnable() {
Etan Cohena00c9192014-12-23 15:02:29 -0800486 public void run() {
487 try {
488 imsManager.getConfigInterface().setProvisionedValue(
489 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE,
490 value);
491 } catch (ImsException e) {
492 // do nothing
493 }
494 }
495 });
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700496 thread.start();
Etan Cohena00c9192014-12-23 15:02:29 -0800497 }
498 }
499
500 /**
501 * Returns the user configuration of WFC roaming setting
502 */
503 public static boolean isWfcRoamingEnabledByUser(Context context) {
504 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
505 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -0800506 getBooleanCarrierConfig(context,
507 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ?
508 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800509 return (enabled == 1) ? true : false;
510 }
511
512 /**
513 * Change persistent WFC roaming enabled setting
514 */
515 public static void setWfcRoamingSetting(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800516 android.provider.Settings.Global.putInt(context.getContentResolver(),
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700517 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -0800518 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700519 : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800520
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700521 setWfcRoamingSettingInternal(context, enabled);
522 }
523
524 private static void setWfcRoamingSettingInternal(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800525 final ImsManager imsManager = ImsManager.getInstance(context,
526 SubscriptionManager.getDefaultVoicePhoneId());
527 if (imsManager != null) {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700528 final int value = enabled
529 ? ImsConfig.FeatureValueConstants.ON
530 : ImsConfig.FeatureValueConstants.OFF;
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700531 Thread thread = new Thread(new Runnable() {
Etan Cohena00c9192014-12-23 15:02:29 -0800532 public void run() {
533 try {
534 imsManager.getConfigInterface().setProvisionedValue(
535 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_ROAMING,
536 value);
537 } catch (ImsException e) {
538 // do nothing
539 }
540 }
541 });
Pavel Zhamaitsiak47aeacf2016-03-30 18:54:55 -0700542 thread.start();
Etan Cohena00c9192014-12-23 15:02:29 -0800543 }
544 }
545
546 /**
547 * Returns a platform configuration for WFC which may override the user
548 * setting. Note: WFC presumes that VoLTE is enabled (these are
549 * configuration settings which must be done correctly).
550 */
551 public static boolean isWfcEnabledByPlatform(Context context) {
552 if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE,
553 PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT) == 1) {
554 return true;
555 }
556
557 return
558 context.getResources().getBoolean(
559 com.android.internal.R.bool.config_device_wfc_ims_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700560 getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700561 CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) &&
562 isGbaValid(context);
563 }
564
565 /**
566 * If carrier requires that IMS is only available if GBA capable SIM is used,
567 * then this function checks GBA bit in EF IST.
568 *
569 * Format of EF IST is defined in 3GPP TS 31.103 (Section 4.2.7).
570 */
571 private static boolean isGbaValid(Context context) {
572 if (getBooleanCarrierConfig(context,
573 CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) {
574 final TelephonyManager telephonyManager = TelephonyManager.getDefault();
575 String efIst = telephonyManager.getIsimIst();
576 if (efIst == null) {
577 loge("ISF is NULL");
578 return true;
579 }
580 boolean result = efIst != null && efIst.length() > 1 &&
581 (0x02 & (byte)efIst.charAt(1)) != 0;
582 if (DBG) log("GBA capable=" + result + ", ISF=" + efIst);
583 return result;
584 }
585 return true;
Etan Cohena00c9192014-12-23 15:02:29 -0800586 }
587
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700588 /**
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700589 * This function should be called when ImsConfig.ACTION_IMS_CONFIG_CHANGED is received.
590 *
591 * We cannot register receiver in ImsManager because this would lead to resource leak.
592 * ImsManager can be created in different processes and it is not notified when that process
593 * is about to be terminated.
594 *
595 * @hide
596 * */
597 public static void onProvisionedValueChanged(Context context, int item, String value) {
Amit Mahajan24f7b162016-07-21 16:33:53 -0700598 if (DBG) Rlog.d(TAG, "onProvisionedValueChanged: item=" + item + " val=" + value);
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700599 ImsManager mgr = ImsManager.getInstance(context,
600 SubscriptionManager.getDefaultVoicePhoneId());
601
602 switch (item) {
603 case ImsConfig.ConfigConstants.VLT_SETTING_ENABLED:
Amit Mahajan24f7b162016-07-21 16:33:53 -0700604 mgr.setVolteProvisionedProperty(value.equals("1"));
605 if (DBG) Rlog.d(TAG,"isVoLteProvisioned = " + mgr.isVolteProvisioned());
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700606 break;
607
608 case ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED:
Amit Mahajan24f7b162016-07-21 16:33:53 -0700609 mgr.setWfcProvisionedProperty(value.equals("1"));
610 if (DBG) Rlog.d(TAG,"isWfcProvisioned = " + mgr.isWfcProvisioned());
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700611 break;
612
Nathan Harolda9fc7f12016-06-30 16:12:14 -0700613 case ImsConfig.ConfigConstants.LVC_SETTING_ENABLED:
Amit Mahajan24f7b162016-07-21 16:33:53 -0700614 mgr.setVtProvisionedProperty(value.equals("1"));
615 if (DBG) Rlog.d(TAG,"isVtProvisioned = " + mgr.isVtProvisioned());
Nathan Harolda9fc7f12016-06-30 16:12:14 -0700616 break;
617
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700618 }
619 }
620
621 private class AsyncUpdateProvisionedValues extends AsyncTask<Void, Void, Void> {
622 @Override
623 protected Void doInBackground(Void... params) {
624 // disable on any error
Amit Mahajan24f7b162016-07-21 16:33:53 -0700625 setVolteProvisionedProperty(false);
626 setWfcProvisionedProperty(false);
627 setVtProvisionedProperty(false);
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700628
629 try {
630 ImsConfig config = getConfigInterface();
631 if (config != null) {
Amit Mahajan24f7b162016-07-21 16:33:53 -0700632 setVolteProvisionedProperty(getProvisionedBool(config,
633 ImsConfig.ConfigConstants.VLT_SETTING_ENABLED));
634 if (DBG) Rlog.d(TAG, "isVoLteProvisioned = " + isVolteProvisioned());
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700635
Amit Mahajan24f7b162016-07-21 16:33:53 -0700636 setWfcProvisionedProperty(getProvisionedBool(config,
637 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED));
638 if (DBG) Rlog.d(TAG, "isWfcProvisioned = " + isWfcProvisioned());
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700639
Amit Mahajan24f7b162016-07-21 16:33:53 -0700640 setVtProvisionedProperty(getProvisionedBool(config,
641 ImsConfig.ConfigConstants.LVC_SETTING_ENABLED));
642 if (DBG) Rlog.d(TAG, "isVtProvisioned = " + isVtProvisioned());
Nathan Harolda9fc7f12016-06-30 16:12:14 -0700643
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700644 }
645 } catch (ImsException ie) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700646 Rlog.e(TAG, "AsyncUpdateProvisionedValues error: ", ie);
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700647 }
648
649 return null;
650 }
651
652 private boolean getProvisionedBool(ImsConfig config, int item) throws ImsException {
653 return config.getProvisionedValue(item) == ImsConfig.FeatureValueConstants.ON;
654 }
655 }
656
657 /** Asynchronously get VoLTE, WFC, VT provisioning statuses */
658 private void updateProvisionedValues() {
659 if (getBooleanCarrierConfig(mContext,
660 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
661
662 new AsyncUpdateProvisionedValues().execute();
663 }
664 }
665
666 /**
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700667 * Sync carrier config and user settings with ImsConfig.
668 *
669 * @param context for the manager object
670 * @param phoneId phone id
671 * @param force update
672 */
673 public static void updateImsServiceConfig(Context context, int phoneId, boolean force) {
Pavel Zhamaitsiakfc202992016-03-29 18:07:38 -0700674 if (!force) {
675 if (TelephonyManager.getDefault().getSimState() != TelephonyManager.SIM_STATE_READY) {
676 log("updateImsServiceConfig: SIM not ready");
677 // Don't disable IMS if SIM is not ready
678 return;
679 }
680 }
681
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700682 final ImsManager imsManager = ImsManager.getInstance(context, phoneId);
683 if (imsManager != null && (!imsManager.mConfigUpdated || force)) {
684 try {
Pavel Zhamaitsiak002b2042016-06-03 16:05:31 -0700685 imsManager.updateProvisionedValues();
686
Pavel Zhamaitsiakd46779c2016-06-03 10:39:51 -0700687 // TODO: Extend ImsConfig API and set all feature values in single function call.
688
689 // Note: currently the order of updates is set to produce different order of
690 // setFeatureValue() function calls from setAdvanced4GMode(). This is done to
691 // differentiate this code path from vendor code perspective.
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800692 boolean isImsUsed = imsManager.updateVolteFeatureValue();
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800693 isImsUsed |= imsManager.updateWfcFeatureAndProvisionedValues();
Pavel Zhamaitsiakd46779c2016-06-03 10:39:51 -0700694 isImsUsed |= imsManager.updateVideoCallFeatureValue();
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700695
Meng Wang9352c432016-06-08 14:22:20 -0700696 if (isImsUsed || !isTurnOffImsAllowedByPlatform(context)) {
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800697 // Turn on IMS if it is used.
698 // Also, if turning off is not allowed for current carrier,
699 // we need to turn IMS on because it might be turned off before
700 // phone switched to current carrier.
Meng Wangca7d4c42016-06-30 22:05:24 -0700701 log("updateImsServiceConfig: turnOnIms");
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700702 imsManager.turnOnIms();
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800703 } else {
704 // Turn off IMS if it is not used AND turning off is allowed for carrier.
Meng Wangca7d4c42016-06-30 22:05:24 -0700705 log("updateImsServiceConfig: turnOffIms");
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700706 imsManager.turnOffIms();
707 }
708
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700709 imsManager.mConfigUpdated = true;
710 } catch (ImsException e) {
Meng Wangca7d4c42016-06-30 22:05:24 -0700711 loge("updateImsServiceConfig: ", e);
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700712 imsManager.mConfigUpdated = false;
713 }
714 }
715 }
716
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700717 /**
718 * Update VoLTE config
719 * @return whether feature is On
720 * @throws ImsException
721 */
722 private boolean updateVolteFeatureValue() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700723 boolean available = isVolteEnabledByPlatform(mContext);
724 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext);
725 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800726 boolean isFeatureOn = available && enabled && isNonTty;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700727
728 log("updateVolteFeatureValue: available = " + available
729 + ", enabled = " + enabled
730 + ", nonTTY = " + isNonTty);
731
732 getConfigInterface().setFeatureValue(
733 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
734 TelephonyManager.NETWORK_TYPE_LTE,
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800735 isFeatureOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700736 ImsConfig.FeatureValueConstants.ON :
737 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800738 mImsConfigListener);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700739
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800740 return isFeatureOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700741 }
742
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700743 /**
Jack Yu643ffe42016-07-08 14:25:46 -0700744 * Update video call over LTE config
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700745 * @return whether feature is On
746 * @throws ImsException
747 */
748 private boolean updateVideoCallFeatureValue() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700749 boolean available = isVtEnabledByPlatform(mContext);
Tyler Gunnfb4abdf2016-08-01 11:14:46 -0700750 boolean enabled = isVtEnabledByUser(mContext);
Omkar Kolangadec0f450d2016-02-11 20:59:48 +0530751 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
Amit Mahajan24f7b162016-07-21 16:33:53 -0700752 boolean isDataEnabled = isDataEnabled();
Jack Yu643ffe42016-07-08 14:25:46 -0700753
Amit Mahajan24f7b162016-07-21 16:33:53 -0700754 boolean isFeatureOn = available && enabled && isNonTty && isDataEnabled;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700755
756 log("updateVideoCallFeatureValue: available = " + available
757 + ", enabled = " + enabled
Jack Yu643ffe42016-07-08 14:25:46 -0700758 + ", nonTTY = " + isNonTty
Amit Mahajan24f7b162016-07-21 16:33:53 -0700759 + ", data enabled = " + isDataEnabled);
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700760
761 getConfigInterface().setFeatureValue(
762 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
763 TelephonyManager.NETWORK_TYPE_LTE,
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800764 isFeatureOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700765 ImsConfig.FeatureValueConstants.ON :
766 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800767 mImsConfigListener);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700768
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800769 return isFeatureOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700770 }
771
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700772 /**
773 * Update WFC config
774 * @return whether feature is On
775 * @throws ImsException
776 */
777 private boolean updateWfcFeatureAndProvisionedValues() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700778 boolean available = isWfcEnabledByPlatform(mContext);
779 boolean enabled = isWfcEnabledByUser(mContext);
780 int mode = getWfcMode(mContext);
781 boolean roaming = isWfcRoamingEnabledByUser(mContext);
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800782 boolean isFeatureOn = available && enabled;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700783
784 log("updateWfcFeatureAndProvisionedValues: available = " + available
785 + ", enabled = " + enabled
786 + ", mode = " + mode
787 + ", roaming = " + roaming);
788
789 getConfigInterface().setFeatureValue(
Pavel Zhamaitsiake6f99432015-09-11 10:29:30 -0700790 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
791 TelephonyManager.NETWORK_TYPE_IWLAN,
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800792 isFeatureOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700793 ImsConfig.FeatureValueConstants.ON :
794 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800795 mImsConfigListener);
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700796
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800797 if (!isFeatureOn) {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700798 mode = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED;
799 roaming = false;
800 }
801 setWfcModeInternal(mContext, mode);
802 setWfcRoamingSettingInternal(mContext, roaming);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700803
Pavel Zhamaitsiak9510b1c2015-12-18 11:30:49 -0800804 return isFeatureOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700805 }
806
Etan Cohenabbd7882014-09-26 22:35:35 -0700807 private ImsManager(Context context, int phoneId) {
Wink Savilleef36ef62014-06-11 08:39:38 -0700808 mContext = context;
Etan Cohenabbd7882014-09-26 22:35:35 -0700809 mPhoneId = phoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700810 createImsService(true);
811 }
812
Etan Cohenf4311122015-02-26 17:47:13 -0800813 /*
814 * Returns a flag indicating whether the IMS service is available.
815 */
816 public boolean isServiceAvailable() {
817 if (mImsService != null) {
818 return true;
819 }
820
821 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
822 if (binder != null) {
823 return true;
824 }
825
826 return false;
827 }
828
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800829 public void setImsConfigListener(ImsConfigListener listener) {
830 mImsConfigListener = listener;
831 }
832
Wink Savilleef36ef62014-06-11 08:39:38 -0700833 /**
834 * Opens the IMS service for making calls and/or receiving generic IMS calls.
835 * The caller may make subsquent calls through {@link #makeCall}.
836 * The IMS service will register the device to the operator's network with the credentials
837 * (from ISIM) periodically in order to receive calls from the operator's network.
838 * When the IMS service receives a new call, it will send out an intent with
839 * the provided action string.
840 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call.
841 *
842 * @param serviceClass a service class specified in {@link ImsServiceClass}
843 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
844 * @param incomingCallPendingIntent When an incoming call is received,
845 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to
846 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE}
847 * as the result code and the intent to fill in the call ID; It cannot be null
848 * @param listener To listen to IMS registration events; It cannot be null
849 * @return identifier (greater than 0) for the specified service
850 * @throws NullPointerException if {@code incomingCallPendingIntent}
851 * or {@code listener} is null
852 * @throws ImsException if calling the IMS service results in an error
853 * @see #getCallId
854 * @see #getServiceId
855 */
856 public int open(int serviceClass, PendingIntent incomingCallPendingIntent,
857 ImsConnectionStateListener listener) throws ImsException {
858 checkAndThrowExceptionIfServiceUnavailable();
859
860 if (incomingCallPendingIntent == null) {
861 throw new NullPointerException("incomingCallPendingIntent can't be null");
862 }
863
864 if (listener == null) {
865 throw new NullPointerException("listener can't be null");
866 }
867
868 int result = 0;
869
870 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700871 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent,
Wink Savilleef36ef62014-06-11 08:39:38 -0700872 createRegistrationListenerProxy(serviceClass, listener));
873 } catch (RemoteException e) {
874 throw new ImsException("open()", e,
875 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
876 }
877
878 if (result <= 0) {
879 // If the return value is a minus value,
880 // it means that an error occurred in the service.
881 // So, it needs to convert to the reason code specified in ImsReasonInfo.
882 throw new ImsException("open()", (result * (-1)));
883 }
884
885 return result;
886 }
887
888 /**
Pavel Zhamaitsiakce410172016-04-15 10:55:56 -0700889 * Adds registration listener to the IMS service.
890 *
891 * @param serviceClass a service class specified in {@link ImsServiceClass}
892 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
893 * @param listener To listen to IMS registration events; It cannot be null
894 * @throws NullPointerException if {@code listener} is null
895 * @throws ImsException if calling the IMS service results in an error
896 */
897 public void addRegistrationListener(int serviceClass, ImsConnectionStateListener listener)
898 throws ImsException {
899 checkAndThrowExceptionIfServiceUnavailable();
900
901 if (listener == null) {
902 throw new NullPointerException("listener can't be null");
903 }
904
905 try {
906 mImsService.addRegistrationListener(mPhoneId, serviceClass,
907 createRegistrationListenerProxy(serviceClass, listener));
908 } catch (RemoteException e) {
909 throw new ImsException("addRegistrationListener()", e,
910 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
911 }
912 }
913
914 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700915 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls.
916 * All the resources that were allocated to the service are also released.
917 *
918 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open}
919 * @throws ImsException if calling the IMS service results in an error
920 */
921 public void close(int serviceId) throws ImsException {
922 checkAndThrowExceptionIfServiceUnavailable();
923
924 try {
925 mImsService.close(serviceId);
926 } catch (RemoteException e) {
927 throw new ImsException("close()", e,
928 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
929 } finally {
930 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500931 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700932 mEcbm = null;
Tyler Gunn4d128b62016-04-13 15:44:38 -0700933 mMultiEndpoint = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700934 }
935 }
936
937 /**
938 * Gets the configuration interface to provision / withdraw the supplementary service settings.
939 *
940 * @param serviceId a service id which is obtained from {@link ImsManager#open}
941 * @return the Ut interface instance
942 * @throws ImsException if getting the Ut interface results in an error
943 */
944 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId)
945 throws ImsException {
946 // FIXME: manage the multiple Ut interfaces based on the service id
947 if (mUt == null) {
948 checkAndThrowExceptionIfServiceUnavailable();
949
950 try {
951 IImsUt iUt = mImsService.getUtInterface(serviceId);
952
953 if (iUt == null) {
954 throw new ImsException("getSupplementaryServiceConfiguration()",
955 ImsReasonInfo.CODE_UT_NOT_SUPPORTED);
956 }
957
958 mUt = new ImsUt(iUt);
959 } catch (RemoteException e) {
960 throw new ImsException("getSupplementaryServiceConfiguration()", e,
961 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
962 }
963 }
964
965 return mUt;
966 }
967
968 /**
969 * Checks if the IMS service has successfully registered to the IMS network
970 * with the specified service & call type.
971 *
972 * @param serviceId a service id which is obtained from {@link ImsManager#open}
973 * @param serviceType a service type that is specified in {@link ImsCallProfile}
974 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
975 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
976 * @param callType a call type that is specified in {@link ImsCallProfile}
977 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
978 * {@link ImsCallProfile#CALL_TYPE_VOICE}
979 * {@link ImsCallProfile#CALL_TYPE_VT}
980 * {@link ImsCallProfile#CALL_TYPE_VS}
981 * @return true if the specified service id is connected to the IMS network;
982 * false otherwise
983 * @throws ImsException if calling the IMS service results in an error
984 */
985 public boolean isConnected(int serviceId, int serviceType, int callType)
986 throws ImsException {
987 checkAndThrowExceptionIfServiceUnavailable();
988
989 try {
990 return mImsService.isConnected(serviceId, serviceType, callType);
991 } catch (RemoteException e) {
992 throw new ImsException("isServiceConnected()", e,
993 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
994 }
995 }
996
997 /**
998 * Checks if the specified IMS service is opend.
999 *
1000 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1001 * @return true if the specified service id is opened; false otherwise
1002 * @throws ImsException if calling the IMS service results in an error
1003 */
1004 public boolean isOpened(int serviceId) throws ImsException {
1005 checkAndThrowExceptionIfServiceUnavailable();
1006
1007 try {
1008 return mImsService.isOpened(serviceId);
1009 } catch (RemoteException e) {
1010 throw new ImsException("isOpened()", e,
1011 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1012 }
1013 }
1014
1015 /**
1016 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
1017 *
1018 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1019 * @param serviceType a service type that is specified in {@link ImsCallProfile}
1020 * {@link ImsCallProfile#SERVICE_TYPE_NONE}
1021 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
1022 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
1023 * @param callType a call type that is specified in {@link ImsCallProfile}
1024 * {@link ImsCallProfile#CALL_TYPE_VOICE}
1025 * {@link ImsCallProfile#CALL_TYPE_VT}
1026 * {@link ImsCallProfile#CALL_TYPE_VT_TX}
1027 * {@link ImsCallProfile#CALL_TYPE_VT_RX}
1028 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
1029 * {@link ImsCallProfile#CALL_TYPE_VS}
1030 * {@link ImsCallProfile#CALL_TYPE_VS_TX}
1031 * {@link ImsCallProfile#CALL_TYPE_VS_RX}
1032 * @return a {@link ImsCallProfile} object
1033 * @throws ImsException if calling the IMS service results in an error
1034 */
1035 public ImsCallProfile createCallProfile(int serviceId,
1036 int serviceType, int callType) throws ImsException {
1037 checkAndThrowExceptionIfServiceUnavailable();
1038
1039 try {
1040 return mImsService.createCallProfile(serviceId, serviceType, callType);
1041 } catch (RemoteException e) {
1042 throw new ImsException("createCallProfile()", e,
1043 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1044 }
1045 }
1046
1047 /**
1048 * Creates a {@link ImsCall} to make a call.
1049 *
1050 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1051 * @param profile a call profile to make the call
1052 * (it contains service type, call type, media information, etc.)
1053 * @param participants participants to invite the conference call
1054 * @param listener listen to the call events from {@link ImsCall}
1055 * @return a {@link ImsCall} object
1056 * @throws ImsException if calling the IMS service results in an error
1057 */
1058 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees,
1059 ImsCall.Listener listener) throws ImsException {
1060 if (DBG) {
1061 log("makeCall :: serviceId=" + serviceId
fionaxu7b3107c2016-07-06 14:04:06 -07001062 + ", profile=" + profile);
Wink Savilleef36ef62014-06-11 08:39:38 -07001063 }
1064
1065 checkAndThrowExceptionIfServiceUnavailable();
1066
1067 ImsCall call = new ImsCall(mContext, profile);
1068
1069 call.setListener(listener);
1070 ImsCallSession session = createCallSession(serviceId, profile);
1071
1072 if ((callees != null) && (callees.length == 1)) {
1073 call.start(session, callees[0]);
1074 } else {
1075 call.start(session, callees);
1076 }
1077
1078 return call;
1079 }
1080
1081 /**
1082 * Creates a {@link ImsCall} to take an incoming call.
1083 *
1084 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1085 * @param incomingCallIntent the incoming call broadcast intent
1086 * @param listener to listen to the call events from {@link ImsCall}
1087 * @return a {@link ImsCall} object
1088 * @throws ImsException if calling the IMS service results in an error
1089 */
1090 public ImsCall takeCall(int serviceId, Intent incomingCallIntent,
1091 ImsCall.Listener listener) throws ImsException {
1092 if (DBG) {
1093 log("takeCall :: serviceId=" + serviceId
1094 + ", incomingCall=" + incomingCallIntent);
1095 }
1096
1097 checkAndThrowExceptionIfServiceUnavailable();
1098
1099 if (incomingCallIntent == null) {
1100 throw new ImsException("Can't retrieve session with null intent",
1101 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
1102 }
1103
1104 int incomingServiceId = getServiceId(incomingCallIntent);
1105
1106 if (serviceId != incomingServiceId) {
1107 throw new ImsException("Service id is mismatched in the incoming call intent",
1108 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
1109 }
1110
1111 String callId = getCallId(incomingCallIntent);
1112
1113 if (callId == null) {
1114 throw new ImsException("Call ID missing in the incoming call intent",
1115 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
1116 }
1117
1118 try {
1119 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId);
1120
1121 if (session == null) {
1122 throw new ImsException("No pending session for the call",
1123 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL);
1124 }
1125
1126 ImsCall call = new ImsCall(mContext, session.getCallProfile());
1127
1128 call.attachSession(new ImsCallSession(session));
1129 call.setListener(listener);
1130
1131 return call;
1132 } catch (Throwable t) {
1133 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED);
1134 }
1135 }
1136
1137 /**
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001138 * Gets the config interface to get/set service/capability parameters.
1139 *
1140 * @return the ImsConfig instance.
1141 * @throws ImsException if getting the setting interface results in an error.
1142 */
1143 public ImsConfig getConfigInterface() throws ImsException {
1144
1145 if (mConfig == null) {
1146 checkAndThrowExceptionIfServiceUnavailable();
1147
1148 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001149 IImsConfig config = mImsService.getConfigInterface(mPhoneId);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001150 if (config == null) {
1151 throw new ImsException("getConfigInterface()",
1152 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
1153 }
Libin.Tang@motorola.com54953c72014-08-07 15:02:08 -05001154 mConfig = new ImsConfig(config, mContext);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001155 } catch (RemoteException e) {
1156 throw new ImsException("getConfigInterface()", e,
1157 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1158 }
1159 }
1160 if (DBG) log("getConfigInterface(), mConfig= " + mConfig);
1161 return mConfig;
1162 }
1163
Etan Cohen82f78122014-12-15 10:10:14 -08001164 public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete)
Shriram Ganeshc403b7b2014-08-14 14:18:57 +05301165 throws ImsException {
1166
Etan Cohen82f78122014-12-15 10:10:14 -08001167 checkAndThrowExceptionIfServiceUnavailable();
Shriram Ganeshc403b7b2014-08-14 14:18:57 +05301168
Etan Cohen82f78122014-12-15 10:10:14 -08001169 try {
1170 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete);
1171 } catch (RemoteException e) {
1172 throw new ImsException("setTTYMode()", e,
1173 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1174 }
1175
Junda Liue7663c02015-06-23 11:16:26 -07001176 if (!getBooleanCarrierConfig(context,
1177 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -08001178 setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) &&
1179 isEnhanced4gLteModeSettingEnabledByUser(context));
1180 }
Shriram Ganeshc403b7b2014-08-14 14:18:57 +05301181 }
1182
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001183 /**
Junda Liue7663c02015-06-23 11:16:26 -07001184 * Get the boolean config from carrier config manager.
1185 *
1186 * @param context the context to get carrier service
1187 * @param key config key defined in CarrierConfigManager
1188 * @return boolean value of corresponding key.
1189 */
1190 private static boolean getBooleanCarrierConfig(Context context, String key) {
1191 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
1192 Context.CARRIER_CONFIG_SERVICE);
Jonathan Basseri2acea6f2015-07-01 15:00:38 -07001193 PersistableBundle b = null;
Junda Liue7663c02015-06-23 11:16:26 -07001194 if (configManager != null) {
Jonathan Basseri2acea6f2015-07-01 15:00:38 -07001195 b = configManager.getConfig();
1196 }
1197 if (b != null) {
1198 return b.getBoolean(key);
Junda Liue7663c02015-06-23 11:16:26 -07001199 } else {
1200 // Return static default defined in CarrierConfigManager.
1201 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
1202 }
1203 }
1204
1205 /**
fionaxu5803ef02016-03-08 11:48:48 -08001206 * Get the int config from carrier config manager.
1207 *
1208 * @param context the context to get carrier service
1209 * @param key config key defined in CarrierConfigManager
1210 * @return integer value of corresponding key.
1211 */
1212 private static int getIntCarrierConfig(Context context, String key) {
1213 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
1214 Context.CARRIER_CONFIG_SERVICE);
1215 PersistableBundle b = null;
1216 if (configManager != null) {
1217 b = configManager.getConfig();
1218 }
1219 if (b != null) {
1220 return b.getInt(key);
1221 } else {
1222 // Return static default defined in CarrierConfigManager.
1223 return CarrierConfigManager.getDefaultConfig().getInt(key);
1224 }
1225 }
1226
1227 /**
Wink Savilleef36ef62014-06-11 08:39:38 -07001228 * Gets the call ID from the specified incoming call broadcast intent.
1229 *
1230 * @param incomingCallIntent the incoming call broadcast intent
1231 * @return the call ID or null if the intent does not contain it
1232 */
1233 private static String getCallId(Intent incomingCallIntent) {
1234 if (incomingCallIntent == null) {
1235 return null;
1236 }
1237
1238 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
1239 }
1240
1241 /**
1242 * Gets the service type from the specified incoming call broadcast intent.
1243 *
1244 * @param incomingCallIntent the incoming call broadcast intent
1245 * @return the service identifier or -1 if the intent does not contain it
1246 */
1247 private static int getServiceId(Intent incomingCallIntent) {
1248 if (incomingCallIntent == null) {
1249 return (-1);
1250 }
1251
1252 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1);
1253 }
1254
1255 /**
1256 * Binds the IMS service only if the service is not created.
1257 */
1258 private void checkAndThrowExceptionIfServiceUnavailable()
1259 throws ImsException {
1260 if (mImsService == null) {
1261 createImsService(true);
1262
1263 if (mImsService == null) {
1264 throw new ImsException("Service is unavailable",
1265 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1266 }
1267 }
1268 }
1269
Etan Cohenabbd7882014-09-26 22:35:35 -07001270 private static String getImsServiceName(int phoneId) {
1271 // TODO: MSIM implementation needs to decide on service name as a function of phoneId
Etan Cohend7727462014-07-12 14:54:10 -07001272 return IMS_SERVICE;
1273 }
1274
Wink Savilleef36ef62014-06-11 08:39:38 -07001275 /**
1276 * Binds the IMS service to make/receive the call.
1277 */
1278 private void createImsService(boolean checkService) {
1279 if (checkService) {
Etan Cohenabbd7882014-09-26 22:35:35 -07001280 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -07001281
1282 if (binder == null) {
1283 return;
1284 }
1285 }
1286
Etan Cohenabbd7882014-09-26 22:35:35 -07001287 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -07001288
1289 if (b != null) {
1290 try {
1291 b.linkToDeath(mDeathRecipient, 0);
1292 } catch (RemoteException e) {
1293 }
1294 }
1295
1296 mImsService = IImsService.Stub.asInterface(b);
1297 }
1298
1299 /**
1300 * Creates a {@link ImsCallSession} with the specified call profile.
1301 * Use other methods, if applicable, instead of interacting with
1302 * {@link ImsCallSession} directly.
1303 *
1304 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1305 * @param profile a call profile to make the call
1306 */
1307 private ImsCallSession createCallSession(int serviceId,
1308 ImsCallProfile profile) throws ImsException {
1309 try {
1310 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null));
1311 } catch (RemoteException e) {
1312 return null;
1313 }
1314 }
1315
1316 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass,
1317 ImsConnectionStateListener listener) {
1318 ImsRegistrationListenerProxy proxy =
1319 new ImsRegistrationListenerProxy(serviceClass, listener);
1320 return proxy;
1321 }
1322
Etan Cohena00c9192014-12-23 15:02:29 -08001323 private static void log(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001324 Rlog.d(TAG, s);
1325 }
1326
Etan Cohena00c9192014-12-23 15:02:29 -08001327 private static void loge(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001328 Rlog.e(TAG, s);
1329 }
1330
Etan Cohena00c9192014-12-23 15:02:29 -08001331 private static void loge(String s, Throwable t) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001332 Rlog.e(TAG, s, t);
1333 }
1334
1335 /**
ram7da5a112014-07-16 20:59:27 +05301336 * Used for turning on IMS.if its off already
1337 */
Etan Cohen82f78122014-12-15 10:10:14 -08001338 private void turnOnIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001339 checkAndThrowExceptionIfServiceUnavailable();
1340
ram7da5a112014-07-16 20:59:27 +05301341 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001342 mImsService.turnOnIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301343 } catch (RemoteException e) {
1344 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1345 }
1346 }
1347
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001348 private boolean isImsTurnOffAllowed() {
Meng Wang9352c432016-06-08 14:22:20 -07001349 return isTurnOffImsAllowedByPlatform(mContext)
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001350 && (!isWfcEnabledByPlatform(mContext)
1351 || !isWfcEnabledByUser(mContext));
1352 }
1353
Amit Mahajan9cba36d2016-08-11 10:17:23 -07001354 private void setLteFeatureValues(boolean turnOn) {
1355 log("setLteFeatureValues: " + turnOn);
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001356 try {
1357 ImsConfig config = getConfigInterface();
Amit Mahajan9cba36d2016-08-11 10:17:23 -07001358 if (config != null) {
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001359 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -08001360 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, mImsConfigListener);
Pavel Zhamaitsiakff29b9d2016-04-15 12:16:57 -07001361
1362 if (isVtEnabledByPlatform(mContext)) {
Jack Yu643ffe42016-07-08 14:25:46 -07001363 boolean enableViLte = turnOn && isVtEnabledByUser(mContext) &&
Amit Mahajan24f7b162016-07-21 16:33:53 -07001364 isDataEnabled();
Pavel Zhamaitsiakff29b9d2016-04-15 12:16:57 -07001365 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
1366 TelephonyManager.NETWORK_TYPE_LTE,
1367 enableViLte ? 1 : 0,
1368 mImsConfigListener);
1369 }
Etan Cohenb651fa52014-10-22 10:51:29 -07001370 }
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001371 } catch (ImsException e) {
Amit Mahajan9cba36d2016-08-11 10:17:23 -07001372 loge("setLteFeatureValues: exception ", e);
Etan Cohencfc784d2014-08-07 18:40:31 -07001373 }
Amit Mahajan9cba36d2016-08-11 10:17:23 -07001374 }
1375
1376 private void setAdvanced4GMode(boolean turnOn) throws ImsException {
1377 checkAndThrowExceptionIfServiceUnavailable();
1378
1379 // if turnOn: first set feature values then call turnOnIms()
1380 // if turnOff: only set feature values if IMS turn off is not allowed. If turn off is
1381 // allowed, first call turnOffIms() then set feature values
Etan Cohencfc784d2014-08-07 18:40:31 -07001382 if (turnOn) {
Amit Mahajan9cba36d2016-08-11 10:17:23 -07001383 setLteFeatureValues(turnOn);
1384 log("setAdvanced4GMode: turnOnIms");
Etan Cohencfc784d2014-08-07 18:40:31 -07001385 turnOnIms();
Amit Mahajan9cba36d2016-08-11 10:17:23 -07001386 } else {
1387 if (isImsTurnOffAllowed()) {
1388 log("setAdvanced4GMode: turnOffIms");
1389 turnOffIms();
1390 }
1391 setLteFeatureValues(turnOn);
Etan Cohencfc784d2014-08-07 18:40:31 -07001392 }
1393 }
1394
ram7da5a112014-07-16 20:59:27 +05301395 /**
1396 * Used for turning off IMS completely in order to make the device CSFB'ed.
1397 * Once turned off, all calls will be over CS.
1398 */
Etan Cohen82f78122014-12-15 10:10:14 -08001399 private void turnOffIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001400 checkAndThrowExceptionIfServiceUnavailable();
1401
ram7da5a112014-07-16 20:59:27 +05301402 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001403 mImsService.turnOffIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301404 } catch (RemoteException e) {
1405 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1406 }
1407 }
1408
1409 /**
Wink Savilleef36ef62014-06-11 08:39:38 -07001410 * Death recipient class for monitoring IMS service.
1411 */
1412 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient {
1413 @Override
1414 public void binderDied() {
1415 mImsService = null;
1416 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001417 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001418 mEcbm = null;
Tyler Gunn4d128b62016-04-13 15:44:38 -07001419 mMultiEndpoint = null;
Wink Savilleef36ef62014-06-11 08:39:38 -07001420
1421 if (mContext != null) {
Etan Cohend7727462014-07-12 14:54:10 -07001422 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN);
Etan Cohenabbd7882014-09-26 22:35:35 -07001423 intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
Etan Cohend7727462014-07-12 14:54:10 -07001424 mContext.sendBroadcast(new Intent(intent));
Wink Savilleef36ef62014-06-11 08:39:38 -07001425 }
1426 }
1427 }
1428
1429 /**
1430 * Adapter class for {@link IImsRegistrationListener}.
1431 */
1432 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub {
1433 private int mServiceClass;
1434 private ImsConnectionStateListener mListener;
1435
1436 public ImsRegistrationListenerProxy(int serviceClass,
1437 ImsConnectionStateListener listener) {
1438 mServiceClass = serviceClass;
1439 mListener = listener;
1440 }
1441
1442 public boolean isSameProxy(int serviceClass) {
1443 return (mServiceClass == serviceClass);
1444 }
1445
Omkar Kolangadea7ced642015-05-04 17:55:13 -07001446 @Deprecated
Wink Savilleef36ef62014-06-11 08:39:38 -07001447 public void registrationConnected() {
1448 if (DBG) {
1449 log("registrationConnected ::");
1450 }
1451
1452 if (mListener != null) {
1453 mListener.onImsConnected();
1454 }
1455 }
1456
Omkar Kolangadea7ced642015-05-04 17:55:13 -07001457 @Deprecated
Rekha Kumar14631742015-02-04 10:47:00 -08001458 public void registrationProgressing() {
Wink Savilleef36ef62014-06-11 08:39:38 -07001459 if (DBG) {
Rekha Kumar14631742015-02-04 10:47:00 -08001460 log("registrationProgressing ::");
Wink Savilleef36ef62014-06-11 08:39:38 -07001461 }
1462
1463 if (mListener != null) {
Rekha Kumar14631742015-02-04 10:47:00 -08001464 mListener.onImsProgressing();
1465 }
1466 }
1467
1468 @Override
Omkar Kolangadea7ced642015-05-04 17:55:13 -07001469 public void registrationConnectedWithRadioTech(int imsRadioTech) {
1470 // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY
1471 // values in ServiceState.java.
1472 if (DBG) {
1473 log("registrationConnectedWithRadioTech :: imsRadioTech=" + imsRadioTech);
1474 }
1475
1476 if (mListener != null) {
1477 mListener.onImsConnected();
1478 }
1479 }
1480
1481 @Override
1482 public void registrationProgressingWithRadioTech(int imsRadioTech) {
1483 // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY
1484 // values in ServiceState.java.
1485 if (DBG) {
1486 log("registrationProgressingWithRadioTech :: imsRadioTech=" + imsRadioTech);
1487 }
1488
1489 if (mListener != null) {
1490 mListener.onImsProgressing();
1491 }
1492 }
1493
1494 @Override
Rekha Kumar14631742015-02-04 10:47:00 -08001495 public void registrationDisconnected(ImsReasonInfo imsReasonInfo) {
1496 if (DBG) {
1497 log("registrationDisconnected :: imsReasonInfo" + imsReasonInfo);
1498 }
1499
1500 if (mListener != null) {
1501 mListener.onImsDisconnected(imsReasonInfo);
Wink Savilleef36ef62014-06-11 08:39:38 -07001502 }
1503 }
1504
1505 @Override
1506 public void registrationResumed() {
1507 if (DBG) {
1508 log("registrationResumed ::");
1509 }
1510
1511 if (mListener != null) {
1512 mListener.onImsResumed();
1513 }
1514 }
1515
1516 @Override
1517 public void registrationSuspended() {
1518 if (DBG) {
1519 log("registrationSuspended ::");
1520 }
1521
1522 if (mListener != null) {
1523 mListener.onImsSuspended();
1524 }
1525 }
1526
1527 @Override
1528 public void registrationServiceCapabilityChanged(int serviceClass, int event) {
1529 log("registrationServiceCapabilityChanged :: serviceClass=" +
1530 serviceClass + ", event=" + event);
1531
1532 if (mListener != null) {
1533 mListener.onImsConnected();
1534 }
1535 }
ram7da5a112014-07-16 20:59:27 +05301536
1537 @Override
1538 public void registrationFeatureCapabilityChanged(int serviceClass,
1539 int[] enabledFeatures, int[] disabledFeatures) {
1540 log("registrationFeatureCapabilityChanged :: serviceClass=" +
1541 serviceClass);
Libin.Tang@motorola.come2296782014-08-19 14:20:01 -05001542 if (mListener != null) {
1543 mListener.onFeatureCapabilityChanged(serviceClass,
1544 enabledFeatures, disabledFeatures);
1545 }
ram7da5a112014-07-16 20:59:27 +05301546 }
1547
Shriram Ganeshd3adfad2015-05-31 10:06:15 -07001548 @Override
1549 public void voiceMessageCountUpdate(int count) {
1550 log("voiceMessageCountUpdate :: count=" + count);
1551
1552 if (mListener != null) {
1553 mListener.onVoiceMessageCountChanged(count);
1554 }
1555 }
1556
Pavel Zhamaitsiak4de9cbb2016-02-11 17:21:05 -08001557 @Override
1558 public void registrationAssociatedUriChanged(Uri[] uris) {
1559 if (DBG) log("registrationAssociatedUriChanged ::");
1560
1561 if (mListener != null) {
1562 mListener.registrationAssociatedUriChanged(uris);
1563 }
1564 }
Wink Savilleef36ef62014-06-11 08:39:38 -07001565 }
Tyler Gunn4d128b62016-04-13 15:44:38 -07001566
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001567 /**
1568 * Gets the ECBM interface to request ECBM exit.
1569 *
1570 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1571 * @return the ECBM interface instance
1572 * @throws ImsException if getting the ECBM interface results in an error
1573 */
1574 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException {
1575 if (mEcbm == null) {
1576 checkAndThrowExceptionIfServiceUnavailable();
1577
1578 try {
1579 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId);
1580
1581 if (iEcbm == null) {
1582 throw new ImsException("getEcbmInterface()",
1583 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED);
1584 }
1585 mEcbm = new ImsEcbm(iEcbm);
1586 } catch (RemoteException e) {
1587 throw new ImsException("getEcbmInterface()", e,
1588 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1589 }
1590 }
1591 return mEcbm;
1592 }
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001593
1594 /**
Tyler Gunn4d128b62016-04-13 15:44:38 -07001595 * Gets the Multi-Endpoint interface to subscribe to multi-enpoint notifications..
1596 *
1597 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1598 * @return the multi-endpoint interface instance
1599 * @throws ImsException if getting the multi-endpoint interface results in an error
1600 */
1601 public ImsMultiEndpoint getMultiEndpointInterface(int serviceId) throws ImsException {
1602 if (mMultiEndpoint == null) {
1603 checkAndThrowExceptionIfServiceUnavailable();
1604
1605 try {
1606 IImsMultiEndpoint iImsMultiEndpoint = mImsService.getMultiEndpointInterface(
1607 serviceId);
1608
1609 if (iImsMultiEndpoint == null) {
1610 throw new ImsException("getMultiEndpointInterface()",
1611 ImsReasonInfo.CODE_MULTIENDPOINT_NOT_SUPPORTED);
1612 }
1613 mMultiEndpoint = new ImsMultiEndpoint(iImsMultiEndpoint);
1614 } catch (RemoteException e) {
1615 throw new ImsException("getMultiEndpointInterface()", e,
1616 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1617 }
1618 }
1619 return mMultiEndpoint;
1620 }
1621
1622 /**
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001623 * Resets ImsManager settings back to factory defaults.
1624 *
1625 * @hide
1626 */
1627 public static void factoryReset(Context context) {
1628 // Set VoLTE to default
1629 android.provider.Settings.Global.putInt(context.getContentResolver(),
1630 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED,
1631 ImsConfig.FeatureValueConstants.ON);
1632
1633 // Set VoWiFi to default
1634 android.provider.Settings.Global.putInt(context.getContentResolver(),
1635 android.provider.Settings.Global.WFC_IMS_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -08001636 getBooleanCarrierConfig(context,
1637 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL) ?
1638 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001639
1640 // Set VoWiFi mode to default
1641 android.provider.Settings.Global.putInt(context.getContentResolver(),
1642 android.provider.Settings.Global.WFC_IMS_MODE,
fionaxu5803ef02016-03-08 11:48:48 -08001643 getIntCarrierConfig(context,
1644 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT));
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001645
1646 // Set VoWiFi roaming to default
1647 android.provider.Settings.Global.putInt(context.getContentResolver(),
1648 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
fionaxu5803ef02016-03-08 11:48:48 -08001649 getBooleanCarrierConfig(context,
1650 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ?
1651 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF);
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001652
1653 // Set VT to default
Pavel Zhamaitsiak92b54b22016-04-01 15:55:47 -07001654 android.provider.Settings.Global.putInt(context.getContentResolver(),
1655 android.provider.Settings.Global.VT_IMS_ENABLED,
1656 ImsConfig.FeatureValueConstants.ON);
Pavel Zhamaitsiak8c065f52015-11-10 14:36:44 -08001657
1658 // Push settings to ImsConfig
1659 ImsManager.updateImsServiceConfig(context,
1660 SubscriptionManager.getDefaultVoicePhoneId(), true);
1661 }
Jack Yu2f102bd2015-12-28 15:31:48 -08001662
Amit Mahajan24f7b162016-07-21 16:33:53 -07001663 private boolean isDataEnabled() {
1664 return SystemProperties.getBoolean(DATA_ENABLED_PROP, true);
1665 }
1666
Jack Yu643ffe42016-07-08 14:25:46 -07001667 /**
1668 * Set data enabled/disabled flag.
1669 * @param enabled True if data is enabled, otherwise disabled.
1670 */
1671 public void setDataEnabled(boolean enabled) {
1672 log("setDataEnabled: " + enabled);
Amit Mahajan24f7b162016-07-21 16:33:53 -07001673 SystemProperties.set(DATA_ENABLED_PROP, enabled ? TRUE : FALSE);
1674 }
1675
1676 private boolean isVolteProvisioned() {
1677 return SystemProperties.getBoolean(VOLTE_PROVISIONED_PROP, true);
1678 }
1679
1680 private void setVolteProvisionedProperty(boolean provisioned) {
1681 SystemProperties.set(VOLTE_PROVISIONED_PROP, provisioned ? TRUE : FALSE);
1682 }
1683
1684 private boolean isWfcProvisioned() {
1685 return SystemProperties.getBoolean(WFC_PROVISIONED_PROP, true);
1686 }
1687
1688 private void setWfcProvisionedProperty(boolean provisioned) {
1689 SystemProperties.set(WFC_PROVISIONED_PROP, provisioned ? TRUE : FALSE);
1690 }
1691
1692 private boolean isVtProvisioned() {
1693 return SystemProperties.getBoolean(VT_PROVISIONED_PROP, true);
1694 }
1695
1696 private void setVtProvisionedProperty(boolean provisioned) {
1697 SystemProperties.set(VT_PROVISIONED_PROP, provisioned ? TRUE : FALSE);
Jack Yu643ffe42016-07-08 14:25:46 -07001698 }
1699
Jack Yu2f102bd2015-12-28 15:31:48 -08001700 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1701 pw.println("ImsManager:");
1702 pw.println(" mPhoneId = " + mPhoneId);
1703 pw.println(" mConfigUpdated = " + mConfigUpdated);
1704 pw.println(" mImsService = " + mImsService);
Amit Mahajan24f7b162016-07-21 16:33:53 -07001705 pw.println(" mDataEnabled = " + isDataEnabled());
Jack Yu2f102bd2015-12-28 15:31:48 -08001706
1707 pw.println(" isGbaValid = " + isGbaValid(mContext));
1708 pw.println(" isImsTurnOffAllowed = " + isImsTurnOffAllowed());
1709 pw.println(" isNonTtyOrTtyOnVolteEnabled = " + isNonTtyOrTtyOnVolteEnabled(mContext));
1710
1711 pw.println(" isVolteEnabledByPlatform = " + isVolteEnabledByPlatform(mContext));
1712 pw.println(" isVolteProvisionedOnDevice = " + isVolteProvisionedOnDevice(mContext));
1713 pw.println(" isEnhanced4gLteModeSettingEnabledByUser = " +
1714 isEnhanced4gLteModeSettingEnabledByUser(mContext));
1715 pw.println(" isVtEnabledByPlatform = " + isVtEnabledByPlatform(mContext));
1716 pw.println(" isVtEnabledByUser = " + isVtEnabledByUser(mContext));
1717
1718 pw.println(" isWfcEnabledByPlatform = " + isWfcEnabledByPlatform(mContext));
1719 pw.println(" isWfcEnabledByUser = " + isWfcEnabledByUser(mContext));
1720 pw.println(" getWfcMode = " + getWfcMode(mContext));
1721 pw.println(" isWfcRoamingEnabledByUser = " + isWfcRoamingEnabledByUser(mContext));
1722
pkanwar10d18832016-07-12 08:50:01 -07001723 pw.println(" isVtProvisionedOnDevice = " + isVtProvisionedOnDevice(mContext));
1724 pw.println(" isWfcProvisionedOnDevice = " + isWfcProvisionedOnDevice(mContext));
Jack Yu2f102bd2015-12-28 15:31:48 -08001725 pw.flush();
1726 }
Wink Savilleef36ef62014-06-11 08:39:38 -07001727}