Add new DisconnectCause class to telecomm.

+ Add a hidden "UNKNOWN" default type to ToneGenerator.
- Hide the Telephony DisconnectCause from the public API.
+ Add a Telecomm DisconnectCause. This is parcelable, and contains
information (code, user facing message, non-user facing reason,
and tone) to help describe the disconnect state and what behaviors
an application can implement for the user experience. This reduces
the causes for a disconnect to a more generic set.
+ Lots of work to pipe this through. DisconnectCause replaces the
code and message which were formerly passed around.

Bug: 17241433
Bug: 17329632
Change-Id: I9d337e478a8784bcc0ade02267c2df52cac9bf17
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 1d33b3b..1a6c52f 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -19,7 +19,6 @@
 import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Bundle;
-import android.telephony.DisconnectCause;
 
 import java.lang.String;
 import java.util.ArrayList;
@@ -89,8 +88,7 @@
         private final PhoneAccountHandle mAccountHandle;
         private final int mCallCapabilities;
         private final int mCallProperties;
-        private final int mDisconnectCauseCode;
-        private final String mDisconnectCauseMessage;
+        private final DisconnectCause mDisconnectCause;
         private final long mConnectTimeMillis;
         private final GatewayInfo mGatewayInfo;
         private final int mVideoState;
@@ -154,18 +152,10 @@
 
         /**
          * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
-         * as a code chosen from among those declared in {@link DisconnectCause}.
+         * by {@link android.telecomm.DisconnectCause}.
          */
-        public int getDisconnectCauseCode() {
-            return mDisconnectCauseCode;
-        }
-
-        /**
-         * @return For a {@link #STATE_DISCONNECTED} {@code Call}, an optional reason for
-         * disconnection expressed as a free text message.
-         */
-        public String getDisconnectCauseMessage() {
-            return mDisconnectCauseMessage;
+        public DisconnectCause getDisconnectCause() {
+            return mDisconnectCause;
         }
 
         /**
@@ -219,8 +209,7 @@
                         Objects.equals(mAccountHandle, d.mAccountHandle) &&
                         Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
                         Objects.equals(mCallProperties, d.mCallProperties) &&
-                        Objects.equals(mDisconnectCauseCode, d.mDisconnectCauseCode) &&
-                        Objects.equals(mDisconnectCauseMessage, d.mDisconnectCauseMessage) &&
+                        Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
                         Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
                         Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
                         Objects.equals(mVideoState, d.mVideoState) &&
@@ -240,8 +229,7 @@
                     Objects.hashCode(mAccountHandle) +
                     Objects.hashCode(mCallCapabilities) +
                     Objects.hashCode(mCallProperties) +
-                    Objects.hashCode(mDisconnectCauseCode) +
-                    Objects.hashCode(mDisconnectCauseMessage) +
+                    Objects.hashCode(mDisconnectCause) +
                     Objects.hashCode(mConnectTimeMillis) +
                     Objects.hashCode(mGatewayInfo) +
                     Objects.hashCode(mVideoState) +
@@ -258,8 +246,7 @@
                 PhoneAccountHandle accountHandle,
                 int capabilities,
                 int properties,
-                int disconnectCauseCode,
-                String disconnectCauseMessage,
+                DisconnectCause disconnectCause,
                 long connectTimeMillis,
                 GatewayInfo gatewayInfo,
                 int videoState,
@@ -272,8 +259,7 @@
             mAccountHandle = accountHandle;
             mCallCapabilities = capabilities;
             mCallProperties = properties;
-            mDisconnectCauseCode = disconnectCauseCode;
-            mDisconnectCauseMessage = disconnectCauseMessage;
+            mDisconnectCause = disconnectCause;
             mConnectTimeMillis = connectTimeMillis;
             mGatewayInfo = gatewayInfo;
             mVideoState = videoState;
@@ -654,8 +640,7 @@
                 parcelableCall.getAccountHandle(),
                 parcelableCall.getCapabilities(),
                 parcelableCall.getProperties(),
-                parcelableCall.getDisconnectCauseCode(),
-                parcelableCall.getDisconnectCauseMsg(),
+                parcelableCall.getDisconnectCause(),
                 parcelableCall.getConnectTimeMillis(),
                 parcelableCall.getGatewayInfo(),
                 parcelableCall.getVideoState(),
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index ca85446..d1e150f 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -16,8 +16,6 @@
 
 package android.telecom;
 
-import android.telephony.DisconnectCause;
-
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
@@ -32,7 +30,7 @@
     /** @hide */
     public abstract static class Listener {
         public void onStateChanged(Conference conference, int oldState, int newState) {}
-        public void onDisconnected(Conference conference, int cause, String message) {}
+        public void onDisconnected(Conference conference, DisconnectCause disconnectCause) {}
         public void onConnectionAdded(Conference conference, Connection connection) {}
         public void onConnectionRemoved(Conference conference, Connection connection) {}
         public void onDestroyed(Conference conference) {}
@@ -46,7 +44,7 @@
 
     private PhoneAccountHandle mPhoneAccount;
     private int mState = Connection.STATE_NEW;
-    private int mDisconnectCause = DisconnectCause.NOT_VALID;
+    private DisconnectCause mDisconnectCause;
     private int mCapabilities;
     private String mDisconnectMessage;
 
@@ -146,16 +144,14 @@
     /**
      * Sets state to disconnected.
      *
-     * @param cause The reason for the disconnection, any of
-     *         {@link android.telephony.DisconnectCause}.
-     * @param message Optional call-service-provided message about the disconnect.
+     * @param disconnectCause The reason for the disconnection, as described by
+     *     {@link android.telecom.DisconnectCause}.
      */
-    public final void setDisconnected(int cause, String message) {
-        mDisconnectCause = cause;
-        mDisconnectMessage = message;
+    public final void setDisconnected(DisconnectCause disconnectCause) {
+        mDisconnectCause = disconnectCause;;
         setState(Connection.STATE_DISCONNECTED);
         for (Listener l : mListeners) {
-            l.onDisconnected(this, mDisconnectCause, mDisconnectMessage);
+            l.onDisconnected(this, mDisconnectCause);
         }
     }
 
@@ -222,7 +218,7 @@
         // If not yet disconnected, set the conference call as disconnected first.
         if (mState != Connection.STATE_DISCONNECTED) {
             Log.d(this, "setting to disconnected");
-            setDisconnected(DisconnectCause.LOCAL, null);
+            setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
         }
 
         // ...and notify.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 5f63af3..76348ec 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -24,7 +24,6 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
-import android.telephony.DisconnectCause;
 import android.view.Surface;
 
 import java.util.ArrayList;
@@ -71,7 +70,7 @@
         public void onCallerDisplayNameChanged(
                 Connection c, String callerDisplayName, int presentation) {}
         public void onVideoStateChanged(Connection c, int videoState) {}
-        public void onDisconnected(Connection c, int cause, String message) {}
+        public void onDisconnected(Connection c, DisconnectCause disconnectCause) {}
         public void onPostDialWait(Connection c, String remaining) {}
         public void onRingbackRequested(Connection c, boolean ringback) {}
         public void onDestroyed(Connection c) {}
@@ -473,8 +472,7 @@
     private boolean mAudioModeIsVoip;
     private StatusHints mStatusHints;
     private int mVideoState;
-    private int mDisconnectCause;
-    private String mDisconnectMessage;
+    private DisconnectCause mDisconnectCause;
     private Conference mConference;
     private ConnectionService mConnectionService;
 
@@ -604,18 +602,11 @@
     /**
      * @return The {@link DisconnectCause} for this connection.
      */
-    public final int getDisconnectCause() {
+    public final DisconnectCause getDisconnectCause() {
         return mDisconnectCause;
     }
 
     /**
-     * @return The disconnect message for this connection.
-     */
-    public final String getDisconnectMessage() {
-        return mDisconnectMessage;
-    }
-
-    /**
      * Inform this Connection that the state of its audio output has been changed externally.
      *
      * @param state The new audio state.
@@ -774,17 +765,15 @@
     /**
      * Sets state to disconnected.
      *
-     * @param cause The reason for the disconnection, any of
+     * @param disconnectCause The reason for the disconnection, as specified by
      *         {@link DisconnectCause}.
-     * @param message Optional call-service-provided message about the disconnect.
      */
-    public final void setDisconnected(int cause, String message) {
-        mDisconnectCause = cause;
-        mDisconnectMessage = message;
+    public final void setDisconnected(DisconnectCause disconnectCause) {
+        mDisconnectCause = disconnectCause;
         setState(STATE_DISCONNECTED);
-        Log.d(this, "Disconnected with cause %d message %s", cause, message);
+        Log.d(this, "Disconnected with cause %d message %s", disconnectCause);
         for (Listener l : mListeners) {
-            l.onDisconnected(this, cause, message);
+            l.onDisconnected(this, disconnectCause);
         }
     }
 
@@ -1071,26 +1060,24 @@
     }
 
     private static class FailureSignalingConnection extends Connection {
-        public FailureSignalingConnection(int cause, String message) {
-            setDisconnected(cause, message);
+        public FailureSignalingConnection(DisconnectCause disconnectCause) {
+            setDisconnected(disconnectCause);
         }
     }
 
     /**
      * Return a {@code Connection} which represents a failed connection attempt. The returned
-     * {@code Connection} will have a {@link #getDisconnectCause()} and
-     * {@link #getDisconnectMessage()} as specified, and a {@link #getState()} of
-     * {@link #STATE_DISCONNECTED}.
+     * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified,
+     * and a {@link #getState()} of {@link #STATE_DISCONNECTED}.
      * <p>
      * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate,
      * so users of this method need not maintain a reference to its return value to destroy it.
      *
-     * @param cause The disconnect cause, ({@see DisconnectCause}).
-     * @param message A reason for why the connection failed (not intended to be shown to the user).
+     * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
      * @return A {@code Connection} which indicates failure.
      */
-    public static Connection createFailedConnection(int cause, String message) {
-        return new FailureSignalingConnection(cause, message);
+    public static Connection createFailedConnection(DisconnectCause disconnectCause) {
+        return new FailureSignalingConnection(disconnectCause);
     }
 
     /**
@@ -1105,7 +1092,7 @@
      * @return A {@code Connection} which indicates that the underlying call should be canceled.
      */
     public static Connection createCanceledConnection() {
-        return new FailureSignalingConnection(DisconnectCause.OUTGOING_CANCELED, null);
+        return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED));
     }
 
     private final void  fireOnConferenceableConnectionsChanged() {
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index cc80e22..0da0adb 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -25,7 +25,6 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.telephony.DisconnectCause;
 
 import com.android.internal.os.SomeArgs;
 import com.android.internal.telecom.IConnectionService;
@@ -344,9 +343,9 @@
         }
 
         @Override
-        public void onDisconnected(Conference conference, int cause, String message) {
+        public void onDisconnected(Conference conference, DisconnectCause disconnectCause) {
             String id = mIdByConference.get(conference);
-            mAdapter.setDisconnected(id, cause, message);
+            mAdapter.setDisconnected(id, disconnectCause);
         }
 
         @Override
@@ -399,10 +398,10 @@
         }
 
         @Override
-        public void onDisconnected(Connection c, int cause, String message) {
+        public void onDisconnected(Connection c, DisconnectCause disconnectCause) {
             String id = mIdByConnection.get(c);
-            Log.d(this, "Adapter set disconnected %d %s", cause, message);
-            mAdapter.setDisconnected(id, cause, message);
+            Log.d(this, "Adapter set disconnected %d %s", disconnectCause);
+            mAdapter.setDisconnected(id, disconnectCause);
         }
 
         @Override
@@ -522,7 +521,8 @@
                 : onCreateOutgoingConnection(callManagerAccount, request);
         Log.d(this, "createConnection, connection: %s", connection);
         if (connection == null) {
-            connection = Connection.createFailedConnection(DisconnectCause.OUTGOING_FAILURE, null);
+            connection = Connection.createFailedConnection(
+                    new DisconnectCause(DisconnectCause.ERROR));
         }
 
         if (connection.getState() != Connection.STATE_DISCONNECTED) {
@@ -555,7 +555,6 @@
                         connection.getAudioModeIsVoip(),
                         connection.getStatusHints(),
                         connection.getDisconnectCause(),
-                        connection.getDisconnectMessage(),
                         createConnectionIdList(connection.getConferenceableConnections())));
     }
 
@@ -836,7 +835,7 @@
      *         making the connection.
      * @param request Details about the outgoing call.
      * @return The {@code Connection} object to satisfy this call, or the result of an invocation
-     *         of {@link Connection#createFailedConnection(int, String)} to not handle the call.
+     *         of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
      */
     public Connection onCreateOutgoingConnection(
             PhoneAccountHandle connectionManagerPhoneAccount,
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index f6bcdc6..c676172 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -134,14 +134,13 @@
      * Sets a call's state to disconnected.
      *
      * @param callId The unique ID of the call whose state is changing to disconnected.
-     * @param disconnectCause The reason for the disconnection, any of
-     *            {@link android.telephony.DisconnectCause}.
-     * @param disconnectMessage Optional call-service-provided message about the disconnect.
+     * @param disconnectCause The reason for the disconnection, as described by
+     *            {@link android.telecomm.DisconnectCause}.
      */
-    void setDisconnected(String callId, int disconnectCause, String disconnectMessage) {
+    void setDisconnected(String callId, DisconnectCause disconnectCause) {
         for (IConnectionServiceAdapter adapter : mAdapters) {
             try {
-                adapter.setDisconnected(callId, disconnectCause, disconnectMessage);
+                adapter.setDisconnected(callId, disconnectCause);
             } catch (RemoteException e) {
             }
         }
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index ffbbc8a..217dbc3 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -96,8 +96,7 @@
                 case MSG_SET_DISCONNECTED: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
-                        mDelegate.setDisconnected(
-                                (String) args.arg1, args.argi1, (String) args.arg2);
+                        mDelegate.setDisconnected((String) args.arg1, (DisconnectCause) args.arg2);
                     } finally {
                         args.recycle();
                     }
@@ -234,11 +233,10 @@
 
         @Override
         public void setDisconnected(
-                String connectionId, int disconnectCause, String disconnectMessage) {
+                String connectionId, DisconnectCause disconnectCause) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = connectionId;
-            args.arg2 = disconnectMessage;
-            args.argi1 = disconnectCause;
+            args.arg2 = disconnectCause;
             mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
         }
 
diff --git a/telecomm/java/android/telecom/DisconnectCause.aidl b/telecomm/java/android/telecom/DisconnectCause.aidl
new file mode 100644
index 0000000..26b8652
--- /dev/null
+++ b/telecomm/java/android/telecom/DisconnectCause.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom;
+
+/**
+ * {@hide}
+ */
+parcelable DisconnectCause;
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
new file mode 100644
index 0000000..cae115d
--- /dev/null
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.media.ToneGenerator;
+import android.text.TextUtils;
+
+import java.util.Objects;
+
+/**
+ * Describes the cause of a disconnected call. This always includes a code describing the generic
+ * cause of the disconnect. Optionally, it may include a localized label and/or localized description
+ * to display to the user which is provided by the {@link ConnectionService}. It also may contain a
+ * reason for the the disconnect, which is intended for logging and not for display to the user.
+ */
+public final class DisconnectCause implements Parcelable {
+
+    /** Disconnected because of an unknown or unspecified reason. */
+    public static final int UNKNOWN = 0;
+    /** Disconnected because there was an error, such as a problem with the network. */
+    public static final int ERROR = 1;
+    /** Disconnected because of a local user-initiated action, such as hanging up. */
+    public static final int LOCAL = 2;
+    /**
+     * Disconnected because of a remote user-initiated action, such as the other party hanging up
+     * up.
+     */
+    public static final int REMOTE = 3;
+    /** Disconnected because it has been canceled. */
+    public static final int CANCELED = 4;
+    /** Disconnected because there was no response to an incoming call. */
+    public static final int MISSED = 5;
+    /** Disconnected because the user rejected an incoming call. */
+    public static final int REJECTED = 6;
+    /** Disconnected because the other party was busy. */
+    public static final int BUSY = 7;
+    /**
+     * Disconnected because of a restriction on placing the call, such as dialing in airplane
+     * mode.
+     */
+    public static final int RESTRICTED = 8;
+    /** Disconnected for reason not described by other disconnect codes. */
+    public static final int OTHER = 9;
+
+    private int mDisconnectCode;
+    private CharSequence mDisconnectLabel;
+    private CharSequence mDisconnectDescription;
+    private String mDisconnectReason;
+    private int mToneToPlay;
+
+    /**
+     * Creates a new DisconnectCause.
+     *
+     * @param code The code for the disconnect cause.
+     */
+    public DisconnectCause(int code) {
+        this(code, null, null, null, ToneGenerator.TONE_UNKNOWN);
+    }
+
+    /**
+     * Creates a new DisconnectCause.
+     *
+     * @param code The code for the disconnect cause.
+     * @param reason The reason for the disconnect.
+     */
+    public DisconnectCause(int code, String reason) {
+        this(code, null, null, reason, ToneGenerator.TONE_UNKNOWN);
+    }
+
+    /**
+     * Creates a new DisconnectCause.
+     *
+     * @param code The code for the disconnect cause.
+     * @param label The localized label to show to the user to explain the disconnect.
+     * @param description The localized description to show to the user to explain the disconnect.
+     * @param reason The reason for the disconnect.
+     * @param toneToPlay The tone to play on disconnect, as defined in {@link ToneGenerator}.
+     */
+    public DisconnectCause(int code, CharSequence label, CharSequence description, String reason,
+            int toneToPlay) {
+        mDisconnectCode = code;
+        mDisconnectLabel = label;
+        mDisconnectDescription = description;
+        mDisconnectReason = reason;
+        mToneToPlay = toneToPlay;
+    }
+
+    /**
+     * Returns the code for the reason for this disconnect.
+     *
+     * @return The disconnect code.
+     */
+    public int getCode() {
+        return mDisconnectCode;
+    }
+
+    /**
+     * Returns a short label which explains the reason for the disconnect cause and is for display
+     * in the user interface. The {@link ConnectionService } is responsible for providing and
+     * localizing this label. If there is no string provided, returns null.
+     *
+     * @return The disconnect label.
+     */
+    public CharSequence getLabel() {
+        return mDisconnectLabel;
+    }
+
+    /**
+     * Returns a description which explains the reason for the disconnect cause and is for display
+     * in the user interface. The {@link ConnectionService } is responsible for providing and
+     * localizing this message. If there is no string provided, returns null.
+     *
+     * @return The disconnect description.
+     */
+    public CharSequence getDescription() {
+        return mDisconnectDescription;
+    }
+
+    /**
+     * Returns an explanation of the reason for the disconnect. This is not intended for display to
+     * the user and is used mainly for logging.
+     *
+     * @return The disconnect reason.
+     */
+    public String getReason() {
+        return mDisconnectReason;
+    }
+
+    /**
+     * Returns the tone to play when disconnected.
+     *
+     * @return the tone as defined in {@link ToneGenerator} to play when disconnected.
+     */
+    public int getTone() {
+        return mToneToPlay;
+    }
+
+    public static final Creator<DisconnectCause> CREATOR = new Creator<DisconnectCause>() {
+        @Override
+        public DisconnectCause createFromParcel(Parcel source) {
+            int code = source.readInt();
+            CharSequence label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            String reason = source.readString();
+            int tone = source.readInt();
+            return new DisconnectCause(code, label, description, reason, tone);
+        }
+
+        @Override
+        public DisconnectCause[] newArray(int size) {
+            return new DisconnectCause[size];
+        }
+    };
+
+    @Override
+    public void writeToParcel(Parcel destination, int flags) {
+        destination.writeInt(mDisconnectCode);
+        TextUtils.writeToParcel(mDisconnectLabel, destination, flags);
+        TextUtils.writeToParcel(mDisconnectDescription, destination, flags);
+        destination.writeString(mDisconnectReason);
+        destination.writeInt(mToneToPlay);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(mDisconnectCode)
+                + Objects.hashCode(mDisconnectLabel)
+                + Objects.hashCode(mDisconnectDescription)
+                + Objects.hashCode(mDisconnectReason)
+                + Objects.hashCode(mToneToPlay);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof DisconnectCause) {
+            DisconnectCause d = (DisconnectCause) o;
+            return Objects.equals(mDisconnectCode, d.getCode())
+                    && Objects.equals(mDisconnectLabel, d.getLabel())
+                    && Objects.equals(mDisconnectDescription, d.getDescription())
+                    && Objects.equals(mDisconnectReason, d.getReason())
+                    && Objects.equals(mToneToPlay, d.getTone());
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        String code = "";
+        switch (getCode()) {
+            case ERROR:
+                code = "ERROR";
+                break;
+            case LOCAL:
+                code = "LOCAL";
+                break;
+            case REMOTE:
+                code = "REMOTE";
+                break;
+            case MISSED:
+                code = "MISSED";
+                break;
+            case REJECTED:
+                code = "REJECTED";
+                break;
+            case BUSY:
+                code = "BUSY";
+                break;
+            case RESTRICTED:
+                code = "RESTRICTED";
+                break;
+            case OTHER:
+                code = "OTHER";
+                break;
+            case UNKNOWN:
+            default:
+                code = "UNKNOWN";
+        }
+        String label = mDisconnectLabel == null ? "" : mDisconnectLabel.toString();
+        String description = mDisconnectDescription == null
+                ? "" : mDisconnectDescription.toString();
+        String reason = mDisconnectReason == null ? "" : mDisconnectReason;
+        return "DisconnectCause [ Code: (" + code + ")"
+                + " Label: (" + label + ")"
+                + " Description: (" + description + ")"
+                + " Reason: (" + reason + ")"
+                + " Tone: (" + mToneToPlay + ") ]";
+    }
+}
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 838c7cf..c5c3d11 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -21,7 +21,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
-import android.telephony.DisconnectCause;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -36,8 +35,7 @@
 public final class ParcelableCall implements Parcelable {
     private final String mId;
     private final int mState;
-    private final int mDisconnectCauseCode;
-    private final String mDisconnectCauseMsg;
+    private final DisconnectCause mDisconnectCause;
     private final List<String> mCannedSmsResponses;
     private final int mCapabilities;
     private final int mProperties;
@@ -60,8 +58,7 @@
     public ParcelableCall(
             String id,
             int state,
-            int disconnectCauseCode,
-            String disconnectCauseMsg,
+            DisconnectCause disconnectCause,
             List<String> cannedSmsResponses,
             int capabilities,
             int properties,
@@ -81,8 +78,7 @@
             Bundle extras) {
         mId = id;
         mState = state;
-        mDisconnectCauseCode = disconnectCauseCode;
-        mDisconnectCauseMsg = disconnectCauseMsg;
+        mDisconnectCause = disconnectCause;
         mCannedSmsResponses = cannedSmsResponses;
         mCapabilities = capabilities;
         mProperties = properties;
@@ -113,19 +109,11 @@
     }
 
     /**
-     * Reason for disconnection, values are defined in {@link DisconnectCause}. Valid when call
-     * state is {@link CallState#DISCONNECTED}.
+     * Reason for disconnection, as described by {@link android.telecomm.DisconnectCause}. Valid
+     * when call state is {@link CallState#DISCONNECTED}.
      */
-    public int getDisconnectCauseCode() {
-        return mDisconnectCauseCode;
-    }
-
-    /**
-     * Further optional textual information about the reason for disconnection. Valid when call
-     * state is {@link CallState#DISCONNECTED}.
-     */
-    public String getDisconnectCauseMsg() {
-        return mDisconnectCauseMsg;
+    public DisconnectCause getDisconnectCause() {
+        return mDisconnectCause;
     }
 
     /**
@@ -252,8 +240,7 @@
             ClassLoader classLoader = ParcelableCall.class.getClassLoader();
             String id = source.readString();
             int state = source.readInt();
-            int disconnectCauseCode = source.readInt();
-            String disconnectCauseMsg = source.readString();
+            DisconnectCause disconnectCause = source.readParcelable(classLoader);
             List<String> cannedSmsResponses = new ArrayList<>();
             source.readList(cannedSmsResponses, classLoader);
             int capabilities = source.readInt();
@@ -275,11 +262,27 @@
             List<String> conferenceableCallIds = new ArrayList<>();
             source.readList(conferenceableCallIds, classLoader);
             Bundle extras = source.readParcelable(classLoader);
-            return new ParcelableCall(id, state, disconnectCauseCode, disconnectCauseMsg,
-                    cannedSmsResponses, capabilities, properties, connectTimeMillis, handle,
-                    handlePresentation, callerDisplayName, callerDisplayNamePresentation,
-                    gatewayInfo, accountHandle, videoCallProvider, parentCallId, childCallIds,
-                    statusHints, videoState, conferenceableCallIds, extras);
+            return new ParcelableCall(
+                    id,
+                    state,
+                    disconnectCause,
+                    cannedSmsResponses,
+                    capabilities,
+                    properties,
+                    connectTimeMillis,
+                    handle,
+                    handlePresentation,
+                    callerDisplayName,
+                    callerDisplayNamePresentation,
+                    gatewayInfo,
+                    accountHandle,
+                    videoCallProvider,
+                    parentCallId,
+                    childCallIds,
+                    statusHints,
+                    videoState,
+                    conferenceableCallIds,
+                    extras);
         }
 
         @Override
@@ -299,8 +302,7 @@
     public void writeToParcel(Parcel destination, int flags) {
         destination.writeString(mId);
         destination.writeInt(mState);
-        destination.writeInt(mDisconnectCauseCode);
-        destination.writeString(mDisconnectCauseMsg);
+        destination.writeParcelable(mDisconnectCause, 0);
         destination.writeList(mCannedSmsResponses);
         destination.writeInt(mCapabilities);
         destination.writeInt(mProperties);
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index 63393b2..9004448 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -44,8 +44,7 @@
     private final boolean mRingbackRequested;
     private final boolean mIsVoipAudioMode;
     private final StatusHints mStatusHints;
-    private final int mDisconnectCause;
-    private final String mDisconnectMessage;
+    private final DisconnectCause mDisconnectCause;
     private final List<String> mConferenceableConnectionIds;
 
     /** @hide */
@@ -62,8 +61,7 @@
             boolean ringbackRequested,
             boolean isVoipAudioMode,
             StatusHints statusHints,
-            int disconnectCause,
-            String disconnectMessage,
+            DisconnectCause disconnectCause,
             List<String> conferenceableConnectionIds) {
         mPhoneAccount = phoneAccount;
         mState = state;
@@ -78,7 +76,6 @@
         mIsVoipAudioMode = isVoipAudioMode;
         mStatusHints = statusHints;
         mDisconnectCause = disconnectCause;
-        mDisconnectMessage = disconnectMessage;
         this.mConferenceableConnectionIds = conferenceableConnectionIds;
     }
 
@@ -131,14 +128,10 @@
         return mStatusHints;
     }
 
-    public final int getDisconnectCause() {
+    public final DisconnectCause getDisconnectCause() {
         return mDisconnectCause;
     }
 
-    public final String getDisconnectMessage() {
-        return mDisconnectMessage;
-    }
-
     public final List<String> getConferenceableConnectionIds() {
         return mConferenceableConnectionIds;
     }
@@ -174,8 +167,7 @@
             boolean ringbackRequested = source.readByte() == 1;
             boolean audioModeIsVoip = source.readByte() == 1;
             StatusHints statusHints = source.readParcelable(classLoader);
-            int disconnectCauseCode = source.readInt();
-            String disconnectCauseMessage = source.readString();
+            DisconnectCause disconnectCause = source.readParcelable(classLoader);
             List<String> conferenceableConnectionIds = new ArrayList<>();
             source.readStringList(conferenceableConnectionIds);
 
@@ -192,8 +184,7 @@
                     ringbackRequested,
                     audioModeIsVoip,
                     statusHints,
-                    disconnectCauseCode,
-                    disconnectCauseMessage,
+                    disconnectCause,
                     conferenceableConnectionIds);
         }
 
@@ -225,8 +216,7 @@
         destination.writeByte((byte) (mRingbackRequested ? 1 : 0));
         destination.writeByte((byte) (mIsVoipAudioMode ? 1 : 0));
         destination.writeParcelable(mStatusHints, 0);
-        destination.writeInt(mDisconnectCause);
-        destination.writeString(mDisconnectMessage);
+        destination.writeParcelable(mDisconnectCause, 0);
         destination.writeStringList(mConferenceableConnectionIds);
     }
 }
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index 996e091..0cf84d0 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -19,7 +19,6 @@
 import com.android.internal.telecom.IConnectionService;
 
 import android.os.RemoteException;
-import android.telephony.DisconnectCause;
 
 import java.util.Collections;
 import java.util.List;
@@ -34,7 +33,7 @@
 
     public abstract static class Callback {
         public void onStateChanged(RemoteConference conference, int oldState, int newState) {}
-        public void onDisconnected(RemoteConference conference, int cause, String message) {}
+        public void onDisconnected(RemoteConference conference, DisconnectCause disconnectCause) {}
         public void onConnectionAdded(RemoteConference conference, RemoteConnection connection) {}
         public void onConnectionRemoved(RemoteConference conference, RemoteConnection connection) {}
         public void onCapabilitiesChanged(RemoteConference conference, int capabilities) {}
@@ -50,9 +49,8 @@
             Collections.unmodifiableList(mChildConnections);
 
     private int mState = Connection.STATE_NEW;
-    private int mDisconnectCause = DisconnectCause.NOT_VALID;
+    private DisconnectCause mDisconnectCause;
     private int mCallCapabilities;
-    private String mDisconnectMessage;
 
     /** {@hide} */
     RemoteConference(String id, IConnectionService connectionService) {
@@ -127,13 +125,12 @@
     }
 
     /** {@hide} */
-    void setDisconnected(int cause, String message) {
+    void setDisconnected(DisconnectCause disconnectCause) {
         if (mState != Connection.STATE_DISCONNECTED) {
-            mDisconnectCause = cause;
-            mDisconnectMessage = message;
+            mDisconnectCause = disconnectCause;
             setState(Connection.STATE_DISCONNECTED);
             for (Callback c : mCallbacks) {
-                c.onDisconnected(this, cause, message);
+                c.onDisconnected(this, disconnectCause);
             }
         }
     }
@@ -180,14 +177,10 @@
         }
     }
 
-    public int getDisconnectCause() {
+    public DisconnectCause getDisconnectCause() {
         return mDisconnectCause;
     }
 
-    public String getDisconnectMessage() {
-        return mDisconnectMessage;
-    }
-
     public final void registerCallback(Callback callback) {
         mCallbacks.add(callback);
     }
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index bf699b3..9a094df 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -23,7 +23,6 @@
 import android.net.Uri;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.telephony.DisconnectCause;
 import android.view.Surface;
 
 import java.util.ArrayList;
@@ -55,15 +54,12 @@
          * Invoked when this {@code RemoteConnection} is disconnected.
          *
          * @param connection The {@code RemoteConnection} invoking this method.
-         * @param disconnectCauseCode The failure code ({@see DisconnectCause}) associated with this
-         *         failed connection.
-         * @param disconnectCauseMessage The reason for the connection failure. This will not be
-         *         displayed to the user.
+         * @param disconnectCause The ({@see DisconnectCause}) associated with this failed
+         *     connection.
          */
         public void onDisconnected(
                 RemoteConnection connection,
-                int disconnectCauseCode,
-                String disconnectCauseMessage) {}
+                DisconnectCause disconnectCause) {}
 
         /**
          * Invoked when this {@code RemoteConnection} is requesting ringback. See
@@ -383,8 +379,7 @@
             Collections.unmodifiableList(mConferenceableConnections);
 
     private int mState = Connection.STATE_NEW;
-    private int mDisconnectCauseCode = DisconnectCause.NOT_VALID;
-    private String mDisconnectCauseMessage;
+    private DisconnectCause mDisconnectCause;
     private boolean mRingbackRequested;
     private boolean mConnected;
     private int mCallCapabilities;
@@ -396,8 +391,6 @@
     private int mAddressPresentation;
     private String mCallerDisplayName;
     private int mCallerDisplayNamePresentation;
-    private int mFailureCode;
-    private String mFailureMessage;
     private RemoteConference mConference;
 
     /**
@@ -418,15 +411,14 @@
      * "real" purpose will almost certainly fail. Callers should note the failure and act
      * accordingly (moving on to another RemoteConnection, for example)
      *
-     * @param failureCode
-     * @param failureMessage
+     * @param disconnectCause The reason for the failed connection.
+     * @hide
      */
-    RemoteConnection(int failureCode, String failureMessage) {
+    RemoteConnection(DisconnectCause disconnectCause) {
         this("NULL", null, null);
         mConnected = false;
         mState = Connection.STATE_DISCONNECTED;
-        mFailureCode = DisconnectCause.OUTGOING_FAILURE;
-        mFailureMessage = failureMessage + " original code = " + failureCode;
+        mDisconnectCause = disconnectCause;
     }
 
     /**
@@ -463,16 +455,8 @@
      * disconnect cause expressed as a code chosen from among those declared in
      * {@link DisconnectCause}.
      */
-    public int getDisconnectCauseCode() {
-        return mDisconnectCauseCode;
-    }
-
-    /**
-     * @return For a {@link Connection#STATE_DISCONNECTED} {@code RemoteConnection}, an optional
-     * reason for disconnection expressed as a free text message.
-     */
-    public String getDisconnectCauseMessage() {
-        return mDisconnectCauseMessage;
+    public DisconnectCause getDisconnectCause() {
+        return mDisconnectCause;
     }
 
     /**
@@ -547,21 +531,6 @@
     }
 
     /**
-     * @return The failure code ({@see DisconnectCause}) associated with this failed
-     * {@code RemoteConnection}.
-     */
-    public int getFailureCode() {
-        return mFailureCode;
-    }
-
-    /**
-     * @return The reason for the connection failure. This will not be displayed to the user.
-     */
-    public String getFailureMessage() {
-        return mFailureMessage;
-    }
-
-    /**
      * @return Whether the {@code RemoteConnection} is requesting that the framework play a
      * ringback tone on its behalf.
      */
@@ -779,14 +748,13 @@
     /**
      * @hide
      */
-    void setDisconnected(int cause, String message) {
+    void setDisconnected(DisconnectCause disconnectCause) {
         if (mState != Connection.STATE_DISCONNECTED) {
             mState = Connection.STATE_DISCONNECTED;
-            mDisconnectCauseCode = cause;
-            mDisconnectCauseMessage = message;
+            mDisconnectCause = disconnectCause;
 
             for (Callback c : mCallbacks) {
-                c.onDisconnected(this, cause, message);
+                c.onDisconnected(this, mDisconnectCause);
             }
         }
     }
@@ -820,7 +788,8 @@
         if (!mCallbacks.isEmpty()) {
             // Make sure that the callbacks are notified that the call is destroyed first.
             if (mState != Connection.STATE_DISCONNECTED) {
-                setDisconnected(DisconnectCause.ERROR_UNSPECIFIED, "Connection destroyed.");
+                setDisconnected(
+                        new DisconnectCause(DisconnectCause.ERROR, "Connection destroyed."));
             }
 
             for (Callback c : mCallbacks) {
@@ -923,7 +892,7 @@
      *
      * @hide
      */
-    public static RemoteConnection failure(int failureCode, String failureMessage) {
-        return new RemoteConnection(failureCode, failureMessage);
+    public static RemoteConnection failure(DisconnectCause disconnectCause) {
+        return new RemoteConnection(disconnectCause);
     }
 }
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index bfd7c51..03b38c2 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -20,7 +20,6 @@
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
-import android.telephony.DisconnectCause;
 
 import com.android.internal.telecom.IConnectionService;
 import com.android.internal.telecom.IConnectionServiceAdapter;
@@ -107,14 +106,13 @@
         }
 
         @Override
-        public void setDisconnected(String callId, int disconnectCause,
-                String disconnectMessage) {
+        public void setDisconnected(String callId, DisconnectCause disconnectCause) {
             if (mConnectionById.containsKey(callId)) {
                 findConnectionForAction(callId, "setDisconnected")
-                        .setDisconnected(disconnectCause, disconnectMessage);
+                        .setDisconnected(disconnectCause);
             } else {
                 findConferenceForAction(callId, "setDisconnected")
-                        .setDisconnected(disconnectCause, disconnectMessage);
+                        .setDisconnected(disconnectCause);
             }
         }
 
@@ -351,8 +349,8 @@
             });
             return connection;
         } catch (RemoteException e) {
-            return RemoteConnection
-                    .failure(DisconnectCause.ERROR_UNSPECIFIED, e.toString());
+            return RemoteConnection.failure(
+                    new DisconnectCause(DisconnectCause.ERROR, e.toString()));
         }
     }
 
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 8f3506d..5daa568 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -19,6 +19,7 @@
 import android.app.PendingIntent;
 import android.net.Uri;
 import android.telecom.ConnectionRequest;
+import android.telecom.DisconnectCause;
 import android.telecom.ParcelableConnection;
 import android.telecom.ParcelableConference;
 import android.telecom.StatusHints;
@@ -45,7 +46,7 @@
 
     void setDialing(String callId);
 
-    void setDisconnected(String callId, int disconnectCause, String disconnectMessage);
+    void setDisconnected(String callId, in DisconnectCause disconnectCause);
 
     void setOnHold(String callId);