blob: 5c4945098d320e4f767e83c51a012ed5befef2a0 [file] [log] [blame]
Wink Savilleef36ef62014-06-11 08:39:38 -07001/*
2 * Copyright (c) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.ims;
18
19import android.app.PendingIntent;
Etan Cohena00c9192014-12-23 15:02:29 -080020import android.app.QueuedWork;
Wink Savilleef36ef62014-06-11 08:39:38 -070021import android.content.Context;
22import android.content.Intent;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -070023import android.content.SharedPreferences;
Wink Savilleef36ef62014-06-11 08:39:38 -070024import android.os.IBinder;
Wink Savilleef36ef62014-06-11 08:39:38 -070025import android.os.Message;
Jonathan Basseri2acea6f2015-07-01 15:00:38 -070026import android.os.PersistableBundle;
Wink Savilleef36ef62014-06-11 08:39:38 -070027import android.os.RemoteException;
28import android.os.ServiceManager;
Etan Cohenaf55a402014-09-04 22:34:41 -070029import android.os.SystemProperties;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -070030import android.preference.PreferenceManager;
Etan Cohen82f78122014-12-15 10:10:14 -080031import android.provider.Settings;
32import android.telecom.TelecomManager;
Junda Liue7663c02015-06-23 11:16:26 -070033import android.telephony.CarrierConfigManager;
Wink Savilleef36ef62014-06-11 08:39:38 -070034import android.telephony.Rlog;
Etan Cohen82f78122014-12-15 10:10:14 -080035import android.telephony.SubscriptionManager;
Etan Cohencfc784d2014-08-07 18:40:31 -070036import android.telephony.TelephonyManager;
Wink Savilleef36ef62014-06-11 08:39:38 -070037
38import com.android.ims.internal.IImsCallSession;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -070039import com.android.ims.internal.IImsEcbm;
40import com.android.ims.internal.IImsEcbmListener;
Wink Savilleef36ef62014-06-11 08:39:38 -070041import com.android.ims.internal.IImsRegistrationListener;
42import com.android.ims.internal.IImsService;
43import com.android.ims.internal.IImsUt;
44import com.android.ims.internal.ImsCallSession;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -050045import com.android.ims.internal.IImsConfig;
46
Jack Yu2f102bd2015-12-28 15:31:48 -080047import java.io.FileDescriptor;
48import java.io.PrintWriter;
Etan Cohend7727462014-07-12 14:54:10 -070049import java.util.HashMap;
50
Wink Savilleef36ef62014-06-11 08:39:38 -070051/**
52 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
53 * the operator's IMS network. This class is the starting point for any IMS actions.
54 * You can acquire an instance of it with {@link #getInstance getInstance()}.</p>
55 * <p>The APIs in this class allows you to:</p>
56 *
57 * @hide
58 */
59public class ImsManager {
Etan Cohen19604c02014-08-11 14:32:57 -070060
Etan Cohenaf55a402014-09-04 22:34:41 -070061 /*
62 * Debug flag to override configuration flag
63 */
Etan Cohenb651fa52014-10-22 10:51:29 -070064 public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr";
65 public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohenea2b5832014-10-23 18:50:35 -070066 public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr";
67 public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohena00c9192014-12-23 15:02:29 -080068 public static final String PROPERTY_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr";
69 public static final int PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT = 0;
Etan Cohenaf55a402014-09-04 22:34:41 -070070
Wink Savilleef36ef62014-06-11 08:39:38 -070071 /**
72 * For accessing the IMS related service.
73 * Internal use only.
74 * @hide
75 */
Etan Cohend7727462014-07-12 14:54:10 -070076 private static final String IMS_SERVICE = "ims";
Wink Savilleef36ef62014-06-11 08:39:38 -070077
78 /**
79 * The result code to be sent back with the incoming call {@link PendingIntent}.
80 * @see #open(PendingIntent, ImsConnectionStateListener)
81 */
82 public static final int INCOMING_CALL_RESULT_CODE = 101;
83
84 /**
85 * Key to retrieve the call ID from an incoming call intent.
86 * @see #open(PendingIntent, ImsConnectionStateListener)
87 */
88 public static final String EXTRA_CALL_ID = "android:imsCallID";
89
90 /**
91 * Action to broadcast when ImsService is up.
92 * Internal use only.
93 * @hide
94 */
95 public static final String ACTION_IMS_SERVICE_UP =
96 "com.android.ims.IMS_SERVICE_UP";
97
98 /**
99 * Action to broadcast when ImsService is down.
100 * Internal use only.
101 * @hide
102 */
103 public static final String ACTION_IMS_SERVICE_DOWN =
104 "com.android.ims.IMS_SERVICE_DOWN";
105
106 /**
Pavel Zhamaitsiak0c2f15c2015-03-12 15:37:54 -0700107 * Action to broadcast when ImsService registration fails.
108 * Internal use only.
109 * @hide
110 */
111 public static final String ACTION_IMS_REGISTRATION_ERROR =
112 "com.android.ims.REGISTRATION_ERROR";
113
114 /**
Etan Cohend7727462014-07-12 14:54:10 -0700115 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
Etan Cohenabbd7882014-09-26 22:35:35 -0700116 * A long value; the phone ID corresponding to the IMS service coming up or down.
Etan Cohend7727462014-07-12 14:54:10 -0700117 * Internal use only.
118 * @hide
119 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700120 public static final String EXTRA_PHONE_ID = "android:phone_id";
Etan Cohend7727462014-07-12 14:54:10 -0700121
122 /**
Wink Savilleef36ef62014-06-11 08:39:38 -0700123 * Action for the incoming call intent for the Phone app.
124 * Internal use only.
125 * @hide
126 */
127 public static final String ACTION_IMS_INCOMING_CALL =
128 "com.android.ims.IMS_INCOMING_CALL";
129
130 /**
131 * Part of the ACTION_IMS_INCOMING_CALL intents.
132 * An integer value; service identifier obtained from {@link ImsManager#open}.
133 * Internal use only.
134 * @hide
135 */
136 public static final String EXTRA_SERVICE_ID = "android:imsServiceId";
137
138 /**
139 * Part of the ACTION_IMS_INCOMING_CALL intents.
140 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD.
141 * The value "true" indicates that the incoming call is for USSD.
142 * Internal use only.
143 * @hide
144 */
145 public static final String EXTRA_USSD = "android:ussd";
146
Shriram Ganeshd3adfad2015-05-31 10:06:15 -0700147 /**
148 * Part of the ACTION_IMS_INCOMING_CALL intents.
149 * A boolean value; Flag to indicate whether the call is an unknown
150 * dialing call. Such calls are originated by sending commands (like
151 * AT commands) directly to modem without Android involvement.
152 * Even though they are not incoming calls, they are propagated
153 * to Phone app using same ACTION_IMS_INCOMING_CALL intent.
154 * Internal use only.
155 * @hide
156 */
Anju Mathapati9c033792015-06-16 16:33:16 -0700157 public static final String EXTRA_IS_UNKNOWN_CALL = "android:isUnknown";
Shriram Ganeshd3adfad2015-05-31 10:06:15 -0700158
Wink Savilleef36ef62014-06-11 08:39:38 -0700159 private static final String TAG = "ImsManager";
160 private static final boolean DBG = true;
161
Wink Saville1e5a38a2014-10-23 10:24:46 -0700162 private static HashMap<Integer, ImsManager> sImsManagerInstances =
163 new HashMap<Integer, ImsManager>();
Etan Cohend7727462014-07-12 14:54:10 -0700164
Wink Savilleef36ef62014-06-11 08:39:38 -0700165 private Context mContext;
Etan Cohenabbd7882014-09-26 22:35:35 -0700166 private int mPhoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700167 private IImsService mImsService = null;
168 private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient();
169 // Ut interface for the supplementary service configuration
170 private ImsUt mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500171 // Interface to get/set ims config items
172 private ImsConfig mConfig = null;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700173 private boolean mConfigUpdated = false;
174 private static final String PREF_ENABLE_VIDEO_CALLING_KEY = "enable_video_calling";
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
Wink Savilleef36ef62014-06-11 08:39:38 -0700181 /**
182 * Gets a manager instance.
183 *
184 * @param context application context for creating the manager object
Etan Cohenabbd7882014-09-26 22:35:35 -0700185 * @param phoneId the phone ID for the IMS Service
186 * @return the manager instance corresponding to the phoneId
Wink Savilleef36ef62014-06-11 08:39:38 -0700187 */
Etan Cohenabbd7882014-09-26 22:35:35 -0700188 public static ImsManager getInstance(Context context, int phoneId) {
Etan Cohend7727462014-07-12 14:54:10 -0700189 synchronized (sImsManagerInstances) {
Etan Cohenabbd7882014-09-26 22:35:35 -0700190 if (sImsManagerInstances.containsKey(phoneId))
191 return sImsManagerInstances.get(phoneId);
Wink Savilleef36ef62014-06-11 08:39:38 -0700192
Etan Cohenabbd7882014-09-26 22:35:35 -0700193 ImsManager mgr = new ImsManager(context, phoneId);
194 sImsManagerInstances.put(phoneId, mgr);
Etan Cohend7727462014-07-12 14:54:10 -0700195
196 return mgr;
197 }
Wink Savilleef36ef62014-06-11 08:39:38 -0700198 }
199
Etan Cohen45b5f312014-08-19 15:55:08 -0700200 /**
201 * Returns the user configuration of Enhanced 4G LTE Mode setting
202 */
203 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) {
Libin.Tang@motorola.com8a6bf4b2014-10-10 15:02:41 -0500204 int enabled = android.provider.Settings.Global.getInt(
205 context.getContentResolver(),
Etan Cohenb651fa52014-10-22 10:51:29 -0700206 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
Etan Cohena00c9192014-12-23 15:02:29 -0800207 return (enabled == 1) ? true : false;
Etan Cohen45b5f312014-08-19 15:55:08 -0700208 }
209
210 /**
Etan Cohen82f78122014-12-15 10:10:14 -0800211 * Change persistent Enhanced 4G LTE Mode setting
212 */
213 public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {
214 int value = enabled ? 1 : 0;
215 android.provider.Settings.Global.putInt(
216 context.getContentResolver(),
217 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, value);
218
219 if (isNonTtyOrTtyOnVolteEnabled(context)) {
220 ImsManager imsManager = ImsManager.getInstance(context,
221 SubscriptionManager.getDefaultVoicePhoneId());
222 if (imsManager != null) {
223 try {
224 imsManager.setAdvanced4GMode(enabled);
225 } catch (ImsException ie) {
226 // do nothing
227 }
228 }
229 }
230 }
231
232 /**
233 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is
234 * supported.
235 */
236 public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) {
Junda Liue7663c02015-06-23 11:16:26 -0700237 if (getBooleanCarrierConfig(context,
238 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -0800239 return true;
240 }
241
242 return Settings.Secure.getInt(context.getContentResolver(),
243 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF)
244 == TelecomManager.TTY_MODE_OFF;
245 }
246
247 /**
Etan Cohenea2b5832014-10-23 18:50:35 -0700248 * Returns a platform configuration for VoLTE which may override the user setting.
Etan Cohen45b5f312014-08-19 15:55:08 -0700249 */
Etan Cohenea2b5832014-10-23 18:50:35 -0700250 public static boolean isVolteEnabledByPlatform(Context context) {
Etan Cohenb651fa52014-10-22 10:51:29 -0700251 if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE,
252 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) {
Etan Cohenaf55a402014-09-04 22:34:41 -0700253 return true;
254 }
255
Etan Cohenb5388a32014-11-26 11:57:47 -0800256 return context.getResources().getBoolean(
Junda Liue7663c02015-06-23 11:16:26 -0700257 com.android.internal.R.bool.config_device_volte_available)
258 && getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700259 CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL)
260 && isGbaValid(context);
Etan Cohenb5388a32014-11-26 11:57:47 -0800261 }
262
263 /*
264 * Indicates whether VoLTE is provisioned on device
265 */
266 public static boolean isVolteProvisionedOnDevice(Context context) {
267 boolean isProvisioned = true;
Junda Liue7663c02015-06-23 11:16:26 -0700268 if (getBooleanCarrierConfig(context,
269 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) {
Etan Cohenb5388a32014-11-26 11:57:47 -0800270 isProvisioned = false; // disable on any error
271 ImsManager mgr = ImsManager.getInstance(context,
Jonathan Basserid7133652015-04-07 19:54:24 -0700272 SubscriptionManager.getDefaultVoicePhoneId());
Etan Cohenb5388a32014-11-26 11:57:47 -0800273 if (mgr != null) {
274 try {
275 ImsConfig config = mgr.getConfigInterface();
276 if (config != null) {
277 isProvisioned = config.getVolteProvisioned();
278 }
279 } catch (ImsException ie) {
280 // do nothing
281 }
282 }
283 }
284
285 return isProvisioned;
Etan Cohenb651fa52014-10-22 10:51:29 -0700286 }
287
Etan Cohenea2b5832014-10-23 18:50:35 -0700288 /**
289 * Returns a platform configuration for VT which may override the user setting.
290 *
291 * Note: VT presumes that VoLTE is enabled (these are configuration settings
292 * which must be done correctly).
293 */
Etan Cohenb651fa52014-10-22 10:51:29 -0700294 public static boolean isVtEnabledByPlatform(Context context) {
Etan Cohenea2b5832014-10-23 18:50:35 -0700295 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE,
296 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) {
297 return true;
298 }
299
Etan Cohenb651fa52014-10-22 10:51:29 -0700300 return
301 context.getResources().getBoolean(
302 com.android.internal.R.bool.config_device_vt_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700303 getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700304 CarrierConfigManager.KEY_CARRIER_VT_AVAILABLE_BOOL) &&
305 isGbaValid(context);
Etan Cohen45b5f312014-08-19 15:55:08 -0700306 }
307
Etan Cohena00c9192014-12-23 15:02:29 -0800308 /**
Etan Cohen6f3737f2015-05-04 18:02:09 -0700309 * Returns the user configuration of VT setting
310 */
311 public static boolean isVtEnabledByUser(Context context) {
312 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
313 android.provider.Settings.Global.VT_IMS_ENABLED,
314 ImsConfig.FeatureValueConstants.ON);
315 return (enabled == 1) ? true : false;
316 }
317
318 /**
319 * Change persistent VT enabled setting
320 */
321 public static void setVtSetting(Context context, boolean enabled) {
322 int value = enabled ? 1 : 0;
323 android.provider.Settings.Global.putInt(context.getContentResolver(),
324 android.provider.Settings.Global.VT_IMS_ENABLED, value);
325
326 ImsManager imsManager = ImsManager.getInstance(context,
327 SubscriptionManager.getDefaultVoicePhoneId());
328 if (imsManager != null) {
329 try {
330 ImsConfig config = imsManager.getConfigInterface();
331 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
332 TelephonyManager.NETWORK_TYPE_LTE,
333 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800334 : ImsConfig.FeatureValueConstants.OFF,
335 imsManager.mImsConfigListener);
Etan Cohen6f3737f2015-05-04 18:02:09 -0700336
337 if (enabled) {
338 imsManager.turnOnIms();
339 } else if (context.getResources().getBoolean(
340 com.android.internal.R.bool.imsServiceAllowTurnOff) && (
341 !isVolteEnabledByPlatform(context)
342 || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
343 log("setVtSetting() : imsServiceAllowTurnOff -> turnOffIms");
344 imsManager.turnOffIms();
345 }
346 } catch (ImsException e) {
347 loge("setVtSetting(): " + e);
348 }
349 }
350 }
351
352 /**
Etan Cohena00c9192014-12-23 15:02:29 -0800353 * Returns the user configuration of WFC setting
354 */
355 public static boolean isWfcEnabledByUser(Context context) {
356 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
357 android.provider.Settings.Global.WFC_IMS_ENABLED,
Pavel Zhamaitsiakeb13a592015-04-27 09:44:33 -0700358 ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800359 return (enabled == 1) ? true : false;
360 }
361
362 /**
363 * Change persistent WFC enabled setting
364 */
365 public static void setWfcSetting(Context context, boolean enabled) {
366 int value = enabled ? 1 : 0;
367 android.provider.Settings.Global.putInt(context.getContentResolver(),
368 android.provider.Settings.Global.WFC_IMS_ENABLED, value);
369
370 ImsManager imsManager = ImsManager.getInstance(context,
371 SubscriptionManager.getDefaultVoicePhoneId());
372 if (imsManager != null) {
373 try {
374 ImsConfig config = imsManager.getConfigInterface();
Etan Cohena00c9192014-12-23 15:02:29 -0800375 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
Nathan Harold3a99f782015-07-24 15:02:34 -0700376 TelephonyManager.NETWORK_TYPE_IWLAN,
Etan Cohena00c9192014-12-23 15:02:29 -0800377 enabled ? ImsConfig.FeatureValueConstants.ON
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800378 : ImsConfig.FeatureValueConstants.OFF,
379 imsManager.mImsConfigListener);
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800380
381 if (enabled) {
382 imsManager.turnOnIms();
Junda Liue7663c02015-06-23 11:16:26 -0700383 } else if (getBooleanCarrierConfig(context,
384 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL)
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800385 && (!isVolteEnabledByPlatform(context)
386 || !isEnhanced4gLteModeSettingEnabledByUser(context))) {
387 log("setWfcSetting() : imsServiceAllowTurnOff -> turnOffIms");
388 imsManager.turnOffIms();
389 }
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700390
391 // Force IMS to register over LTE when turning off WFC
392 setWfcModeInternal(context, enabled
393 ? getWfcMode(context)
394 : ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED);
Etan Cohena00c9192014-12-23 15:02:29 -0800395 } catch (ImsException e) {
Pavel Zhamaitsiak183af602015-02-24 10:20:27 -0800396 loge("setWfcSetting(): " + e);
Etan Cohena00c9192014-12-23 15:02:29 -0800397 }
398 }
399 }
400
401 /**
402 * Returns the user configuration of WFC modem setting
403 */
404 public static int getWfcMode(Context context) {
405 int setting = android.provider.Settings.Global.getInt(context.getContentResolver(),
406 android.provider.Settings.Global.WFC_IMS_MODE,
407 ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED);
408 if (DBG) log("getWfcMode - setting=" + setting);
409 return setting;
410 }
411
412 /**
413 * Returns the user configuration of WFC modem setting
414 */
415 public static void setWfcMode(Context context, int wfcMode) {
416 if (DBG) log("setWfcMode - setting=" + wfcMode);
417 android.provider.Settings.Global.putInt(context.getContentResolver(),
418 android.provider.Settings.Global.WFC_IMS_MODE, wfcMode);
419
Pavel Zhamaitsiak9e6eca22015-03-16 15:30:53 -0700420 setWfcModeInternal(context, wfcMode);
421 }
422
423 private static void setWfcModeInternal(Context context, int wfcMode) {
Etan Cohena00c9192014-12-23 15:02:29 -0800424 final ImsManager imsManager = ImsManager.getInstance(context,
425 SubscriptionManager.getDefaultVoicePhoneId());
426 if (imsManager != null) {
427 final int value = wfcMode;
428 QueuedWork.singleThreadExecutor().submit(new Runnable() {
429 public void run() {
430 try {
431 imsManager.getConfigInterface().setProvisionedValue(
432 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE,
433 value);
434 } catch (ImsException e) {
435 // do nothing
436 }
437 }
438 });
439 }
440 }
441
442 /**
443 * Returns the user configuration of WFC roaming setting
444 */
445 public static boolean isWfcRoamingEnabledByUser(Context context) {
446 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
447 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
Pavel Zhamaitsiak28c84002015-03-10 16:42:01 -0700448 ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800449 return (enabled == 1) ? true : false;
450 }
451
452 /**
453 * Change persistent WFC roaming enabled setting
454 */
455 public static void setWfcRoamingSetting(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800456 android.provider.Settings.Global.putInt(context.getContentResolver(),
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700457 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
458 enabled
459 ? ImsConfig.FeatureValueConstants.ON
460 : ImsConfig.FeatureValueConstants.OFF);
Etan Cohena00c9192014-12-23 15:02:29 -0800461
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700462 setWfcRoamingSettingInternal(context, enabled);
463 }
464
465 private static void setWfcRoamingSettingInternal(Context context, boolean enabled) {
Etan Cohena00c9192014-12-23 15:02:29 -0800466 final ImsManager imsManager = ImsManager.getInstance(context,
467 SubscriptionManager.getDefaultVoicePhoneId());
468 if (imsManager != null) {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700469 final int value = enabled
470 ? ImsConfig.FeatureValueConstants.ON
471 : ImsConfig.FeatureValueConstants.OFF;
Etan Cohena00c9192014-12-23 15:02:29 -0800472 QueuedWork.singleThreadExecutor().submit(new Runnable() {
473 public void run() {
474 try {
475 imsManager.getConfigInterface().setProvisionedValue(
476 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_ROAMING,
477 value);
478 } catch (ImsException e) {
479 // do nothing
480 }
481 }
482 });
483 }
484 }
485
486 /**
487 * Returns a platform configuration for WFC which may override the user
488 * setting. Note: WFC presumes that VoLTE is enabled (these are
489 * configuration settings which must be done correctly).
490 */
491 public static boolean isWfcEnabledByPlatform(Context context) {
492 if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE,
493 PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT) == 1) {
494 return true;
495 }
496
497 return
498 context.getResources().getBoolean(
499 com.android.internal.R.bool.config_device_wfc_ims_available) &&
Junda Liue7663c02015-06-23 11:16:26 -0700500 getBooleanCarrierConfig(context,
Pavel Zhamaitsiak57911d12015-10-20 14:26:34 -0700501 CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) &&
502 isGbaValid(context);
503 }
504
505 /**
506 * If carrier requires that IMS is only available if GBA capable SIM is used,
507 * then this function checks GBA bit in EF IST.
508 *
509 * Format of EF IST is defined in 3GPP TS 31.103 (Section 4.2.7).
510 */
511 private static boolean isGbaValid(Context context) {
512 if (getBooleanCarrierConfig(context,
513 CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) {
514 final TelephonyManager telephonyManager = TelephonyManager.getDefault();
515 String efIst = telephonyManager.getIsimIst();
516 if (efIst == null) {
517 loge("ISF is NULL");
518 return true;
519 }
520 boolean result = efIst != null && efIst.length() > 1 &&
521 (0x02 & (byte)efIst.charAt(1)) != 0;
522 if (DBG) log("GBA capable=" + result + ", ISF=" + efIst);
523 return result;
524 }
525 return true;
Etan Cohena00c9192014-12-23 15:02:29 -0800526 }
527
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700528 /**
529 * Sync carrier config and user settings with ImsConfig.
530 *
531 * @param context for the manager object
532 * @param phoneId phone id
533 * @param force update
534 */
535 public static void updateImsServiceConfig(Context context, int phoneId, boolean force) {
536 final ImsManager imsManager = ImsManager.getInstance(context, phoneId);
537 if (imsManager != null && (!imsManager.mConfigUpdated || force)) {
538 try {
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700539 boolean turnOn = imsManager.updateVolteFeatureValue();
540 turnOn |= imsManager.updateVideoCallFeatureValue();
541 turnOn |= imsManager.updateWfcFeatureAndProvisionedValues();
542
543 if (turnOn) {
544 imsManager.turnOnIms();
545 } else if (getBooleanCarrierConfig(context,
546 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL)) {
547 imsManager.turnOffIms();
548 }
549
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700550 imsManager.mConfigUpdated = true;
551 } catch (ImsException e) {
552 loge("updateImsServiceConfig: " + e);
553 imsManager.mConfigUpdated = false;
554 }
555 }
556 }
557
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700558 /**
559 * Update VoLTE config
560 * @return whether feature is On
561 * @throws ImsException
562 */
563 private boolean updateVolteFeatureValue() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700564 boolean available = isVolteEnabledByPlatform(mContext);
565 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext);
566 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700567 boolean turnOn = available && enabled && isNonTty;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700568
569 log("updateVolteFeatureValue: available = " + available
570 + ", enabled = " + enabled
571 + ", nonTTY = " + isNonTty);
572
573 getConfigInterface().setFeatureValue(
574 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
575 TelephonyManager.NETWORK_TYPE_LTE,
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700576 turnOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700577 ImsConfig.FeatureValueConstants.ON :
578 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800579 mImsConfigListener);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700580
581 return turnOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700582 }
583
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700584 /**
585 * Update VC config
586 * @return whether feature is On
587 * @throws ImsException
588 */
589 private boolean updateVideoCallFeatureValue() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700590 boolean available = isVtEnabledByPlatform(mContext);
591 SharedPreferences sharedPrefs =
592 PreferenceManager.getDefaultSharedPreferences(mContext);
593 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext) &&
594 sharedPrefs.getBoolean(PREF_ENABLE_VIDEO_CALLING_KEY, true);
595 boolean isNonTty = Settings.Secure.getInt(mContext.getContentResolver(),
596 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF)
597 == TelecomManager.TTY_MODE_OFF;
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700598 boolean turnOn = available && enabled && isNonTty;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700599
600 log("updateVideoCallFeatureValue: available = " + available
601 + ", enabled = " + enabled
602 + ", nonTTY = " + isNonTty);
603
604 getConfigInterface().setFeatureValue(
605 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
606 TelephonyManager.NETWORK_TYPE_LTE,
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700607 turnOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700608 ImsConfig.FeatureValueConstants.ON :
609 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800610 mImsConfigListener);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700611
612 return turnOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700613 }
614
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700615 /**
616 * Update WFC config
617 * @return whether feature is On
618 * @throws ImsException
619 */
620 private boolean updateWfcFeatureAndProvisionedValues() throws ImsException {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700621 boolean available = isWfcEnabledByPlatform(mContext);
622 boolean enabled = isWfcEnabledByUser(mContext);
623 int mode = getWfcMode(mContext);
624 boolean roaming = isWfcRoamingEnabledByUser(mContext);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700625 boolean turnOn = available && enabled;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700626
627 log("updateWfcFeatureAndProvisionedValues: available = " + available
628 + ", enabled = " + enabled
629 + ", mode = " + mode
630 + ", roaming = " + roaming);
631
632 getConfigInterface().setFeatureValue(
Pavel Zhamaitsiake6f99432015-09-11 10:29:30 -0700633 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI,
634 TelephonyManager.NETWORK_TYPE_IWLAN,
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700635 turnOn ?
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700636 ImsConfig.FeatureValueConstants.ON :
637 ImsConfig.FeatureValueConstants.OFF,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800638 mImsConfigListener);
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700639
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700640 if (!turnOn) {
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700641 mode = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED;
642 roaming = false;
643 }
644 setWfcModeInternal(mContext, mode);
645 setWfcRoamingSettingInternal(mContext, roaming);
Pavel Zhamaitsiakdc16e452015-09-08 17:12:06 -0700646
647 return turnOn;
Pavel Zhamaitsiak8ca52ff2015-09-04 17:08:35 -0700648 }
649
Etan Cohenabbd7882014-09-26 22:35:35 -0700650 private ImsManager(Context context, int phoneId) {
Wink Savilleef36ef62014-06-11 08:39:38 -0700651 mContext = context;
Etan Cohenabbd7882014-09-26 22:35:35 -0700652 mPhoneId = phoneId;
Wink Savilleef36ef62014-06-11 08:39:38 -0700653 createImsService(true);
654 }
655
Etan Cohenf4311122015-02-26 17:47:13 -0800656 /*
657 * Returns a flag indicating whether the IMS service is available.
658 */
659 public boolean isServiceAvailable() {
660 if (mImsService != null) {
661 return true;
662 }
663
664 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
665 if (binder != null) {
666 return true;
667 }
668
669 return false;
670 }
671
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -0800672 public void setImsConfigListener(ImsConfigListener listener) {
673 mImsConfigListener = listener;
674 }
675
Wink Savilleef36ef62014-06-11 08:39:38 -0700676 /**
677 * Opens the IMS service for making calls and/or receiving generic IMS calls.
678 * The caller may make subsquent calls through {@link #makeCall}.
679 * The IMS service will register the device to the operator's network with the credentials
680 * (from ISIM) periodically in order to receive calls from the operator's network.
681 * When the IMS service receives a new call, it will send out an intent with
682 * the provided action string.
683 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call.
684 *
685 * @param serviceClass a service class specified in {@link ImsServiceClass}
686 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}.
687 * @param incomingCallPendingIntent When an incoming call is received,
688 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to
689 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE}
690 * as the result code and the intent to fill in the call ID; It cannot be null
691 * @param listener To listen to IMS registration events; It cannot be null
692 * @return identifier (greater than 0) for the specified service
693 * @throws NullPointerException if {@code incomingCallPendingIntent}
694 * or {@code listener} is null
695 * @throws ImsException if calling the IMS service results in an error
696 * @see #getCallId
697 * @see #getServiceId
698 */
699 public int open(int serviceClass, PendingIntent incomingCallPendingIntent,
700 ImsConnectionStateListener listener) throws ImsException {
701 checkAndThrowExceptionIfServiceUnavailable();
702
703 if (incomingCallPendingIntent == null) {
704 throw new NullPointerException("incomingCallPendingIntent can't be null");
705 }
706
707 if (listener == null) {
708 throw new NullPointerException("listener can't be null");
709 }
710
711 int result = 0;
712
713 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700714 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent,
Wink Savilleef36ef62014-06-11 08:39:38 -0700715 createRegistrationListenerProxy(serviceClass, listener));
716 } catch (RemoteException e) {
717 throw new ImsException("open()", e,
718 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
719 }
720
721 if (result <= 0) {
722 // If the return value is a minus value,
723 // it means that an error occurred in the service.
724 // So, it needs to convert to the reason code specified in ImsReasonInfo.
725 throw new ImsException("open()", (result * (-1)));
726 }
727
728 return result;
729 }
730
731 /**
732 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls.
733 * All the resources that were allocated to the service are also released.
734 *
735 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open}
736 * @throws ImsException if calling the IMS service results in an error
737 */
738 public void close(int serviceId) throws ImsException {
739 checkAndThrowExceptionIfServiceUnavailable();
740
741 try {
742 mImsService.close(serviceId);
743 } catch (RemoteException e) {
744 throw new ImsException("close()", e,
745 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
746 } finally {
747 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500748 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -0700749 mEcbm = null;
Wink Savilleef36ef62014-06-11 08:39:38 -0700750 }
751 }
752
753 /**
754 * Gets the configuration interface to provision / withdraw the supplementary service settings.
755 *
756 * @param serviceId a service id which is obtained from {@link ImsManager#open}
757 * @return the Ut interface instance
758 * @throws ImsException if getting the Ut interface results in an error
759 */
760 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId)
761 throws ImsException {
762 // FIXME: manage the multiple Ut interfaces based on the service id
763 if (mUt == null) {
764 checkAndThrowExceptionIfServiceUnavailable();
765
766 try {
767 IImsUt iUt = mImsService.getUtInterface(serviceId);
768
769 if (iUt == null) {
770 throw new ImsException("getSupplementaryServiceConfiguration()",
771 ImsReasonInfo.CODE_UT_NOT_SUPPORTED);
772 }
773
774 mUt = new ImsUt(iUt);
775 } catch (RemoteException e) {
776 throw new ImsException("getSupplementaryServiceConfiguration()", e,
777 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
778 }
779 }
780
781 return mUt;
782 }
783
784 /**
785 * Checks if the IMS service has successfully registered to the IMS network
786 * with the specified service & call type.
787 *
788 * @param serviceId a service id which is obtained from {@link ImsManager#open}
789 * @param serviceType a service type that is specified in {@link ImsCallProfile}
790 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
791 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
792 * @param callType a call type that is specified in {@link ImsCallProfile}
793 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
794 * {@link ImsCallProfile#CALL_TYPE_VOICE}
795 * {@link ImsCallProfile#CALL_TYPE_VT}
796 * {@link ImsCallProfile#CALL_TYPE_VS}
797 * @return true if the specified service id is connected to the IMS network;
798 * false otherwise
799 * @throws ImsException if calling the IMS service results in an error
800 */
801 public boolean isConnected(int serviceId, int serviceType, int callType)
802 throws ImsException {
803 checkAndThrowExceptionIfServiceUnavailable();
804
805 try {
806 return mImsService.isConnected(serviceId, serviceType, callType);
807 } catch (RemoteException e) {
808 throw new ImsException("isServiceConnected()", e,
809 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
810 }
811 }
812
813 /**
814 * Checks if the specified IMS service is opend.
815 *
816 * @param serviceId a service id which is obtained from {@link ImsManager#open}
817 * @return true if the specified service id is opened; false otherwise
818 * @throws ImsException if calling the IMS service results in an error
819 */
820 public boolean isOpened(int serviceId) throws ImsException {
821 checkAndThrowExceptionIfServiceUnavailable();
822
823 try {
824 return mImsService.isOpened(serviceId);
825 } catch (RemoteException e) {
826 throw new ImsException("isOpened()", e,
827 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
828 }
829 }
830
831 /**
832 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
833 *
834 * @param serviceId a service id which is obtained from {@link ImsManager#open}
835 * @param serviceType a service type that is specified in {@link ImsCallProfile}
836 * {@link ImsCallProfile#SERVICE_TYPE_NONE}
837 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
838 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
839 * @param callType a call type that is specified in {@link ImsCallProfile}
840 * {@link ImsCallProfile#CALL_TYPE_VOICE}
841 * {@link ImsCallProfile#CALL_TYPE_VT}
842 * {@link ImsCallProfile#CALL_TYPE_VT_TX}
843 * {@link ImsCallProfile#CALL_TYPE_VT_RX}
844 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
845 * {@link ImsCallProfile#CALL_TYPE_VS}
846 * {@link ImsCallProfile#CALL_TYPE_VS_TX}
847 * {@link ImsCallProfile#CALL_TYPE_VS_RX}
848 * @return a {@link ImsCallProfile} object
849 * @throws ImsException if calling the IMS service results in an error
850 */
851 public ImsCallProfile createCallProfile(int serviceId,
852 int serviceType, int callType) throws ImsException {
853 checkAndThrowExceptionIfServiceUnavailable();
854
855 try {
856 return mImsService.createCallProfile(serviceId, serviceType, callType);
857 } catch (RemoteException e) {
858 throw new ImsException("createCallProfile()", e,
859 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
860 }
861 }
862
863 /**
864 * Creates a {@link ImsCall} to make a call.
865 *
866 * @param serviceId a service id which is obtained from {@link ImsManager#open}
867 * @param profile a call profile to make the call
868 * (it contains service type, call type, media information, etc.)
869 * @param participants participants to invite the conference call
870 * @param listener listen to the call events from {@link ImsCall}
871 * @return a {@link ImsCall} object
872 * @throws ImsException if calling the IMS service results in an error
873 */
874 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees,
875 ImsCall.Listener listener) throws ImsException {
876 if (DBG) {
877 log("makeCall :: serviceId=" + serviceId
878 + ", profile=" + profile + ", callees=" + callees);
879 }
880
881 checkAndThrowExceptionIfServiceUnavailable();
882
883 ImsCall call = new ImsCall(mContext, profile);
884
885 call.setListener(listener);
886 ImsCallSession session = createCallSession(serviceId, profile);
887
888 if ((callees != null) && (callees.length == 1)) {
889 call.start(session, callees[0]);
890 } else {
891 call.start(session, callees);
892 }
893
894 return call;
895 }
896
897 /**
898 * Creates a {@link ImsCall} to take an incoming call.
899 *
900 * @param serviceId a service id which is obtained from {@link ImsManager#open}
901 * @param incomingCallIntent the incoming call broadcast intent
902 * @param listener to listen to the call events from {@link ImsCall}
903 * @return a {@link ImsCall} object
904 * @throws ImsException if calling the IMS service results in an error
905 */
906 public ImsCall takeCall(int serviceId, Intent incomingCallIntent,
907 ImsCall.Listener listener) throws ImsException {
908 if (DBG) {
909 log("takeCall :: serviceId=" + serviceId
910 + ", incomingCall=" + incomingCallIntent);
911 }
912
913 checkAndThrowExceptionIfServiceUnavailable();
914
915 if (incomingCallIntent == null) {
916 throw new ImsException("Can't retrieve session with null intent",
917 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
918 }
919
920 int incomingServiceId = getServiceId(incomingCallIntent);
921
922 if (serviceId != incomingServiceId) {
923 throw new ImsException("Service id is mismatched in the incoming call intent",
924 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
925 }
926
927 String callId = getCallId(incomingCallIntent);
928
929 if (callId == null) {
930 throw new ImsException("Call ID missing in the incoming call intent",
931 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT);
932 }
933
934 try {
935 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId);
936
937 if (session == null) {
938 throw new ImsException("No pending session for the call",
939 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL);
940 }
941
942 ImsCall call = new ImsCall(mContext, session.getCallProfile());
943
944 call.attachSession(new ImsCallSession(session));
945 call.setListener(listener);
946
947 return call;
948 } catch (Throwable t) {
949 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED);
950 }
951 }
952
953 /**
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500954 * Gets the config interface to get/set service/capability parameters.
955 *
956 * @return the ImsConfig instance.
957 * @throws ImsException if getting the setting interface results in an error.
958 */
959 public ImsConfig getConfigInterface() throws ImsException {
960
961 if (mConfig == null) {
962 checkAndThrowExceptionIfServiceUnavailable();
963
964 try {
Etan Cohenabbd7882014-09-26 22:35:35 -0700965 IImsConfig config = mImsService.getConfigInterface(mPhoneId);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500966 if (config == null) {
967 throw new ImsException("getConfigInterface()",
968 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
969 }
Libin.Tang@motorola.com54953c72014-08-07 15:02:08 -0500970 mConfig = new ImsConfig(config, mContext);
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500971 } catch (RemoteException e) {
972 throw new ImsException("getConfigInterface()", e,
973 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
974 }
975 }
976 if (DBG) log("getConfigInterface(), mConfig= " + mConfig);
977 return mConfig;
978 }
979
Etan Cohen82f78122014-12-15 10:10:14 -0800980 public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete)
Shriram Ganeshc403b7b2014-08-14 14:18:57 +0530981 throws ImsException {
982
Etan Cohen82f78122014-12-15 10:10:14 -0800983 checkAndThrowExceptionIfServiceUnavailable();
Shriram Ganeshc403b7b2014-08-14 14:18:57 +0530984
Etan Cohen82f78122014-12-15 10:10:14 -0800985 try {
986 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete);
987 } catch (RemoteException e) {
988 throw new ImsException("setTTYMode()", e,
989 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
990 }
991
Junda Liue7663c02015-06-23 11:16:26 -0700992 if (!getBooleanCarrierConfig(context,
993 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
Etan Cohen82f78122014-12-15 10:10:14 -0800994 setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) &&
995 isEnhanced4gLteModeSettingEnabledByUser(context));
996 }
Shriram Ganeshc403b7b2014-08-14 14:18:57 +0530997 }
998
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -0500999 /**
Junda Liue7663c02015-06-23 11:16:26 -07001000 * Get the boolean config from carrier config manager.
1001 *
1002 * @param context the context to get carrier service
1003 * @param key config key defined in CarrierConfigManager
1004 * @return boolean value of corresponding key.
1005 */
1006 private static boolean getBooleanCarrierConfig(Context context, String key) {
1007 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
1008 Context.CARRIER_CONFIG_SERVICE);
Jonathan Basseri2acea6f2015-07-01 15:00:38 -07001009 PersistableBundle b = null;
Junda Liue7663c02015-06-23 11:16:26 -07001010 if (configManager != null) {
Jonathan Basseri2acea6f2015-07-01 15:00:38 -07001011 b = configManager.getConfig();
1012 }
1013 if (b != null) {
1014 return b.getBoolean(key);
Junda Liue7663c02015-06-23 11:16:26 -07001015 } else {
1016 // Return static default defined in CarrierConfigManager.
1017 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
1018 }
1019 }
1020
1021 /**
Wink Savilleef36ef62014-06-11 08:39:38 -07001022 * Gets the call ID from the specified incoming call broadcast intent.
1023 *
1024 * @param incomingCallIntent the incoming call broadcast intent
1025 * @return the call ID or null if the intent does not contain it
1026 */
1027 private static String getCallId(Intent incomingCallIntent) {
1028 if (incomingCallIntent == null) {
1029 return null;
1030 }
1031
1032 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID);
1033 }
1034
1035 /**
1036 * Gets the service type from the specified incoming call broadcast intent.
1037 *
1038 * @param incomingCallIntent the incoming call broadcast intent
1039 * @return the service identifier or -1 if the intent does not contain it
1040 */
1041 private static int getServiceId(Intent incomingCallIntent) {
1042 if (incomingCallIntent == null) {
1043 return (-1);
1044 }
1045
1046 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1);
1047 }
1048
1049 /**
1050 * Binds the IMS service only if the service is not created.
1051 */
1052 private void checkAndThrowExceptionIfServiceUnavailable()
1053 throws ImsException {
1054 if (mImsService == null) {
1055 createImsService(true);
1056
1057 if (mImsService == null) {
1058 throw new ImsException("Service is unavailable",
1059 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1060 }
1061 }
1062 }
1063
Etan Cohenabbd7882014-09-26 22:35:35 -07001064 private static String getImsServiceName(int phoneId) {
1065 // TODO: MSIM implementation needs to decide on service name as a function of phoneId
Etan Cohend7727462014-07-12 14:54:10 -07001066 return IMS_SERVICE;
1067 }
1068
Wink Savilleef36ef62014-06-11 08:39:38 -07001069 /**
1070 * Binds the IMS service to make/receive the call.
1071 */
1072 private void createImsService(boolean checkService) {
1073 if (checkService) {
Etan Cohenabbd7882014-09-26 22:35:35 -07001074 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -07001075
1076 if (binder == null) {
1077 return;
1078 }
1079 }
1080
Etan Cohenabbd7882014-09-26 22:35:35 -07001081 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));
Wink Savilleef36ef62014-06-11 08:39:38 -07001082
1083 if (b != null) {
1084 try {
1085 b.linkToDeath(mDeathRecipient, 0);
1086 } catch (RemoteException e) {
1087 }
1088 }
1089
1090 mImsService = IImsService.Stub.asInterface(b);
1091 }
1092
1093 /**
1094 * Creates a {@link ImsCallSession} with the specified call profile.
1095 * Use other methods, if applicable, instead of interacting with
1096 * {@link ImsCallSession} directly.
1097 *
1098 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1099 * @param profile a call profile to make the call
1100 */
1101 private ImsCallSession createCallSession(int serviceId,
1102 ImsCallProfile profile) throws ImsException {
1103 try {
1104 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null));
1105 } catch (RemoteException e) {
1106 return null;
1107 }
1108 }
1109
1110 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass,
1111 ImsConnectionStateListener listener) {
1112 ImsRegistrationListenerProxy proxy =
1113 new ImsRegistrationListenerProxy(serviceClass, listener);
1114 return proxy;
1115 }
1116
Etan Cohena00c9192014-12-23 15:02:29 -08001117 private static void log(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001118 Rlog.d(TAG, s);
1119 }
1120
Etan Cohena00c9192014-12-23 15:02:29 -08001121 private static void loge(String s) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001122 Rlog.e(TAG, s);
1123 }
1124
Etan Cohena00c9192014-12-23 15:02:29 -08001125 private static void loge(String s, Throwable t) {
Wink Savilleef36ef62014-06-11 08:39:38 -07001126 Rlog.e(TAG, s, t);
1127 }
1128
1129 /**
ram7da5a112014-07-16 20:59:27 +05301130 * Used for turning on IMS.if its off already
1131 */
Etan Cohen82f78122014-12-15 10:10:14 -08001132 private void turnOnIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001133 checkAndThrowExceptionIfServiceUnavailable();
1134
ram7da5a112014-07-16 20:59:27 +05301135 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001136 mImsService.turnOnIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301137 } catch (RemoteException e) {
1138 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1139 }
1140 }
1141
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001142 private boolean isImsTurnOffAllowed() {
1143 return getBooleanCarrierConfig(mContext,
1144 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL)
1145 && (!isWfcEnabledByPlatform(mContext)
1146 || !isWfcEnabledByUser(mContext));
1147 }
1148
Etan Cohen82f78122014-12-15 10:10:14 -08001149 private void setAdvanced4GMode(boolean turnOn) throws ImsException {
Etan Cohencfc784d2014-08-07 18:40:31 -07001150 checkAndThrowExceptionIfServiceUnavailable();
1151
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001152 try {
1153 ImsConfig config = getConfigInterface();
1154 if (config != null && (turnOn || !isImsTurnOffAllowed())) {
1155 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -08001156 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, mImsConfigListener);
1157
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001158 if (isVtEnabledByPlatform(mContext)) {
1159 // TODO: once VT is available on platform:
1160 // - replace the '1' with the current user configuration of VT.
1161 // - separate exception checks for setFeatureValue() failures for VoLTE and VT.
1162 // I.e. if VoLTE fails still try to configure VT.
1163 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE,
Pavel Zhamaitsiakf4b90322016-01-26 14:34:09 -08001164 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, mImsConfigListener);
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001165 }
Etan Cohenb651fa52014-10-22 10:51:29 -07001166 }
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001167 } catch (ImsException e) {
1168 log("setAdvanced4GMode() : " + e);
Etan Cohencfc784d2014-08-07 18:40:31 -07001169 }
Etan Cohencfc784d2014-08-07 18:40:31 -07001170 if (turnOn) {
1171 turnOnIms();
Omkar Kolangade75f3ca32014-10-24 11:10:52 -07001172 } else if (isImsTurnOffAllowed()) {
Etan Cohencfc784d2014-08-07 18:40:31 -07001173 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms");
1174 turnOffIms();
1175 }
1176 }
1177
ram7da5a112014-07-16 20:59:27 +05301178 /**
1179 * Used for turning off IMS completely in order to make the device CSFB'ed.
1180 * Once turned off, all calls will be over CS.
1181 */
Etan Cohen82f78122014-12-15 10:10:14 -08001182 private void turnOffIms() throws ImsException {
Etan Cohen0c9c09e2014-07-25 11:09:12 -07001183 checkAndThrowExceptionIfServiceUnavailable();
1184
ram7da5a112014-07-16 20:59:27 +05301185 try {
Etan Cohenabbd7882014-09-26 22:35:35 -07001186 mImsService.turnOffIms(mPhoneId);
ram7da5a112014-07-16 20:59:27 +05301187 } catch (RemoteException e) {
1188 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1189 }
1190 }
1191
1192 /**
Wink Savilleef36ef62014-06-11 08:39:38 -07001193 * Death recipient class for monitoring IMS service.
1194 */
1195 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient {
1196 @Override
1197 public void binderDied() {
1198 mImsService = null;
1199 mUt = null;
Libin.Tang@motorola.com076c55d2014-06-23 19:46:36 -05001200 mConfig = null;
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001201 mEcbm = null;
Wink Savilleef36ef62014-06-11 08:39:38 -07001202
1203 if (mContext != null) {
Etan Cohend7727462014-07-12 14:54:10 -07001204 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN);
Etan Cohenabbd7882014-09-26 22:35:35 -07001205 intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
Etan Cohend7727462014-07-12 14:54:10 -07001206 mContext.sendBroadcast(new Intent(intent));
Wink Savilleef36ef62014-06-11 08:39:38 -07001207 }
1208 }
1209 }
1210
1211 /**
1212 * Adapter class for {@link IImsRegistrationListener}.
1213 */
1214 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub {
1215 private int mServiceClass;
1216 private ImsConnectionStateListener mListener;
1217
1218 public ImsRegistrationListenerProxy(int serviceClass,
1219 ImsConnectionStateListener listener) {
1220 mServiceClass = serviceClass;
1221 mListener = listener;
1222 }
1223
1224 public boolean isSameProxy(int serviceClass) {
1225 return (mServiceClass == serviceClass);
1226 }
1227
1228 @Override
1229 public void registrationConnected() {
1230 if (DBG) {
1231 log("registrationConnected ::");
1232 }
1233
1234 if (mListener != null) {
1235 mListener.onImsConnected();
1236 }
1237 }
1238
1239 @Override
Rekha Kumar14631742015-02-04 10:47:00 -08001240 public void registrationProgressing() {
Wink Savilleef36ef62014-06-11 08:39:38 -07001241 if (DBG) {
Rekha Kumar14631742015-02-04 10:47:00 -08001242 log("registrationProgressing ::");
Wink Savilleef36ef62014-06-11 08:39:38 -07001243 }
1244
1245 if (mListener != null) {
Rekha Kumar14631742015-02-04 10:47:00 -08001246 mListener.onImsProgressing();
1247 }
1248 }
1249
1250 @Override
1251 public void registrationDisconnected(ImsReasonInfo imsReasonInfo) {
1252 if (DBG) {
1253 log("registrationDisconnected :: imsReasonInfo" + imsReasonInfo);
1254 }
1255
1256 if (mListener != null) {
1257 mListener.onImsDisconnected(imsReasonInfo);
Wink Savilleef36ef62014-06-11 08:39:38 -07001258 }
1259 }
1260
1261 @Override
1262 public void registrationResumed() {
1263 if (DBG) {
1264 log("registrationResumed ::");
1265 }
1266
1267 if (mListener != null) {
1268 mListener.onImsResumed();
1269 }
1270 }
1271
1272 @Override
1273 public void registrationSuspended() {
1274 if (DBG) {
1275 log("registrationSuspended ::");
1276 }
1277
1278 if (mListener != null) {
1279 mListener.onImsSuspended();
1280 }
1281 }
1282
1283 @Override
1284 public void registrationServiceCapabilityChanged(int serviceClass, int event) {
1285 log("registrationServiceCapabilityChanged :: serviceClass=" +
1286 serviceClass + ", event=" + event);
1287
1288 if (mListener != null) {
1289 mListener.onImsConnected();
1290 }
1291 }
ram7da5a112014-07-16 20:59:27 +05301292
1293 @Override
1294 public void registrationFeatureCapabilityChanged(int serviceClass,
1295 int[] enabledFeatures, int[] disabledFeatures) {
1296 log("registrationFeatureCapabilityChanged :: serviceClass=" +
1297 serviceClass);
Libin.Tang@motorola.come2296782014-08-19 14:20:01 -05001298 if (mListener != null) {
1299 mListener.onFeatureCapabilityChanged(serviceClass,
1300 enabledFeatures, disabledFeatures);
1301 }
ram7da5a112014-07-16 20:59:27 +05301302 }
1303
Shriram Ganeshd3adfad2015-05-31 10:06:15 -07001304 @Override
1305 public void voiceMessageCountUpdate(int count) {
1306 log("voiceMessageCountUpdate :: count=" + count);
1307
1308 if (mListener != null) {
1309 mListener.onVoiceMessageCountChanged(count);
1310 }
1311 }
1312
Wink Savilleef36ef62014-06-11 08:39:38 -07001313 }
Uma Maheswari Ramalingam4f2161d2014-07-31 16:01:47 -07001314 /**
1315 * Gets the ECBM interface to request ECBM exit.
1316 *
1317 * @param serviceId a service id which is obtained from {@link ImsManager#open}
1318 * @return the ECBM interface instance
1319 * @throws ImsException if getting the ECBM interface results in an error
1320 */
1321 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException {
1322 if (mEcbm == null) {
1323 checkAndThrowExceptionIfServiceUnavailable();
1324
1325 try {
1326 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId);
1327
1328 if (iEcbm == null) {
1329 throw new ImsException("getEcbmInterface()",
1330 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED);
1331 }
1332 mEcbm = new ImsEcbm(iEcbm);
1333 } catch (RemoteException e) {
1334 throw new ImsException("getEcbmInterface()", e,
1335 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
1336 }
1337 }
1338 return mEcbm;
1339 }
Pavel Zhamaitsiakd2969f52015-11-10 14:36:44 -08001340
1341 /**
1342 * Resets ImsManager settings back to factory defaults.
1343 *
1344 * @hide
1345 */
1346 public static void factoryReset(Context context) {
1347 // Set VoLTE to default
1348 android.provider.Settings.Global.putInt(context.getContentResolver(),
1349 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED,
1350 ImsConfig.FeatureValueConstants.ON);
1351
1352 // Set VoWiFi to default
1353 android.provider.Settings.Global.putInt(context.getContentResolver(),
1354 android.provider.Settings.Global.WFC_IMS_ENABLED,
1355 ImsConfig.FeatureValueConstants.OFF);
1356
1357 // Set VoWiFi mode to default
1358 android.provider.Settings.Global.putInt(context.getContentResolver(),
1359 android.provider.Settings.Global.WFC_IMS_MODE,
1360 ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED);
1361
1362 // Set VoWiFi roaming to default
1363 android.provider.Settings.Global.putInt(context.getContentResolver(),
1364 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED,
1365 ImsConfig.FeatureValueConstants.OFF);
1366
1367 // Set VT to default
1368 SharedPreferences sharedPrefs =
1369 PreferenceManager.getDefaultSharedPreferences(context);
1370 SharedPreferences.Editor editor = sharedPrefs.edit();
1371 editor.putBoolean(PREF_ENABLE_VIDEO_CALLING_KEY, true);
1372 editor.commit();
1373
1374 // Push settings to ImsConfig
1375 ImsManager.updateImsServiceConfig(context,
1376 SubscriptionManager.getDefaultVoicePhoneId(), true);
1377 }
Jack Yu2f102bd2015-12-28 15:31:48 -08001378
1379 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1380 pw.println("ImsManager:");
1381 pw.println(" mPhoneId = " + mPhoneId);
1382 pw.println(" mConfigUpdated = " + mConfigUpdated);
1383 pw.println(" mImsService = " + mImsService);
1384
1385 pw.println(" isGbaValid = " + isGbaValid(mContext));
1386 pw.println(" isImsTurnOffAllowed = " + isImsTurnOffAllowed());
1387 pw.println(" isNonTtyOrTtyOnVolteEnabled = " + isNonTtyOrTtyOnVolteEnabled(mContext));
1388
1389 pw.println(" isVolteEnabledByPlatform = " + isVolteEnabledByPlatform(mContext));
1390 pw.println(" isVolteProvisionedOnDevice = " + isVolteProvisionedOnDevice(mContext));
1391 pw.println(" isEnhanced4gLteModeSettingEnabledByUser = " +
1392 isEnhanced4gLteModeSettingEnabledByUser(mContext));
1393 pw.println(" isVtEnabledByPlatform = " + isVtEnabledByPlatform(mContext));
1394 pw.println(" isVtEnabledByUser = " + isVtEnabledByUser(mContext));
1395
1396 pw.println(" isWfcEnabledByPlatform = " + isWfcEnabledByPlatform(mContext));
1397 pw.println(" isWfcEnabledByUser = " + isWfcEnabledByUser(mContext));
1398 pw.println(" getWfcMode = " + getWfcMode(mContext));
1399 pw.println(" isWfcRoamingEnabledByUser = " + isWfcRoamingEnabledByUser(mContext));
1400
1401 pw.flush();
1402 }
Wink Savilleef36ef62014-06-11 08:39:38 -07001403}