Add error handling for outgoing WFC calls.

+ If POWER_OFF or OUT_OF_SERVICE is returned, show more specific
error messages based on WFC config and current wifi connectivity.

Assumes that IN_SERVICE will return if a call can be made,
regardless of the transport technology being used.

Assumes that OUT_OF_SERVICE will be returned if a call can not
be made and the radio is powered on.

Assumes that POWER_OFF will be returned if a call can not be
made and the radio is powered off.

Bug: 19167571
Change-Id: I32790bd05bb33e4890ee797f9f7a5297f6f0228c
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8a15ad9..044c593 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -839,9 +839,8 @@
     <string name="simContacts_empty">No contacts on your SIM card.</string>
     <!-- Call settings: title of the dialog that lets you select contacts from the SIM. -->
     <string name="simContacts_title">Select contacts to import</string>
-    <!-- Appears when user tries to import contacts in SIM during Airplane mode
-      [CHAR LIMIT=NONE] -->
-    <string name="simContacts_airplaneMode">To import contacts from the SIM card, first turn off Airplane mode.</string>
+    <!-- Appears when user tries to import contacts in SIM during airplane mode [CHAR LIMIT=NONE] -->
+    <string name="simContacts_airplaneMode">Turn off airplane mode to import contacts from the SIM card.</string>
 
     <!-- SIM PIN strings -->
     <!-- Title of "Enable/disable SIM PIN" screen -->
@@ -994,14 +993,18 @@
          [CHAR LIMIT=60] -->
     <string name="notification_missedCall_message">Message</string>
 
-    <!-- In-call screen: call failure message displayed in an error dialog -->
-    <string name="incall_error_power_off">To place a call, first turn off Airplane mode.</string>
+    <!-- In-call screen: call failure message displayed in an error dialog. [CHAR_LIMIT=NONE] -->
+    <string name="incall_error_power_off">Turn off airplane mode to make a call.</string>
+    <!-- In-call screen: call failure message displayed in an error dialog when in airplane mode, WFC is enabled, not wifi-only, and not connected to wireless networks. [CHAR_LIMIT=NONE] -->
+    <string name="incall_error_power_off_wfc">Turn off airplane mode or connect to a wireless network to make a call.</string>
     <!-- In-call screen: call failure message displayed in an error dialog.
          This string is currently unused (see comments in InCallScreen.java.) -->
     <string name="incall_error_emergency_only">Not registered on network.</string>
     <!-- In-call screen: call failure message displayed in an error dialog -->
     <string name="incall_error_out_of_service">Cellular network not available.</string>
     <!-- In-call screen: call failure message displayed in an error dialog -->
+    <string name="incall_error_out_of_service_wfc">Cellular network is not available. Connect to a wireless network to make a call.</string>
+    <!-- In-call screen: call failure message displayed in an error dialog -->
     <string name="incall_error_no_phone_number_supplied">To place a call, enter a valid number.</string>
     <!-- In-call screen: call failure message displayed in an error dialog -->
     <string name="incall_error_call_failed">Can\'t call.</string>
@@ -1021,6 +1024,8 @@
     <string name="incall_error_supp_service_reject">Can\'t reject call.</string>
     <!-- In-call screen: message displayed in an error dialog -->
     <string name="incall_error_supp_service_hangup">Can\'t release call(s).</string>
+    <!-- In-call screen: call failure message displayed in an error dialog when WFC is enabled, is wifi-only, and not connected to a wireless network. [CHAR_LIMIT=NONE] -->
+    <string name="incall_error_wfc_only_no_wireless_network">Connect to a wireless network to make a call.</string>
 
     <!-- Dialog title for the "radio enable" UI for emergency calls -->
     <string name="emergency_enable_radio_dialog_title">Emergency call</string>
diff --git a/src/com/android/phone/ImsUtil.java b/src/com/android/phone/ImsUtil.java
index c3d780b..868a0f1 100644
--- a/src/com/android/phone/ImsUtil.java
+++ b/src/com/android/phone/ImsUtil.java
@@ -16,9 +16,16 @@
 
 package com.android.phone;
 
+import android.content.Context;
+import android.util.Log;
+
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsManager;
 import com.android.phone.PhoneGlobals;
 
 public class ImsUtil {
+    private static final String LOG_TAG = ImsUtil.class.getSimpleName();
+    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
 
     private static boolean sImsPhoneSupported = false;
 
@@ -31,10 +38,32 @@
     }
 
     /**
-     * @return true if this device supports voice calls using the built-in SIP stack.
+     * @return {@code true} if this device supports voice calls using the built-in SIP stack.
      */
     static boolean isImsPhoneSupported() {
         return sImsPhoneSupported;
 
     }
+
+    /**
+     * @return {@code true} if WFC is supported by the platform and has been enabled by the user.
+     */
+    public static boolean isWfcEnabled(Context context) {
+        boolean isEnabledByPlatform = ImsManager.isWfcEnabledByPlatform(context);
+        boolean isEnabledByUser = ImsManager.isWfcEnabledByUser(context);
+        if (DBG) Log.d(LOG_TAG, "isWfcEnabled :: isEnabledByPlatform=" + isEnabledByPlatform);
+        if (DBG) Log.d(LOG_TAG, "isWfcEnabled :: isEnabledByUser=" + isEnabledByUser);
+        return isEnabledByPlatform && isEnabledByUser;
+    }
+
+    /**
+     * @return {@code true} if the device is configured to use "Wi-Fi only" mode. If WFC is not
+     * enabled, this will return {@code false}.
+     */
+    public static boolean isWfcModeWifiOnly(Context context) {
+        boolean isWifiOnlyMode =
+                ImsManager.getWfcMode(context) == ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY;
+        if (DBG) Log.d(LOG_TAG, "isWfcModeWifiOnly :: isWifiOnlyMode" + isWifiOnlyMode);
+        return isWfcEnabled(context) && isWifiOnlyMode;
+    }
 }
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 0e9c0d0..aaaf7db 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -22,6 +22,7 @@
 
 import com.android.phone.PhoneGlobals;
 import com.android.phone.common.R;
+import com.android.phone.ImsUtil;
 
 public class DisconnectCauseUtil {
 
@@ -254,15 +255,18 @@
                 break;
 
             case android.telephony.DisconnectCause.POWER_OFF:
-                // Radio is explictly powered off, presumably because the
-                // device is in airplane mode.
-                //
-                // TODO: For now this UI is ultra-simple: we simply display
-                // a message telling the user to turn off airplane mode.
-                // But it might be nicer for the dialog to offer the option
-                // to turn the radio on right there (and automatically retry
-                // the call once network registration is complete.)
-                resourceId = R.string.incall_error_power_off;
+                // Radio is explictly powered off because the device is in airplane mode.
+
+                // TODO: Offer the option to turn the radio on, and automatically retry the call
+                // once network registration is complete.
+
+                if (ImsUtil.isWfcModeWifiOnly(context)) {
+                    resourceId = R.string.incall_error_wfc_only_no_wireless_network;
+                } else if (ImsUtil.isWfcEnabled(context)) {
+                    resourceId = R.string.incall_error_power_off_wfc;
+                } else {
+                    resourceId = R.string.incall_error_power_off;
+                }
                 break;
 
             case android.telephony.DisconnectCause.EMERGENCY_ONLY:
@@ -273,7 +277,13 @@
 
             case android.telephony.DisconnectCause.OUT_OF_SERVICE:
                 // No network connection.
-                resourceId = R.string.incall_error_out_of_service;
+                if (ImsUtil.isWfcModeWifiOnly(context)) {
+                    resourceId = R.string.incall_error_wfc_only_no_wireless_network;
+                } else if (ImsUtil.isWfcEnabled(context)) {
+                    resourceId = R.string.incall_error_out_of_service_wfc;
+                } else {
+                    resourceId = R.string.incall_error_out_of_service;
+                }
                 break;
 
             case android.telephony.DisconnectCause.NO_PHONE_NUMBER_SUPPLIED: