Merge "IMS: Update user preferred TTY mode always for UI TTY setting" into mm-wireless-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2d449ad..9e89f68 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -497,7 +497,12 @@
         </service>
 
         <!-- service to dump telephony information -->
-        <service android:name="TelephonyDebugService" />
+        <service android:name="com.android.phone.TelephonyDebugService"
+                 android:permission="android.permission.DUMP">
+            <intent-filter>
+                <action android:name="com.android.phone.TelephonyDebugService" />
+            </intent-filter>
+        </service>
 
         <activity android:name="EmergencyCallbackModeExitDialog"
             android:excludeFromRecents="true"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d71025d..80c7e22 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -986,6 +986,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: message displayed in an error dialog -->
+    <string name="incall_error_supp_service_hold">Can\'t hold calls.</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>
 
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index dd1eaab..93f9875 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -917,6 +917,9 @@
             if (DBG) log("onSuppServiceFailed: displaying merge failure message");
             mergeFailedString = mApplication.getResources().getString(
                     R.string.incall_error_supp_service_switch);
+        } else if (r.result == Phone.SuppService.HOLD) {
+            mergeFailedString = mApplication.getResources().getString(
+                    R.string.incall_error_supp_service_hold);
         }
         PhoneDisplayMessage.displayErrorMessage(mApplication, mergeFailedString);
 
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 780f76b..65c8c2a 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -206,7 +206,7 @@
         CarrierConfigManager configMgr =
                 (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE);
         PersistableBundle carrierConfig =
-                configMgr.getConfigForSubId(SubscriptionManager.getDefaultVoiceSubId());
+                configMgr.getConfigForSubId(SubscriptionManager.getDefaultVoiceSubscriptionId());
         if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL)) {
             mDialButton.setOnClickListener(this);
         } else {
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index b73b4bc..1b4e648 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -506,7 +506,7 @@
     }
 
     public PersistableBundle getCarrierConfig() {
-        return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubId());
+        return getCarrierConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
     }
 
     public PersistableBundle getCarrierConfigForSubId(int subId) {
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 6f828db..32dbfde 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -739,6 +739,10 @@
                             loge("queryModemActivityInfo: Unknown exception");
                         }
                     }
+                    // Result cannot be null. Return ModemActivityInfo with all fields set to 0.
+                    if (request.result == null) {
+                        request.result = new ModemActivityInfo(0, 0, 0, null, 0, 0);
+                    }
                     synchronized (request) {
                         request.notifyAll();
                     }
diff --git a/src/com/android/phone/TelephonyDebugService.java b/src/com/android/phone/TelephonyDebugService.java
index 04ebec2..8ec76a2 100644
--- a/src/com/android/phone/TelephonyDebugService.java
+++ b/src/com/android/phone/TelephonyDebugService.java
@@ -18,22 +18,20 @@
 
 import com.android.internal.telephony.DebugService;
 import com.android.internal.telephony.ITelephonyDebug;
-import com.android.internal.telephony.TelephonyEventLog;
+import com.android.internal.telephony.ITelephonyDebugSubscriber;
+import com.android.internal.telephony.TelephonyEvent;
 
 import android.app.Service;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.util.Log;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Formatter;
 import java.util.List;
-import java.util.Locale;
-
-import static com.android.internal.telephony.RILConstants.*;
 
 /**
  * A debug service for telephony.
@@ -44,52 +42,6 @@
     private static final boolean VDBG = true;
     private DebugService mDebugService = new DebugService();
 
-    public static final String JSON_KEY_TAG = "tag";
-    public static final String JSON_KEY_REG_STATE = "reg-state";
-    public static final String JSON_KEY_DATA_REG_STATE = "data-reg-state";
-    public static final String JSON_KEY_ROAMING_TYPE = "roaming-type";
-    public static final String JSON_KEY_DATA_ROAMING_TYPE = "data-roaming-type";
-    public static final String JSON_KEY_OPERATOR_ALPHA_LONG = "operator-alpha-long";
-    public static final String JSON_KEY_OPERATOR_ALPHA_SHORT = "operator-alpha-short";
-    public static final String JSON_KEY_OPERATOR_NUMERIC = "operator-numeric";
-    public static final String JSON_KEY_DATA_OPERATOR_ALPHA_LONG = "data-operator-alpha-long";
-    public static final String JSON_KEY_DATA_OPERATOR_ALPHA_SHORT = "data-operator-alpha-short";
-    public static final String JSON_KEY_DATA_OPERATOR_NUMERIC = "data-operator-numeric";
-    public static final String JSON_KEY_RAT = "rat";
-    public static final String JSON_KEY_DATA_RAT = "data-rat";
-    public static final String JSON_KEY_STATE = "state";
-    public static final String JSON_KEY_REASON_INFO = "reason_info";
-    public static final String JSON_KEY_REASON_INFO_CODE = "code";
-    public static final String JSON_KEY_REASON_INFO_EXTRA_CODE = "extra_code";
-    public static final String JSON_KEY_REASON_INFO_EXTRA_MESSAGE = "extra_message";
-    public static final String JSON_KEY_VOLTE = "VoLTE";
-    public static final String JSON_KEY_VILTE = "ViLTE";
-    public static final String JSON_KEY_VOWIFI = "VoWiFi";
-    public static final String JSON_KEY_VIWIFI = "ViWiFi";
-    public static final String JSON_KEY_UTLTE = "UTLTE";
-    public static final String JSON_KEY_UTWIFI = "UTWiFi";
-    public static final String JSON_KEY_DATA_CALLS = "data-calls";
-    public static final String JSON_KEY_STATUS = "status";
-    public static final String JSON_KEY_CID = "cid";
-    public static final String JSON_KEY_ACTIVE = "active";
-    public static final String JSON_KEY_TYPE = "type";
-    public static final String JSON_KEY_IFNAME = "ifname";
-    public static final String JSON_KEY_SERIAL = "serial";
-    public static final String JSON_KEY_PROFILE = "profile";
-    public static final String JSON_KEY_APN = "apn";
-    public static final String JSON_KEY_PROTOCOL = "protocol";
-    public static final String JSON_KEY_REASON = "reason";
-    public static final String JSON_KEY_CLIR_MODE = "clirMode";
-    public static final String JSON_KEY_EVT = "evt";
-    public static final String JSON_KEY_GSM_INDEX = "gsmIndex";
-    public static final String JSON_KEY_RETRY = "retry";
-    public static final String JSON_KEY_SMS_MESSAGE_REF = "messageRef";
-    public static final String JSON_KEY_SMS_ERROR_CODE = "errorCode";
-    public static final String JSON_KEY_RIL_ERROR = "error";
-    public static final String JSON_KEY_CALL_ID = "call-id";
-    public static final String JSON_KEY_SRC_TECH = "src-tech";
-    public static final String JSON_KEY_TARGET_TECH = "target-tech";
-
     /** Constructor */
     public TelephonyDebugService() {
         if (DBG) Log.d(TAG, "TelephonyDebugService()");
@@ -106,489 +58,82 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        boolean dumpEvents = false;
-        if (args != null) {
-            for (String arg : args) {
-                if ("--events".equals(arg)) {
-                    dumpEvents = true;
-                } else if ("--reset-events".equals(arg)) {
-                    synchronized (mEvents) {
-                        mEvents.clear();
-                    }
-                    pw.println("TelephonyDebugService reset.");
-                    return;
-                } else if ("-h".equals(arg)) {
-                    dumpHelp(pw);
-                    return;
-                } else {
-                    pw.println("Unknown option: " + arg);
-                    dumpHelp(pw);
-                    return;
-                }
-            }
-        }
-
-        if (dumpEvents) {
-            synchronized (mEvents) {
-                pw.println("{\"version\": \"1.0\"," +
-                        "\"events\": [");
-                for (Event e : mEvents) {
-                    pw.println(e.toJson());
-                }
-                pw.println("]}");
-            }
-        } else {
-            mDebugService.dump(fd, pw, args);
-        }
+        mDebugService.dump(fd, pw, args);
     }
 
-    private static void dumpHelp(PrintWriter pw) {
-        pw.println("TelephonyDebugService dump options:");
-        pw.println("  [--events] [--reset-events] [-h]");
-        pw.println("  --events: dump events in JSON format.");
-        pw.println("  --reset-events: reset the stats, clearing all current data.");
-        pw.println("  -h: print this help text.");
-    }
-
-    class Event {
-
-        public static final String JSON_TAG_SETTINGS = "SETTINGS";
-        public static final String JSON_TAG_SERVICE_STATE = "SERVICE_STATE";
-        public static final String JSON_TAG_IMS_CONNECTION_STATE = "IMS_CONNECTION_STATE";
-        public static final String JSON_TAG_IMS_CAPABILITIES = "IMS_CAPABILITIES";
-        public static final String JSON_TAG_DATA_CALL_LIST = "DATA_CALL_LIST";
-        public static final String JSON_TAG_RIL_REQUEST_SETUP_DATA_CALL
-                = "RIL_REQUEST_SETUP_DATA_CALL";
-        public static final String JSON_TAG_RIL_REQUEST_DEACTIVATE_DATA_CALL
-                = "RIL_REQUEST_DEACTIVATE_DATA_CALL";
-        public static final String JSON_TAG_RIL_REQUEST_DIAL = "RIL_REQUEST_DIAL";
-        public static final String JSON_TAG_RIL_REQUEST_HANGUP = "RIL_REQUEST_HANGUP";
-        public static final String JSON_TAG_RIL_REQUEST_ANSWER = "RIL_REQUEST_ANSWER";
-        public static final String JSON_TAG_RIL_REQUEST_SEND_SMS = "RIL_REQUEST_SEND_SMS";
-        public static final String JSON_TAG_RIL_RESPONSE_SETUP_DATA_CALL
-                = "RIL_RESPONSE_SETUP_DATA_CALL";
-        public static final String JSON_TAG_RIL_UNSOL_CALL_RING = "RIL_UNSOL_CALL_RING";
-        public static final String JSON_TAG_RIL_UNSOL_SRVCC_STATE_NOTIFY
-                = "RIL_UNSOL_SRVCC_STATE_NOTIFY";
-        public static final String JSON_TAG_RIL_UNSOL_RESPONSE_NEW_SMS
-                = "RIL_UNSOL_RESPONSE_NEW_SMS";
-        public static final String JSON_TAG_RIL_UNSOL_RESPONSE_CDMA_NEW_SMS
-                = "RIL_UNSOL_RESPONSE_CDMA_NEW_SMS";
-        public static final String JSON_TAG_IMS_CALL = "IMS_CALL";
-        public static final String JSON_TAG_IMS_CALL_HANDOVER = "IMS_CALL_HANDOVER";
-        public static final String JSON_TAG_IMS_CALL_STATE = "IMS_CALL_STATE";
-        public static final String JSON_TAG_PHONE_STATE = "PHONE_STATE";
-        public static final String JSON_TAG_SMS = "SMS";
-
-        public long timestamp;
-        public int phoneId;
-        public int tag;
-        public int param1;
-        public int param2;
-        public Bundle data;
-
-        public Event(long timestamp, int phoneId, int tag, int param1, int param2, Bundle data) {
-            this.timestamp = timestamp;
-            this.phoneId = phoneId;
-            this.tag = tag;
-            this.param1 = param1;
-            this.param2 = param2;
-            this.data = data;
-        }
-
-        public String imsCallEventToString(int evt) {
-            switch (evt) {
-                case TelephonyEventLog.TAG_IMS_CALL_START: return "START";
-                case TelephonyEventLog.TAG_IMS_CALL_START_CONFERENCE: return "START_CONFERENCE";
-                case TelephonyEventLog.TAG_IMS_CALL_RECEIVE: return "RECEIVE";
-                case TelephonyEventLog.TAG_IMS_CALL_ACCEPT: return "ACCEPT";
-                case TelephonyEventLog.TAG_IMS_CALL_REJECT: return "REJECT";
-                case TelephonyEventLog.TAG_IMS_CALL_TERMINATE: return "TERMINATE";
-                case TelephonyEventLog.TAG_IMS_CALL_HOLD: return "HOLD";
-                case TelephonyEventLog.TAG_IMS_CALL_RESUME: return "RESUME";
-                case TelephonyEventLog.TAG_IMS_CALL_MERGE: return "MERGE";
-                case TelephonyEventLog.TAG_IMS_CALL_UPDATE: return "UPDATE";
-                case TelephonyEventLog.TAG_IMS_CALL_PROGRESSING: return "PROGRESSING";
-                case TelephonyEventLog.TAG_IMS_CALL_STARTED: return "STARTED";
-                case TelephonyEventLog.TAG_IMS_CALL_START_FAILED: return "START_FAILED";
-                case TelephonyEventLog.TAG_IMS_CALL_TERMINATED: return "TERMINATED";
-                case TelephonyEventLog.TAG_IMS_CALL_HELD: return "HELD";
-                case TelephonyEventLog.TAG_IMS_CALL_HOLD_FAILED: return "HOLD_FAILED";
-                case TelephonyEventLog.TAG_IMS_CALL_HOLD_RECEIVED: return "HOLD_RECEIVED";
-                case TelephonyEventLog.TAG_IMS_CALL_RESUMED: return "RESUMED";
-                case TelephonyEventLog.TAG_IMS_CALL_RESUME_FAILED: return "RESUME_FAILED";
-                case TelephonyEventLog.TAG_IMS_CALL_RESUME_RECEIVED: return "RESUME_RECEIVED";
-                case TelephonyEventLog.TAG_IMS_CALL_UPDATED: return "UPDATED";
-                case TelephonyEventLog.TAG_IMS_CALL_UPDATE_FAILED: return "UPDATE_FAILED";
-                case TelephonyEventLog.TAG_IMS_CALL_MERGED: return "MERGED";
-                case TelephonyEventLog.TAG_IMS_CALL_MERGE_FAILED: return "MERGE_FAILED";
-                case TelephonyEventLog.TAG_IMS_CALL_HANDOVER: return "HANDOVER";
-                case TelephonyEventLog.TAG_IMS_CALL_HANDOVER_FAILED: return "HANDOVER_FAILED";
-                case TelephonyEventLog.TAG_IMS_CALL_TTY_MODE_RECEIVED: return "TTY_MODE_RECEIVED";
-                case TelephonyEventLog.TAG_IMS_CONFERENCE_PARTICIPANTS_STATE_CHANGED:
-                    return "CONFERENCE_PARTICIPANTS_STATE_CHANGED";
-                case TelephonyEventLog.TAG_IMS_MULTIPARTY_STATE_CHANGED:
-                    return "MULTIPARTY_STATE_CHANGED";
-                case TelephonyEventLog.TAG_IMS_CALL_STATE: return "STATE";
-            }
-            return "UNKNOWN("+evt+")";
-        }
-
-        public String rilResponseToString(int evt) {
-            switch (evt) {
-                case RIL_REQUEST_DEACTIVATE_DATA_CALL: return "RIL_RESPONSE_DEACTIVATE_DATA_CALL";
-                case RIL_REQUEST_HANGUP: return "RIL_RESPONSE_HANGUP";
-                case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: return "RIL_RESPONSE_HANGUP_WAITING_OR_BACKGROUND";
-                case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: return "RIL_RESPONSE_HANGUP_FOREGROUND_RESUME_BACKGROUND";
-                case RIL_REQUEST_DIAL: return "RIL_RESPONSE_DIAL";
-                case RIL_REQUEST_ANSWER: return "RIL_RESPONSE_ANSWER";
-                case RIL_REQUEST_SEND_SMS: return "RIL_RESPONSE_SEND_SMS";
-                case RIL_REQUEST_SEND_SMS_EXPECT_MORE: return "RIL_RESPONSE_SEND_SMS_EXPECT_MORE";
-                case RIL_REQUEST_CDMA_SEND_SMS: return "RIL_RESPONSE_CDMA_SEND_SMS";
-                case RIL_REQUEST_IMS_SEND_SMS: return "RIL_RESPONSE_IMS_SEND_SMS";
-            }
-            return "UNKNOWN("+evt+")";
-        }
-
-        public String toString() {
-            return String.format("%d,%d,%d,%d,%d,%s",
-                    timestamp, phoneId, tag, param1, param2, data);
-        }
-
-        public String toJson() {
-            StringBuilder sb = new StringBuilder();
-            Formatter formatter = new Formatter(sb, Locale.US);
-            formatter.format("{\"ts\":%d, \"phone\":%d", timestamp, phoneId);
-            switch (tag) {
-                case TelephonyEventLog.TAG_SETTINGS:
-                    formatter.format(", \"%s\":\"%s\"", JSON_KEY_TAG, JSON_TAG_SETTINGS);
-                    break;
-
-                case TelephonyEventLog.TAG_SERVICE_STATE:
-                    serviceStateToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_IMS_CONNECTION_STATE:
-                    imsConnectionStateToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_IMS_CAPABILITIES:
-                    imsCapabilitiesToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_DATA_CALL_LIST:
-                    dataCallListToJson(sb, formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_RIL_REQUEST:
-                    rilRequestToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_RIL_RESPONSE:
-                    rilResponseToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_RIL_UNSOL_RESPONSE:
-                    unsolRilResponseToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_IMS_CALL_START:
-                case TelephonyEventLog.TAG_IMS_CALL_START_CONFERENCE:
-                case TelephonyEventLog.TAG_IMS_CALL_RECEIVE:
-                case TelephonyEventLog.TAG_IMS_CALL_ACCEPT:
-                case TelephonyEventLog.TAG_IMS_CALL_REJECT:
-                case TelephonyEventLog.TAG_IMS_CALL_TERMINATE:
-                case TelephonyEventLog.TAG_IMS_CALL_HOLD:
-                case TelephonyEventLog.TAG_IMS_CALL_RESUME:
-                case TelephonyEventLog.TAG_IMS_CALL_PROGRESSING:
-                case TelephonyEventLog.TAG_IMS_CALL_STARTED:
-                case TelephonyEventLog.TAG_IMS_CALL_START_FAILED:
-                case TelephonyEventLog.TAG_IMS_CALL_TERMINATED:
-                case TelephonyEventLog.TAG_IMS_CALL_HELD:
-                case TelephonyEventLog.TAG_IMS_CALL_HOLD_RECEIVED:
-                case TelephonyEventLog.TAG_IMS_CALL_HOLD_FAILED:
-                case TelephonyEventLog.TAG_IMS_CALL_RESUMED:
-                case TelephonyEventLog.TAG_IMS_CALL_RESUME_RECEIVED:
-                case TelephonyEventLog.TAG_IMS_CALL_RESUME_FAILED:
-                    imsCallEventToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_IMS_CALL_HANDOVER:
-                case TelephonyEventLog.TAG_IMS_CALL_HANDOVER_FAILED:
-                    imsHandoverToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_IMS_CALL_STATE:
-                    imsCallStateToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_PHONE_STATE:
-                    phoneStateToJson(formatter);
-                    break;
-
-                case TelephonyEventLog.TAG_SMS:
-                    formatter.format(", \"%s\":\"%s\"", JSON_KEY_TAG, JSON_TAG_SMS);
-                    break;
-
-                default:
-                    formatter.format(", \"%s\":\"UNKNOWN(%d)\"", JSON_KEY_TAG, tag);
-                    break;
-            }
-            sb.append("},");
-            return sb.toString();
-        }
-
-        private void serviceStateToJson(Formatter formatter) {
-            formatter.format(", \"%s\":\"%s\""
-                            + ",\"%s\":%d,\"%s\":%d,\"%s\":%d,\"%s\":%d"
-                            + ",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\""
-                            + ",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\""
-                            + ",\"%s\":%d,\"%s\":%d",
-                    JSON_KEY_TAG, JSON_TAG_SERVICE_STATE,
-                    JSON_KEY_REG_STATE, data.getInt("voiceRegState"),
-                    JSON_KEY_DATA_REG_STATE, data.getInt("dataRegState"),
-                    JSON_KEY_ROAMING_TYPE, data.getInt("voiceRoamingType"),
-                    JSON_KEY_DATA_ROAMING_TYPE, data.getInt("dataRoamingType"),
-                    JSON_KEY_OPERATOR_ALPHA_LONG, data.getString("operator-alpha-long"),
-                    JSON_KEY_OPERATOR_ALPHA_SHORT, data.getString("operator-alpha-short"),
-                    JSON_KEY_OPERATOR_NUMERIC, data.getString("operator-numeric"),
-                    JSON_KEY_DATA_OPERATOR_ALPHA_LONG, data.getString("data-operator-alpha-long"),
-                    JSON_KEY_DATA_OPERATOR_ALPHA_SHORT, data.getString("data-operator-alpha-short"),
-                    JSON_KEY_DATA_OPERATOR_NUMERIC, data.getString("data-operator-numeric"),
-                    JSON_KEY_RAT, data.getInt("radioTechnology"),
-                    JSON_KEY_DATA_RAT, data.getInt("dataRadioTechnology"));
-        }
-
-        private void imsConnectionStateToJson(Formatter formatter) {
-            if (data == null) {
-                formatter.format(", \"%s\":\"%s\", \"%s\":%d",
-                        JSON_KEY_TAG, JSON_TAG_IMS_CONNECTION_STATE, JSON_KEY_STATE, param1);
-            } else {
-                formatter.format(", \"%s\":\"%s\""
-                                + ", \"%s\":%d"
-                                + ", \"%s\":{\"%s\":%d,\"%s\":%d,\"%s\":%s}",
-                        JSON_KEY_TAG, JSON_TAG_IMS_CONNECTION_STATE,
-                        JSON_KEY_STATE, param1,
-                        JSON_KEY_REASON_INFO,
-                        JSON_KEY_REASON_INFO_CODE, data.getInt(
-                                TelephonyEventLog.DATA_KEY_REASONINFO_CODE),
-                        JSON_KEY_REASON_INFO_EXTRA_CODE, data.getInt(
-                                TelephonyEventLog.DATA_KEY_REASONINFO_EXTRA_CODE),
-                        JSON_KEY_REASON_INFO_EXTRA_MESSAGE, data.getString(
-                                TelephonyEventLog.DATA_KEY_REASONINFO_EXTRA_MESSAGE));
-            }
-        }
-
-        private void imsCapabilitiesToJson(Formatter formatter) {
-            formatter.format(", \"%s\":\"%s\""
-                            + ",\"%s\":%b,\"%s\":%b,\"%s\":%b"
-                            + ",\"%s\":%b,\"%s\":%b,\"%s\":%b",
-                    JSON_KEY_TAG, JSON_TAG_IMS_CAPABILITIES,
-                    JSON_KEY_VOLTE, data.getBoolean(TelephonyEventLog.DATA_KEY_VOLTE),
-                    JSON_KEY_VILTE, data.getBoolean(TelephonyEventLog.DATA_KEY_VILTE),
-                    JSON_KEY_VOWIFI, data.getBoolean(TelephonyEventLog.DATA_KEY_VOWIFI),
-                    JSON_KEY_VIWIFI, data.getBoolean(TelephonyEventLog.DATA_KEY_VIWIFI),
-                    JSON_KEY_UTLTE, data.getBoolean(TelephonyEventLog.DATA_KEY_UTLTE),
-                    JSON_KEY_UTWIFI, data.getBoolean(TelephonyEventLog.DATA_KEY_UTWIFI));
-        }
-
-        private void dataCallListToJson(StringBuilder sb, Formatter formatter) {
-            formatter.format(", \"%s\":\"%s\",\"%s\":[",
-                    JSON_KEY_TAG, JSON_TAG_DATA_CALL_LIST, JSON_KEY_DATA_CALLS);
-            int[] statuses = data.getIntArray(TelephonyEventLog.DATA_KEY_DATA_CALL_STATUSES);
-            int[] cids = data.getIntArray(TelephonyEventLog.DATA_KEY_DATA_CALL_CIDS);
-            int[] actives = data.getIntArray(TelephonyEventLog.DATA_KEY_DATA_CALL_ACTIVES);
-            String[] types = data.getStringArray(TelephonyEventLog.DATA_KEY_DATA_CALL_TYPES);
-            String[] ifnames = data.getStringArray(TelephonyEventLog.DATA_KEY_DATA_CALL_IFNAMES);
-            for (int i = 0; i < cids.length; i++) {
-                formatter.format("{\"%s\":%d,\"%s\":%d,\"%s\":%d"
-                                + ",\"%s\":\"%s\",\"%s\":\"%s\"},",
-                        JSON_KEY_STATUS, statuses[i], JSON_KEY_CID, cids[i],
-                        JSON_KEY_ACTIVE, actives[i],
-                        JSON_KEY_TYPE, types[i], JSON_KEY_IFNAME, ifnames[i]);
-            }
-            sb.append("]");
-        }
-
-        private void rilRequestToJson(Formatter formatter) {
-            switch (param1) {
-                case RIL_REQUEST_SETUP_DATA_CALL:
-                    formatter.format(", \"%s\":\"%s\""
-                                    + ",\"%s\":%d,\"%s\":\"%s\",\"%s\":\"%s\""
-                                    + ",\"%s\":\"%s\",\"%s\":\"%s\"",
-                            JSON_KEY_TAG, JSON_TAG_RIL_REQUEST_SETUP_DATA_CALL,
-                            JSON_KEY_SERIAL, param2,
-                            JSON_KEY_RAT, data.getString(
-                                    TelephonyEventLog.DATA_KEY_RAT),
-                            JSON_KEY_PROFILE, data.getString(
-                                    TelephonyEventLog.DATA_KEY_DATA_PROFILE),
-                            JSON_KEY_APN, data.getString(
-                                    TelephonyEventLog.DATA_KEY_APN),
-                            JSON_KEY_PROTOCOL, data.getString(
-                                    TelephonyEventLog.DATA_KEY_PROTOCOL));
-                    break;
-                case RIL_REQUEST_DEACTIVATE_DATA_CALL:
-                    formatter.format(", \"%s\":\"%s\""
-                                    + ",\"%s\":%d,\"%s\":%d,\"%s\":%d",
-                            JSON_KEY_TAG, JSON_TAG_RIL_REQUEST_DEACTIVATE_DATA_CALL,
-                            JSON_KEY_SERIAL, param2,
-                            JSON_KEY_CID, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_DATA_CALL_CID),
-                            JSON_KEY_REASON, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_DATA_DEACTIVATE_REASON));
-                    break;
-                case RIL_REQUEST_DIAL:
-                    formatter.format(", \"%s\":\"%s\""
-                                    + ",\"%s\":%d,\"%s\":%d",
-                            JSON_KEY_TAG, JSON_TAG_RIL_REQUEST_DIAL,
-                            JSON_KEY_SERIAL, param2,
-                            JSON_KEY_CLIR_MODE, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_CLIR_MODE));
-                    break;
-                case RIL_REQUEST_HANGUP:
-                case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
-                case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
-                    formatter.format(", \"%s\":\"%s\""
-                                    + ",\"%s\":%d, \"%s\":%d"
-                                    + ",\"%s\":\"%d\"",
-                            JSON_KEY_TAG, JSON_TAG_RIL_REQUEST_HANGUP,
-                            JSON_KEY_SERIAL, param2, JSON_KEY_EVT, param1,
-                            JSON_KEY_GSM_INDEX, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_RIL_HANGUP_GSM_INDEX));
-                    break;
-                case RIL_REQUEST_ANSWER:
-                    formatter.format(", \"%s\":\"%s\",\"%s\":%d",
-                            JSON_KEY_TAG, JSON_TAG_RIL_REQUEST_ANSWER, JSON_KEY_SERIAL, param2);
-                    break;
-
-                case RIL_REQUEST_SEND_SMS:
-                case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
-                case RIL_REQUEST_CDMA_SEND_SMS:
-                case RIL_REQUEST_IMS_SEND_SMS:
-                    formatter.format(", \"%s\":\"%s\",\"%s\":%d",
-                            JSON_KEY_TAG, JSON_TAG_RIL_REQUEST_SEND_SMS, JSON_KEY_SERIAL, param2);
-                    break;
-            }
-        }
-
-        private void rilResponseToJson(Formatter formatter) {
-            switch (param1) {
-                case RIL_REQUEST_SETUP_DATA_CALL:
-                    formatter.format(", \"%s\":\"%s\""
-                                    + ",\"%s\":%d,\"%s\":%d,\"%s\":%d"
-                                    + ",\"%s\":%d,\"%s\":%d"
-                                    + ",\"%s\":\"%s\",\"%s\":\"%s\"",
-                            JSON_KEY_TAG, JSON_TAG_RIL_RESPONSE_SETUP_DATA_CALL,
-                            JSON_KEY_SERIAL, param2,
-                            JSON_KEY_STATUS, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_DATA_CALL_STATUS),
-                            JSON_KEY_RETRY, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_DATA_CALL_RETRY),
-                            JSON_KEY_CID, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_DATA_CALL_CID),
-                            JSON_KEY_ACTIVE, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_DATA_CALL_ACTIVE),
-                            JSON_KEY_TYPE, data.getString(
-                                    TelephonyEventLog.DATA_KEY_DATA_CALL_TYPE),
-                            JSON_KEY_IFNAME, data.getString(
-                                    TelephonyEventLog.DATA_KEY_DATA_CALL_IFNAME));
-                    break;
-
-                case RIL_REQUEST_DEACTIVATE_DATA_CALL:
-                case RIL_REQUEST_HANGUP:
-                case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
-                case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
-                case RIL_REQUEST_DIAL:
-                case RIL_REQUEST_ANSWER:
-                    formatter.format(", \"%s\":\"%s\",\"%s\":%d",
-                            JSON_KEY_TAG, rilResponseToString(param1), JSON_KEY_SERIAL, param2);
-                    break;
-
-                case RIL_REQUEST_SEND_SMS:
-                case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
-                case RIL_REQUEST_CDMA_SEND_SMS:
-                case RIL_REQUEST_IMS_SEND_SMS:
-                    formatter.format(", \"%s\":\"%s\",\"%s\":%d"
-                                    + ",\"%s\":%d,\"%s\":%d",
-                            JSON_KEY_TAG, rilResponseToString(param1), JSON_KEY_SERIAL, param2,
-                            JSON_KEY_SMS_MESSAGE_REF, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_SMS_MESSAGE_REF),
-                            JSON_KEY_SMS_ERROR_CODE, data.getInt(
-                                    TelephonyEventLog.DATA_KEY_SMS_ERROR_CODE));
-                    break;
-            }
-            formatter.format(", \"%s\":%d",
-                    JSON_KEY_RIL_ERROR, data.getInt(TelephonyEventLog.DATA_KEY_RIL_ERROR));
-        }
-
-        private void unsolRilResponseToJson(Formatter formatter) {
-            switch (param1) {
-                case RIL_UNSOL_CALL_RING:
-                    formatter.format(", \"%s\":\"%s\"", JSON_KEY_TAG, JSON_TAG_RIL_UNSOL_CALL_RING);
-                    break;
-                case RIL_UNSOL_SRVCC_STATE_NOTIFY:
-                    formatter.format(", \"%s\":\"%s\",\"%s\":%d",
-                            JSON_KEY_TAG, JSON_TAG_RIL_UNSOL_SRVCC_STATE_NOTIFY,
-                            JSON_KEY_STATE, param2);
-                    break;
-                case RIL_UNSOL_RESPONSE_NEW_SMS:
-                    formatter.format(", \"%s\":\"%s\"",
-                            JSON_KEY_TAG, JSON_TAG_RIL_UNSOL_RESPONSE_NEW_SMS);
-                    break;
-                case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS:
-                    formatter.format(", \"%s\":\"%s\"",
-                            JSON_KEY_TAG, JSON_TAG_RIL_UNSOL_RESPONSE_CDMA_NEW_SMS);
-                    break;
-            }
-        }
-
-        private void imsCallEventToJson(Formatter formatter) {
-            formatter.format(", \"%s\":\"%s\", \"%s\":\"%s\",\"%s\":%d",
-                    JSON_KEY_TAG, JSON_TAG_IMS_CALL, JSON_KEY_EVT, imsCallEventToString(tag),
-                    JSON_KEY_CALL_ID, param1);
-        }
-
-        private void imsHandoverToJson(Formatter formatter) {
-            formatter.format(", \"%s\":\"%s\", \"%s\":\"%s\",\"%s\":%d"
-                            + ",\"%s\":%d,\"%s\":%d"
-                            + ",\"%s\":%d,\"%s\":%d,\"%s\":\"%s\"",
-                    JSON_KEY_TAG, JSON_TAG_IMS_CALL_HANDOVER,
-                    JSON_KEY_EVT, imsCallEventToString(tag), JSON_KEY_CALL_ID, param1,
-                    JSON_KEY_SRC_TECH, data.getInt(TelephonyEventLog.DATA_KEY_SRC_TECH),
-                    JSON_KEY_TARGET_TECH, data.getInt(TelephonyEventLog.DATA_KEY_TARGET_TECH),
-                    JSON_KEY_REASON_INFO_CODE, data.getInt(
-                            TelephonyEventLog.DATA_KEY_REASONINFO_CODE),
-                    JSON_KEY_REASON_INFO_EXTRA_CODE, data.getInt(
-                            TelephonyEventLog.DATA_KEY_REASONINFO_EXTRA_CODE),
-                    JSON_KEY_REASON_INFO_EXTRA_MESSAGE, data.getString(
-                            TelephonyEventLog.DATA_KEY_REASONINFO_EXTRA_MESSAGE));
-        }
-
-        private void imsCallStateToJson(Formatter formatter) {
-            formatter.format(", \"%s\":\"%s\", \"%s\":%d, \"%s\":%d",
-                    JSON_KEY_TAG, JSON_TAG_IMS_CALL_STATE, JSON_KEY_CALL_ID, param1,
-                    JSON_KEY_STATE, param2);
-        }
-
-        private void phoneStateToJson(Formatter formatter) {
-            formatter.format(", \"%s\":\"%s\", \"%s\":%d",
-                    JSON_KEY_TAG, JSON_TAG_PHONE_STATE, JSON_KEY_STATE, param1);
-        }
-    }
-    private final List<Event> mEvents = new ArrayList<Event>();
+    private final int MAX_NUMBER_OF_EVENTS = 100;
+    private final int MIN_TIME_OFFSET = 900000; // 15 minutes
+    private final List<TelephonyEvent> mEvents = new ArrayList<TelephonyEvent>();
+    private long mLastSentEventTimeMillis = System.currentTimeMillis();
 
     /**
      * Implementation of the ITelephonyDebug interface.
      */
     private final ITelephonyDebug.Stub mBinder = new ITelephonyDebug.Stub() {
+
+        private final List<ITelephonyDebugSubscriber> mSubscribers = new ArrayList<>();
+
         public void writeEvent(long timestamp, int phoneId, int tag,
                 int param1, int param2, Bundle data) {
+            final TelephonyEvent ev = new TelephonyEvent(timestamp, phoneId, tag,
+                    param1, param2, data);
+            TelephonyEvent[] events = null;
+
             if (VDBG) {
-                Log.v(TAG, String.format("writeEvent(%d, %d, %d, %d, %d)",
-                        timestamp, phoneId, tag, param1, param2));
+                Log.v(TAG, "writeEvent(" + ev.toString() + ")");
             }
+
             synchronized (mEvents) {
-                mEvents.add(new Event(timestamp, phoneId, tag, param1, param2, data));
+                mEvents.add(ev);
+
+                final long currentTimeMillis = System.currentTimeMillis();
+                final long timeOffset = currentTimeMillis - mLastSentEventTimeMillis;
+                if (timeOffset > MIN_TIME_OFFSET
+                        || timeOffset < 0 // system time has changed
+                        || mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
+                    // batch events
+                    mLastSentEventTimeMillis = currentTimeMillis;
+                    events = new TelephonyEvent[mEvents.size()];
+                    mEvents.toArray(events);
+                    mEvents.clear();
+                }
+            }
+
+            if (events != null) {
+                synchronized (mSubscribers) {
+                    for (ITelephonyDebugSubscriber s : mSubscribers) {
+                        try {
+                            s.onEvents(events);
+                        } catch (RemoteException ex) {
+                            Log.e(TAG, "RemoteException " + ex);
+                        }
+                    }
+                }
+            }
+        }
+
+        public void subscribe(ITelephonyDebugSubscriber subscriber) {
+            if (VDBG) Log.v(TAG, "subscribe");
+            synchronized (mSubscribers) {
+                mSubscribers.add(subscriber);
+            }
+
+            synchronized (mEvents) {
+                try {
+                    // send cached events
+                    TelephonyEvent[] events = new TelephonyEvent[mEvents.size()];
+                    mEvents.toArray(events);
+                    subscriber.onEvents(events);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "RemoteException " + ex);
+                }
+            }
+        }
+
+        public void unsubscribe(ITelephonyDebugSubscriber subscriber) {
+            if (VDBG) Log.v(TAG, "unsubscribe");
+            synchronized (mSubscribers) {
+                mSubscribers.remove(subscriber);
             }
         }
     };
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 235c4b9..d7db345 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -92,6 +92,7 @@
             case android.telephony.DisconnectCause.EMERGENCY_ONLY:
             case android.telephony.DisconnectCause.FDN_BLOCKED:
             case android.telephony.DisconnectCause.LIMIT_EXCEEDED:
+            case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
                 return DisconnectCause.RESTRICTED;
 
             case android.telephony.DisconnectCause.CDMA_ACCESS_FAILURE:
@@ -324,6 +325,10 @@
                 resourceId = R.string.incall_error_missing_voicemail_number;
                 break;
 
+            case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
+                resourceId = R.string.callFailed_video_call_tty_enabled;
+                break;
+
             case android.telephony.DisconnectCause.OUTGOING_CANCELED:
                 // We don't want to show any dialog for the canceled case since the call was
                 // either canceled by the user explicitly (end-call button pushed immediately)
@@ -371,6 +376,7 @@
             case android.telephony.DisconnectCause.ERROR_UNSPECIFIED:
             case android.telephony.DisconnectCause.LOCAL:
             case android.telephony.DisconnectCause.NORMAL:
+            case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
                 return ToneGenerator.TONE_PROP_PROMPT;
 
             case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY:
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 8de6465..7556798 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -171,8 +171,8 @@
 
         @Override
         public void onConnectionCapabilitiesChanged(Connection c, int connectionCapabilities) {
-            Log.d(this, "onCallCapabilitiesChanged: Connection: %s, callCapabilities: %s", c,
-                    connectionCapabilities);
+            Log.d(this, "onConnectionCapabilitiesChanged: Connection: %s," +
+                    " connectionCapabilities: %s", c, connectionCapabilities);
             int capabilites = ImsConference.this.getConnectionCapabilities();
             setConnectionCapabilities(applyHostCapabilities(capabilites, connectionCapabilities));
         }
@@ -271,37 +271,26 @@
      * @return The merged capabilities to be applied to the conference.
      */
     private int applyHostCapabilities(int conferenceCapabilities, int capabilities) {
-        if (can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
-            conferenceCapabilities = applyCapability(conferenceCapabilities,
-                    Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
-        } else {
-            conferenceCapabilities = removeCapability(conferenceCapabilities,
-                    Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
-        }
+        conferenceCapabilities = changeCapability(conferenceCapabilities,
+                    Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
+                    can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
 
-        if (can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
-            conferenceCapabilities = applyCapability(conferenceCapabilities,
-                    Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
-        } else {
-            conferenceCapabilities = removeCapability(conferenceCapabilities,
-                    Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
-        }
+        conferenceCapabilities = changeCapability(conferenceCapabilities,
+                    Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
+                    can(capabilities, Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL));
 
-        if (can(capabilities, Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
-            conferenceCapabilities = applyCapability(conferenceCapabilities,
-                    Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO);
-        } else {
-            conferenceCapabilities = removeCapability(conferenceCapabilities,
-                    Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO);
-        }
+        conferenceCapabilities = changeCapability(conferenceCapabilities,
+                    Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
+                    can(capabilities, Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO));
 
-        if (can(capabilities, Connection.CAPABILITY_HIGH_DEF_AUDIO)) {
-            conferenceCapabilities = applyCapability(conferenceCapabilities,
-                    Connection.CAPABILITY_HIGH_DEF_AUDIO);
-        } else {
-            conferenceCapabilities = removeCapability(conferenceCapabilities,
-                    Connection.CAPABILITY_HIGH_DEF_AUDIO);
-        }
+        conferenceCapabilities = changeCapability(conferenceCapabilities,
+                    Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
+                    can(capabilities, Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO));
+
+        conferenceCapabilities = changeCapability(conferenceCapabilities,
+                    Connection.CAPABILITY_HIGH_DEF_AUDIO,
+                    can(capabilities, Connection.CAPABILITY_HIGH_DEF_AUDIO));
+
         return conferenceCapabilities;
     }
 
@@ -454,14 +443,20 @@
         // No-op
     }
 
-    private int applyCapability(int capabilities, int capability) {
-        int newCapabilities = capabilities | capability;
-        return newCapabilities;
-    }
-
-    private int removeCapability(int capabilities, int capability) {
-        int newCapabilities = capabilities & ~capability;
-        return newCapabilities;
+    /**
+     * Changes a capabilities bit-mask to add or remove a capability.
+     *
+     * @param capabilities The capabilities bit-mask.
+     * @param capability The capability to change.
+     * @param enabled Whether the capability should be set or removed.
+     * @return The capabilities bit-mask with the capability changed.
+     */
+    private int changeCapability(int capabilities, int capability, boolean enabled) {
+        if (enabled) {
+            return capabilities | capability;
+        } else {
+            return capabilities & ~capability;
+        }
     }
 
     /**
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index a7e2242..c0533c1 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -75,7 +75,7 @@
         @Override
         public void onConferenceStarted() {
             Log.v(this, "onConferenceStarted");
-            recalculateConference();
+            recalculate();
         }
     };
 
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index d2ea67e..5c238d0 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -100,7 +100,7 @@
             int subId = mPhone.getSubId();
             int color = PhoneAccount.NO_HIGHLIGHT_COLOR;
             int slotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
-            String line1Number = mTelephonyManager.getLine1NumberForSubscriber(subId);
+            String line1Number = mTelephonyManager.getLine1Number(subId);
             if (line1Number == null) {
                 line1Number = "";
             }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index b6e58d5..532916b 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -32,6 +32,7 @@
 import com.android.ims.ImsCallProfile;
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.Connection.Capability;
 import com.android.internal.telephony.Connection.PostDialListener;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
@@ -62,7 +63,8 @@
     private static final int MSG_CONFERENCE_MERGE_FAILED = 6;
     private static final int MSG_SUPP_SERVICE_NOTIFY = 7;
     private static final int MSG_CONNECTION_EXTRAS_CHANGED = 8;
-
+    private static final int MSG_SET_ORIGNAL_CONNECTION_CAPABILITIES = 9;
+ 
     /**
      * Mappings from {@link com.android.internal.telephony.Connection} extras keys to their
      * equivalents defined in {@link android.telecom.Connection}.
@@ -147,6 +149,10 @@
                     final Bundle extras = (Bundle) msg.obj;
                     updateExtras(extras);
                     break;
+
+                case MSG_SET_ORIGNAL_CONNECTION_CAPABILITIES:
+                    setOriginalConnectionCapabilities(msg.arg1);
+                    break;
             }
         }
     };
@@ -188,26 +194,15 @@
             setVideoState(videoState);
         }
 
-        /**
-         * The {@link com.android.internal.telephony.Connection} has reported a change in local
-         * video capability.
-         *
-         * @param capable True if capable.
+        /*
+         * The {@link com.android.internal.telephony.Connection} has reported a change in
+         * connection capability.
+         * @param capabilities bit mask containing voice or video or both capabilities.
          */
         @Override
-        public void onLocalVideoCapabilityChanged(boolean capable) {
-            setLocalVideoCapable(capable);
-        }
-
-        /**
-         * The {@link com.android.internal.telephony.Connection} has reported a change in remote
-         * video capability.
-         *
-         * @param capable True if capable.
-         */
-        @Override
-        public void onRemoteVideoCapabilityChanged(boolean capable) {
-            setRemoteVideoCapable(capable);
+        public void onConnectionCapabilitiesChanged(int capabilities) {
+            mHandler.obtainMessage(MSG_SET_ORIGNAL_CONNECTION_CAPABILITIES,
+                    capabilities, 0).sendToTarget();
         }
 
         /**
@@ -299,23 +294,10 @@
     private boolean mIsMultiParty = false;
 
     /**
-     * Determines if the {@link TelephonyConnection} has local video capabilities.
-     * This is used when {@link TelephonyConnection#updateConnectionCapabilities()}} is called,
-     * ensuring the appropriate capabilities are set.  Since capabilities
-     * can be rebuilt at any time it is necessary to track the video capabilities between rebuild.
-     * The capabilities (including video capabilities) are communicated to the telecom
-     * layer.
+     * The {@link com.android.internal.telephony.Connection} capabilities associated with the
+     * current {@link #mOriginalConnection}.
      */
-    private boolean mLocalVideoCapable;
-
-    /**
-     * Determines if the {@link TelephonyConnection} has remote video capabilities.
-     * This is used when {@link TelephonyConnection#updateConnectionCapabilities()}} is called,
-     * ensuring the appropriate capabilities are set.  Since capabilities can be rebuilt at any time
-     * it is necessary to track the video capabilities between rebuild. The capabilities (including
-     * video capabilities) are communicated to the telecom layer.
-     */
-    private boolean mRemoteVideoCapable;
+    private int mOriginalConnectionCapabilities;
 
     /**
      * Determines if the {@link TelephonyConnection} is using wifi.
@@ -543,7 +525,7 @@
     }
 
     /**
-     * Builds call capabilities common to all TelephonyConnections. Namely, apply IMS-based
+     * Builds connection capabilities common to all TelephonyConnections. Namely, apply IMS-based
      * capabilities.
      */
     protected int buildConnectionCapabilities() {
@@ -570,16 +552,12 @@
     protected final void updateConnectionCapabilities() {
         int newCapabilities = buildConnectionCapabilities();
 
-        newCapabilities = changeCapability(newCapabilities,
-                CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL, mRemoteVideoCapable);
-        newCapabilities = changeCapability(newCapabilities,
-                CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL, mLocalVideoCapable);
+        newCapabilities = applyOriginalConnectionCapabilities(newCapabilities);
         newCapabilities = changeCapability(newCapabilities,
                 CAPABILITY_HIGH_DEF_AUDIO, mHasHighDefAudio);
         newCapabilities = changeCapability(newCapabilities, CAPABILITY_WIFI, mIsWifi);
         newCapabilities = changeCapability(newCapabilities, CAPABILITY_CAN_PAUSE_VIDEO,
-                mIsVideoPauseSupported && mRemoteVideoCapable && mLocalVideoCapable);
-
+                mIsVideoPauseSupported && isVideoCapable());
         newCapabilities = applyConferenceTerminationCapabilities(newCapabilities);
 
         if (getConnectionCapabilities() != newCapabilities) {
@@ -632,8 +610,7 @@
 
         // Set video state and capabilities
         setVideoState(mOriginalConnection.getVideoState());
-        setLocalVideoCapable(mOriginalConnection.isLocalVideoCapable());
-        setRemoteVideoCapable(mOriginalConnection.isRemoteVideoCapable());
+        setOriginalConnectionCapabilities(mOriginalConnection.getConnectionCapabilities());
         setWifi(mOriginalConnection.isWifi());
         setVideoProvider(mOriginalConnection.getVideoProvider());
         setAudioQuality(mOriginalConnection.getAudioQuality());
@@ -967,10 +944,24 @@
     }
 
     /**
-     * Applies capabilities specific to conferences termination to the
-     * {@code CallCapabilities} bit-mask.
+     * Determines if the current connection is video capable.
      *
-     * @param capabilities The {@code CallCapabilities} bit-mask.
+     * A connection is deemed to be video capable if the original connection capabilities state that
+     * both local and remote video is supported.
+     *
+     * @return {@code true} if the connection is video capable, {@code false} otherwise.
+     */
+    private boolean isVideoCapable() {
+        return can(mOriginalConnectionCapabilities, Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL)
+                && can(mOriginalConnectionCapabilities,
+                Capability.SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
+    }
+
+    /**
+     * Applies capabilities specific to conferences termination to the
+     * {@code ConnectionCapabilities} bit-mask.
+     *
+     * @param capabilities The {@code ConnectionCapabilities} bit-mask.
      * @return The capabilities with the IMS conference capabilities applied.
      */
     private int applyConferenceTerminationCapabilities(int capabilities) {
@@ -987,43 +978,42 @@
     }
 
     /**
-     * Returns the local video capability state for the connection.
+     * Stores the new original connection capabilities, and applies them to the current connection,
+     * notifying any listeners as necessary.
      *
-     * @return {@code True} if the connection has local video capabilities.
+     * @param connectionCapabilities The original connection capabilties.
      */
-    public boolean isLocalVideoCapable() {
-        return mLocalVideoCapable;
-    }
-
-    /**
-     * Returns the remote video capability state for the connection.
-     *
-     * @return {@code True} if the connection has remote video capabilities.
-     */
-    public boolean isRemoteVideoCapable() {
-        return mRemoteVideoCapable;
-    }
-
-    /**
-     * Sets whether video capability is present locally.  Used during rebuild of the
-     * capabilities to set the video call capabilities.
-     *
-     * @param capable {@code True} if video capable.
-     */
-    public void setLocalVideoCapable(boolean capable) {
-        mLocalVideoCapable = capable;
+    public void setOriginalConnectionCapabilities(int connectionCapabilities) {
+        mOriginalConnectionCapabilities = connectionCapabilities;
         updateConnectionCapabilities();
     }
 
     /**
-     * Sets whether video capability is present remotely.  Used during rebuild of the
-     * capabilities to set the video call capabilities.
+     * Called to apply the capabilities present in the {@link #mOriginalConnection} to this
+     * {@link Connection}.  Provides a mapping between the capabilities present in the original
+     * connection (see {@link com.android.internal.telephony.Connection.Capability}) and those in
+     * this {@link Connection}.
      *
-     * @param capable {@code True} if video capable.
+     * @param capabilities The capabilities bitmask from the {@link Connection}.
+     * @return the capabilities bitmask with the original connection capabilities remapped and
+     *      applied.
      */
-    public void setRemoteVideoCapable(boolean capable) {
-        mRemoteVideoCapable = capable;
-        updateConnectionCapabilities();
+    public int applyOriginalConnectionCapabilities(int capabilities) {
+        // We only support downgrading to audio if both the remote and local side support
+        // downgrading to audio.
+        boolean supportsDowngradeToAudio = can(mOriginalConnectionCapabilities,
+                Capability.SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL |
+                        Capability.SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE);
+        capabilities = changeCapability(capabilities,
+                CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO, !supportsDowngradeToAudio);
+
+        capabilities = changeCapability(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
+                can(mOriginalConnectionCapabilities, Capability.SUPPORTS_VT_REMOTE_BIDIRECTIONAL));
+
+        capabilities = changeCapability(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
+                can(mOriginalConnectionCapabilities, Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
+
+        return capabilities;
     }
 
     /**
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 5f68d9a..c919059 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -26,6 +26,8 @@
 import android.telecom.ConnectionService;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
@@ -275,6 +277,14 @@
             }
         }
 
+        final Context context = getApplicationContext();
+        if (VideoProfile.isVideo(request.getVideoState()) && isTtyModeEnabled(context) &&
+                !isEmergencyNumber) {
+            return Connection.createFailedConnection(
+                    DisconnectCauseUtil.toTelecomDisconnectCause(
+                            DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED));
+        }
+
         final TelephonyConnection connection =
                 createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle(),
                         request.getTelecomCallId());
@@ -623,4 +633,11 @@
             mImsConferenceController.remove(connection);
         }
     }
+
+    private boolean isTtyModeEnabled(Context context) {
+        return (android.provider.Settings.Secure.getInt(
+                context.getContentResolver(),
+                android.provider.Settings.Secure.PREFERRED_TTY_MODE,
+                TelecomManager.TTY_MODE_OFF) != TelecomManager.TTY_MODE_OFF);
+    }
 }