Merge "Telephony API extension v2"
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b198937..8355928 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1088,6 +1088,14 @@
         android:label="@string/permlab_readPhoneState"
         android:description="@string/permdesc_readPhoneState" />
 
+    <!-- Allows read only access to precise phone state.
+         @hide Pending API council approval -->
+    <permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
+        android:permissionGroup="android.permission-group.PHONE_CALLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_readPrecisePhoneState"
+        android:description="@string/permdesc_readPrecisePhoneState" />
+
     <!-- Allows read access to privileged phone state.
          @hide Used internally. -->
     <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 986a005..012fb83 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1639,6 +1639,14 @@
       connected by a call.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_readPrecisePhoneState">read precise phone states</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_readPrecisePhoneState">Allows the app to access the precise
+      phone states.  This permission allows the app to determine the real
+      call status, whether a call is active or in the background, call fails,
+      precise data connection status and data connection fails.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="default">prevent phone from sleeping</string>
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 699d79e..77f5182 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -37,6 +37,10 @@
 import android.telephony.SignalStrength;
 import android.telephony.CellInfo;
 import android.telephony.TelephonyManager;
+import android.telephony.DisconnectCause;
+import android.telephony.PreciseCallState;
+import android.telephony.PreciseDataConnectionState;
+import android.telephony.PreciseDisconnectCause;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -125,6 +129,17 @@
 
     private List<CellInfo> mCellInfo = null;
 
+    private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+
+    private int mForegroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+
+    private int mBackgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+
+    private PreciseCallState mPreciseCallState = new PreciseCallState();
+
+    private PreciseDataConnectionState mPreciseDataConnectionState =
+                new PreciseDataConnectionState();
+
     static final int PHONE_STATE_PERMISSION_MASK =
                 PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
                 PhoneStateListener.LISTEN_CALL_STATE |
@@ -132,6 +147,10 @@
                 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
                 PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
 
+    static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
+                PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
+                PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
+
     private static final int MSG_USER_SWITCHED = 1;
 
     private final Handler mHandler = new Handler() {
@@ -305,6 +324,21 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+                        try {
+                            r.callback.onPreciseCallStateChanged(mPreciseCallState);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
+                    if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+                        try {
+                            r.callback.onPreciseDataConnectionStateChanged(
+                                    mPreciseDataConnectionState);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                 }
             }
         } else {
@@ -533,30 +567,47 @@
                 }
                 handleRemoveListLocked();
             }
+            mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
+                    apnType, apn, reason, linkProperties, "");
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+                    try {
+                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
         }
         broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
                 apnType, linkProperties, linkCapabilities, roaming);
+        broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
+                linkProperties, "");
     }
 
     public void notifyDataConnectionFailed(String reason, String apnType) {
         if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
             return;
         }
-        /*
-         * This is commented out because there is no onDataConnectionFailed callback
-         * in PhoneStateListener. There should be.
         synchronized (mRecords) {
-            mDataConnectionFailedReason = reason;
-            final int N = mRecords.size();
-            for (int i=N-1; i>=0; i--) {
-                Record r = mRecords.get(i);
-                if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_FAILED) != 0) {
-                    // XXX
+            mPreciseDataConnectionState = new PreciseDataConnectionState(
+                    TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                    apnType, "", reason, null, "");
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+                    try {
+                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
                 }
             }
+            handleRemoveListLocked();
         }
-        */
         broadcastDataConnectionFailed(reason, apnType);
+        broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
+                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
     }
 
     public void notifyCellLocation(Bundle cellLocation) {
@@ -602,6 +653,81 @@
         }
     }
 
+    public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
+            int backgroundCallState) {
+        if (!checkNotifyPermission("notifyPreciseCallState()")) {
+            return;
+        }
+        synchronized (mRecords) {
+            mRingingCallState = ringingCallState;
+            mForegroundCallState = foregroundCallState;
+            mBackgroundCallState = backgroundCallState;
+            mPreciseCallState = new PreciseCallState(ringingCallState, foregroundCallState,
+                    backgroundCallState,
+                    DisconnectCause.NOT_VALID,
+                    PreciseDisconnectCause.NOT_VALID);
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+                    try {
+                        r.callback.onPreciseCallStateChanged(mPreciseCallState);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+        broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState,
+                DisconnectCause.NOT_VALID,
+                PreciseDisconnectCause.NOT_VALID);
+    }
+
+    public void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause) {
+        if (!checkNotifyPermission("notifyDisconnectCause()")) {
+            return;
+        }
+        synchronized (mRecords) {
+            mPreciseCallState = new PreciseCallState(mRingingCallState, mForegroundCallState,
+                    mBackgroundCallState, disconnectCause, preciseDisconnectCause);
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+                    try {
+                        r.callback.onPreciseCallStateChanged(mPreciseCallState);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+        broadcastPreciseCallStateChanged(mRingingCallState, mForegroundCallState,
+                mBackgroundCallState, disconnectCause, preciseDisconnectCause);
+    }
+
+    public void notifyPreciseDataConnectionFailed(String reason, String apnType,
+            String apn, String failCause) {
+        if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
+            return;
+        }
+        synchronized (mRecords) {
+            mPreciseDataConnectionState = new PreciseDataConnectionState(
+                    TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                    apnType, apn, reason, null, failCause);
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+                    try {
+                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+        broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
+                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -738,6 +864,33 @@
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
+    private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
+            int backgroundCallState, int disconnectCause, int preciseDisconnectCause) {
+        Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
+        intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
+        intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
+        intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
+        intent.putExtra(TelephonyManager.EXTRA_DISCONNECT_CAUSE, disconnectCause);
+        intent.putExtra(TelephonyManager.EXTRA_PRECISE_DISCONNECT_CAUSE, preciseDisconnectCause);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+                android.Manifest.permission.READ_PRECISE_PHONE_STATE);
+    }
+
+    private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
+            String apnType, String apn, String reason, LinkProperties linkProperties, String failCause) {
+        Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+        intent.putExtra(PhoneConstants.STATE_KEY, state);
+        intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
+        if (reason != null) intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
+        if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+        if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
+        if (linkProperties != null) intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
+        if (failCause != null) intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
+
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+                android.Manifest.permission.READ_PRECISE_PHONE_STATE);
+    }
+
     private boolean checkNotifyPermission(String method) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
                 == PackageManager.PERMISSION_GRANTED) {
@@ -766,6 +919,12 @@
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PHONE_STATE, null);
         }
+
+        if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
+
+        }
     }
 
     private void handleRemoveListLocked() {
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
new file mode 100644
index 0000000..323e0ac
--- /dev/null
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -0,0 +1,108 @@
+/*
+ * 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.telephony;
+
+/**
+ * Contains disconnect call causes generated by the
+ * framework and the RIL.
+ *
+ * @hide
+ */
+public class DisconnectCause {
+
+    /** The disconnect cause is not valid (Not received a disconnect cause) */
+    public static final int NOT_VALID                      = -1;
+    /** Has not yet disconnected */
+    public static final int NOT_DISCONNECTED               = 0;
+    /** An incoming call that was missed and never answered */
+    public static final int INCOMING_MISSED                = 1;
+    /** Normal; Remote hangup*/
+    public static final int NORMAL                         = 2;
+    /** Normal; Local hangup */
+    public static final int LOCAL                          = 3;
+    /** Outgoing call to busy line */
+    public static final int BUSY                           = 4;
+    /** Outgoing call to congested network */
+    public static final int CONGESTION                     = 5;
+    /** Not presently used */
+    public static final int MMI                            = 6;
+    /** Invalid dial string */
+    public static final int INVALID_NUMBER                 = 7;
+    /** Cannot reach the peer */
+    public static final int NUMBER_UNREACHABLE             = 8;
+    /** Cannot reach the server */
+    public static final int SERVER_UNREACHABLE             = 9;
+    /** Invalid credentials */
+    public static final int INVALID_CREDENTIALS            = 10;
+    /** Calling from out of network is not allowed */
+    public static final int OUT_OF_NETWORK                 = 11;
+    /** Server error */
+    public static final int SERVER_ERROR                   = 12;
+    /** Client timed out */
+    public static final int TIMED_OUT                      = 13;
+    /** Client went out of network range */
+    public static final int LOST_SIGNAL                    = 14;
+    /** GSM or CDMA ACM limit exceeded */
+    public static final int LIMIT_EXCEEDED                 = 15;
+    /** An incoming call that was rejected */
+    public static final int INCOMING_REJECTED              = 16;
+    /** Radio is turned off explicitly */
+    public static final int POWER_OFF                      = 17;
+    /** Out of service */
+    public static final int OUT_OF_SERVICE                 = 18;
+    /** No ICC, ICC locked, or other ICC error */
+    public static final int ICC_ERROR                      = 19;
+    /** Call was blocked by call barring */
+    public static final int CALL_BARRED                    = 20;
+    /** Call was blocked by fixed dial number */
+    public static final int FDN_BLOCKED                    = 21;
+    /** Call was blocked by restricted all voice access */
+    public static final int CS_RESTRICTED                  = 22;
+    /** Call was blocked by restricted normal voice access */
+    public static final int CS_RESTRICTED_NORMAL           = 23;
+    /** Call was blocked by restricted emergency voice access */
+    public static final int CS_RESTRICTED_EMERGENCY        = 24;
+    /** Unassigned number */
+    public static final int UNOBTAINABLE_NUMBER            = 25;
+    /** MS is locked until next power cycle */
+    public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE  = 26;
+    /** Drop call*/
+    public static final int CDMA_DROP                      = 27;
+    /** INTERCEPT order received, MS state idle entered */
+    public static final int CDMA_INTERCEPT                 = 28;
+    /** MS has been redirected, call is cancelled */
+    public static final int CDMA_REORDER                   = 29;
+    /** Service option rejection */
+    public static final int CDMA_SO_REJECT                 = 30;
+    /** Requested service is rejected, retry delay is set */
+    public static final int CDMA_RETRY_ORDER               = 31;
+    /** Unable to obtain access to the CDMA system */
+    public static final int CDMA_ACCESS_FAILURE            = 32;
+    /** Not a preempted call */
+    public static final int CDMA_PREEMPTED                 = 33;
+    /** Not an emergency call */
+    public static final int CDMA_NOT_EMERGENCY             = 34;
+    /** Access Blocked by CDMA network */
+    public static final int CDMA_ACCESS_BLOCKED            = 35;
+    /** Unknown error or not specified */
+    public static final int ERROR_UNSPECIFIED              = 36;
+
+    /** Private constructor to avoid class instantiation. */
+    private DisconnectCause() {
+        // Do nothing.
+    }
+}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index ff77fc0..538548d 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -24,6 +24,8 @@
 import android.telephony.CellLocation;
 import android.telephony.CellInfo;
 import android.telephony.Rlog;
+import android.telephony.PreciseCallState;
+import android.telephony.PreciseDataConnectionState;
 
 import com.android.internal.telephony.IPhoneStateListener;
 
@@ -165,6 +167,27 @@
      */
     public static final int LISTEN_CELL_INFO = 0x00000400;
 
+    /**
+     * Listen for precise changes and fails to the device calls (cellular).
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+     * READ_PRECISE_PHONE_STATE}
+     *
+     * @hide
+     */
+    public static final int LISTEN_PRECISE_CALL_STATE                       = 0x00000800;
+
+    /**
+     * Listen for precise changes and fails on the data connection (cellular).
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+     * READ_PRECISE_PHONE_STATE}
+     *
+     * @see #onPreciseDataConnectionStateChanged
+     * @hide
+     */
+    public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE            = 0x00001000;
+
     public PhoneStateListener() {
     }
 
@@ -293,6 +316,25 @@
     }
 
     /**
+     * Callback invoked when precise device call state changes.
+     *
+     * @hide
+     */
+    public void onPreciseCallStateChanged(PreciseCallState callState) {
+        // default implementation empty
+    }
+
+    /**
+     * Callback invoked when data connection state changes with precise information.
+     *
+     * @hide
+     */
+    public void onPreciseDataConnectionStateChanged(
+            PreciseDataConnectionState dataConnectionState) {
+        // default implementation empty
+    }
+
+    /**
      * The callback methods need to be called on the handler thread where
      * this object was created.  If the binder did that for us it'd be nice.
      */
@@ -344,6 +386,16 @@
         public void onCellInfoChanged(List<CellInfo> cellInfo) {
             Message.obtain(mHandler, LISTEN_CELL_INFO, 0, 0, cellInfo).sendToTarget();
         }
+
+        public void onPreciseCallStateChanged(PreciseCallState callState) {
+            Message.obtain(mHandler, LISTEN_PRECISE_CALL_STATE, 0, 0, callState).sendToTarget();
+        }
+
+        public void onPreciseDataConnectionStateChanged(
+                PreciseDataConnectionState dataConnectionState) {
+            Message.obtain(mHandler, LISTEN_PRECISE_DATA_CONNECTION_STATE, 0, 0,
+                    dataConnectionState).sendToTarget();
+        }
     };
 
     Handler mHandler = new Handler() {
@@ -383,6 +435,12 @@
                     break;
                 case LISTEN_CELL_INFO:
                     PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj);
+                    break;
+                case LISTEN_PRECISE_CALL_STATE:
+                    PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj);
+                    break;
+                case LISTEN_PRECISE_DATA_CONNECTION_STATE:
+                    PhoneStateListener.this.onPreciseDataConnectionStateChanged((PreciseDataConnectionState)msg.obj);
             }
         }
     };
diff --git a/telephony/java/android/telephony/PreciseCallState.aidl b/telephony/java/android/telephony/PreciseCallState.aidl
new file mode 100644
index 0000000..447f29b
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseCallState.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** 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.telephony;
+
+parcelable PreciseCallState;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
new file mode 100644
index 0000000..a85df15
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -0,0 +1,311 @@
+/*
+ * 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.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+import android.telephony.DisconnectCause;
+import android.telephony.PreciseDisconnectCause;
+
+/**
+ * Contains precise call state and call fail causes generated by the
+ * framework and the RIL.
+ *
+ * The following call information is included in returned PreciseCallState:
+ *
+ * <ul>
+ *   <li>Ringing call state.
+ *   <li>Foreground call state.
+ *   <li>Background call state.
+ *   <li>Disconnect cause; generated by the framework.
+ *   <li>Precise disconnect cause; generated by the RIL.
+ * </ul>
+ *
+ * @hide
+ */
+public class PreciseCallState implements Parcelable {
+
+    /** Call state is not valid (Not received a call state). */
+    public static final int PRECISE_CALL_STATE_NOT_VALID =      -1;
+    /** Call state: No activity. */
+    public static final int PRECISE_CALL_STATE_IDLE =           0;
+    /** Call state: Active. */
+    public static final int PRECISE_CALL_STATE_ACTIVE =         1;
+    /** Call state: On hold. */
+    public static final int PRECISE_CALL_STATE_HOLDING =        2;
+    /** Call state: Dialing. */
+    public static final int PRECISE_CALL_STATE_DIALING =        3;
+    /** Call state: Alerting. */
+    public static final int PRECISE_CALL_STATE_ALERTING =       4;
+    /** Call state: Incoming. */
+    public static final int PRECISE_CALL_STATE_INCOMING =       5;
+    /** Call state: Waiting. */
+    public static final int PRECISE_CALL_STATE_WAITING =        6;
+    /** Call state: Disconnected. */
+    public static final int PRECISE_CALL_STATE_DISCONNECTED =   7;
+    /** Call state: Disconnecting. */
+    public static final int PRECISE_CALL_STATE_DISCONNECTING =  8;
+
+    private int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private int mDisconnectCause = DisconnectCause.NOT_VALID;
+    private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
+
+    /**
+     * Constructor
+     *
+     * @hide
+     */
+    public PreciseCallState(int ringingCall, int foregroundCall, int backgroundCall,
+            int disconnectCause, int preciseDisconnectCause) {
+        mRingingCallState = ringingCall;
+        mForegroundCallState = foregroundCall;
+        mBackgroundCallState = backgroundCall;
+        mDisconnectCause = disconnectCause;
+        mPreciseDisconnectCause = preciseDisconnectCause;
+    }
+
+    /**
+     * Empty Constructor
+     *
+     * @hide
+     */
+    public PreciseCallState() {
+    }
+
+    /**
+     * Construct a PreciseCallState object from the given parcel.
+     */
+    private PreciseCallState(Parcel in) {
+        mRingingCallState = in.readInt();
+        mForegroundCallState = in.readInt();
+        mBackgroundCallState = in.readInt();
+        mDisconnectCause = in.readInt();
+        mPreciseDisconnectCause = in.readInt();
+    }
+
+    /**
+     * Get precise ringing call state
+     *
+     * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+     * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+     * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+     * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+     * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+     * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+     * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+     */
+    public int getRingingCallState() {
+        return mRingingCallState;
+    }
+
+    /**
+     * Get precise foreground call state
+     *
+     * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+     * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+     * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+     * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+     * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+     * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+     * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+     */
+    public int getForegroundCallState() {
+        return mForegroundCallState;
+    }
+
+    /**
+     * Get precise background call state
+     *
+     * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+     * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+     * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+     * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+     * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+     * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+     * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+     */
+    public int getBackgroundCallState() {
+        return mBackgroundCallState;
+    }
+
+    /**
+     * Get disconnect cause generated by the framework
+     *
+     * @see DisconnectCause#NOT_VALID
+     * @see DisconnectCause#NOT_DISCONNECTED
+     * @see DisconnectCause#INCOMING_MISSED
+     * @see DisconnectCause#NORMAL
+     * @see DisconnectCause#LOCAL
+     * @see DisconnectCause#BUSY
+     * @see DisconnectCause#CONGESTION
+     * @see DisconnectCause#MMI
+     * @see DisconnectCause#INVALID_NUMBER
+     * @see DisconnectCause#NUMBER_UNREACHABLE
+     * @see DisconnectCause#SERVER_UNREACHABLE
+     * @see DisconnectCause#INVALID_CREDENTIALS
+     * @see DisconnectCause#OUT_OF_NETWORK
+     * @see DisconnectCause#SERVER_ERROR
+     * @see DisconnectCause#TIMED_OUT
+     * @see DisconnectCause#LOST_SIGNAL
+     * @see DisconnectCause#LIMIT_EXCEEDED
+     * @see DisconnectCause#INCOMING_REJECTED
+     * @see DisconnectCause#POWER_OFF
+     * @see DisconnectCause#OUT_OF_SERVICE
+     * @see DisconnectCause#ICC_ERROR
+     * @see DisconnectCause#CALL_BARRED
+     * @see DisconnectCause#FDN_BLOCKED
+     * @see DisconnectCause#CS_RESTRICTED
+     * @see DisconnectCause#CS_RESTRICTED_NORMAL
+     * @see DisconnectCause#CS_RESTRICTED_EMERGENCY
+     * @see DisconnectCause#UNOBTAINABLE_NUMBER
+     * @see DisconnectCause#CDMA_LOCKED_UNTIL_POWER_CYCLE
+     * @see DisconnectCause#CDMA_DROP
+     * @see DisconnectCause#CDMA_INTERCEPT
+     * @see DisconnectCause#CDMA_REORDER
+     * @see DisconnectCause#CDMA_SO_REJECT
+     * @see DisconnectCause#CDMA_RETRY_ORDER
+     * @see DisconnectCause#CDMA_ACCESS_FAILURE
+     * @see DisconnectCause#CDMA_PREEMPTED
+     * @see DisconnectCause#CDMA_NOT_EMERGENCY
+     * @see DisconnectCause#CDMA_ACCESS_BLOCKED
+     * @see DisconnectCause#ERROR_UNSPECIFIED
+     */
+    public int getDisconnectCause() {
+        return mDisconnectCause;
+    }
+
+    /**
+     * Get disconnect cause generated by the RIL
+     *
+     * @see PreciseDisconnectCause#NOT_VALID
+     * @see PreciseDisconnectCause#NO_DISCONNECT_CAUSE_AVAILABLE
+     * @see PreciseDisconnectCause#UNOBTAINABLE_NUMBER
+     * @see PreciseDisconnectCause#NORMAL
+     * @see PreciseDisconnectCause#BUSY
+     * @see PreciseDisconnectCause#NUMBER_CHANGED
+     * @see PreciseDisconnectCause#STATUS_ENQUIRY
+     * @see PreciseDisconnectCause#NORMAL_UNSPECIFIED
+     * @see PreciseDisconnectCause#NO_CIRCUIT_AVAIL
+     * @see PreciseDisconnectCause#TEMPORARY_FAILURE
+     * @see PreciseDisconnectCause#SWITCHING_CONGESTION
+     * @see PreciseDisconnectCause#CHANNEL_NOT_AVAIL
+     * @see PreciseDisconnectCause#QOS_NOT_AVAIL
+     * @see PreciseDisconnectCause#BEARER_NOT_AVAIL
+     * @see PreciseDisconnectCause#ACM_LIMIT_EXCEEDED
+     * @see PreciseDisconnectCause#CALL_BARRED
+     * @see PreciseDisconnectCause#FDN_BLOCKED
+     * @see PreciseDisconnectCause#IMSI_UNKNOWN_IN_VLR
+     * @see PreciseDisconnectCause#IMEI_NOT_ACCEPTED
+     * @see PreciseDisconnectCause#CDMA_LOCKED_UNTIL_POWER_CYCLE
+     * @see PreciseDisconnectCause#CDMA_DROP
+     * @see PreciseDisconnectCause#CDMA_INTERCEPT
+     * @see PreciseDisconnectCause#CDMA_REORDER
+     * @see PreciseDisconnectCause#CDMA_SO_REJECT
+     * @see PreciseDisconnectCause#CDMA_RETRY_ORDER
+     * @see PreciseDisconnectCause#CDMA_ACCESS_FAILURE
+     * @see PreciseDisconnectCause#CDMA_PREEMPTED
+     * @see PreciseDisconnectCause#CDMA_NOT_EMERGENCY
+     * @see PreciseDisconnectCause#CDMA_ACCESS_BLOCKED
+     * @see PreciseDisconnectCause#ERROR_UNSPECIFIED
+     */
+    public int getPreciseDisconnectCause() {
+        return mPreciseDisconnectCause;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mRingingCallState);
+        out.writeInt(mForegroundCallState);
+        out.writeInt(mBackgroundCallState);
+        out.writeInt(mDisconnectCause);
+        out.writeInt(mPreciseDisconnectCause);
+    }
+
+    public static final Parcelable.Creator<PreciseCallState> CREATOR
+            = new Parcelable.Creator<PreciseCallState>() {
+
+        public PreciseCallState createFromParcel(Parcel in) {
+            return new PreciseCallState(in);
+        }
+
+        public PreciseCallState[] newArray(int size) {
+            return new PreciseCallState[size];
+        }
+    };
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mRingingCallState;
+        result = prime * result + mForegroundCallState;
+        result = prime * result + mBackgroundCallState;
+        result = prime * result + mDisconnectCause;
+        result = prime * result + mPreciseDisconnectCause;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PreciseCallState other = (PreciseCallState) obj;
+        return (mRingingCallState != other.mRingingCallState &&
+            mForegroundCallState != other.mForegroundCallState &&
+            mBackgroundCallState != other.mBackgroundCallState &&
+            mDisconnectCause != other.mDisconnectCause &&
+            mPreciseDisconnectCause != other.mPreciseDisconnectCause);
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("Ringing call state: " + mRingingCallState);
+        sb.append(", Foreground call state: " + mForegroundCallState);
+        sb.append(", Background call state: " + mBackgroundCallState);
+        sb.append(", Disconnect cause: " + mDisconnectCause);
+        sb.append(", Precise disconnect cause: " + mPreciseDisconnectCause);
+
+        return sb.toString();
+    }
+}
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.aidl b/telephony/java/android/telephony/PreciseDataConnectionState.aidl
new file mode 100644
index 0000000..07ad762
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** 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.telephony;
+
+parcelable PreciseDataConnectionState;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
new file mode 100644
index 0000000..87529fe
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -0,0 +1,275 @@
+/*
+ * 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.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+import android.telephony.TelephonyManager;
+import android.net.LinkProperties;
+
+/**
+ * Contains precise data connection state.
+ *
+ * The following data connection information is included in returned PreciseDataConnectionState:
+ *
+ * <ul>
+ *   <li>Data connection state.
+ *   <li>Network type of the connection.
+ *   <li>APN type.
+ *   <li>APN.
+ *   <li>Data connection change reason.
+ *   <li>The properties of the network link.
+ *   <li>Data connection fail cause.
+ * </ul>
+ *
+ * @hide
+ */
+public class PreciseDataConnectionState implements Parcelable {
+
+    private int mState = TelephonyManager.DATA_UNKNOWN;
+    private int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+    private String mAPNType = "";
+    private String mAPN = "";
+    private String mReason = "";
+    private LinkProperties mLinkProperties = null;
+    private String mFailCause = "";
+
+    /**
+     * Constructor
+     *
+     * @hide
+     */
+    public PreciseDataConnectionState(int state, int networkType,
+            String apnType, String apn, String reason,
+            LinkProperties linkProperties, String failCause) {
+        mState = state;
+        mNetworkType = networkType;
+        mAPNType = apnType;
+        mAPN = apn;
+        mReason = reason;
+        mLinkProperties = linkProperties;
+        mFailCause = failCause;
+    }
+
+    /**
+     * Empty Constructor
+     *
+     * @hide
+     */
+    public PreciseDataConnectionState() {
+    }
+
+    /**
+     * Construct a PreciseDataConnectionState object from the given parcel.
+     */
+    private PreciseDataConnectionState(Parcel in) {
+        mState = in.readInt();
+        mNetworkType = in.readInt();
+        mAPNType = in.readString();
+        mAPN = in.readString();
+        mReason = in.readString();
+        mLinkProperties = (LinkProperties)in.readParcelable(null);
+        mFailCause = in.readString();
+    }
+
+    /**
+     * Get data connection state
+     *
+     * @see TelephonyManager#DATA_UNKNOWN
+     * @see TelephonyManager#DATA_DISCONNECTED
+     * @see TelephonyManager#DATA_CONNECTING
+     * @see TelephonyManager#DATA_CONNECTED
+     * @see TelephonyManager#DATA_SUSPENDED
+     */
+    public int getDataConnectionState() {
+        return mState;
+    }
+
+    /**
+     * Get data connection network type
+     *
+     * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
+     * @see TelephonyManager#NETWORK_TYPE_GPRS
+     * @see TelephonyManager#NETWORK_TYPE_EDGE
+     * @see TelephonyManager#NETWORK_TYPE_UMTS
+     * @see TelephonyManager#NETWORK_TYPE_CDMA
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_0
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_A
+     * @see TelephonyManager#NETWORK_TYPE_1xRTT
+     * @see TelephonyManager#NETWORK_TYPE_HSDPA
+     * @see TelephonyManager#NETWORK_TYPE_HSUPA
+     * @see TelephonyManager#NETWORK_TYPE_HSPA
+     * @see TelephonyManager#NETWORK_TYPE_IDEN
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_B
+     * @see TelephonyManager#NETWORK_TYPE_LTE
+     * @see TelephonyManager#NETWORK_TYPE_EHRPD
+     * @see TelephonyManager#NETWORK_TYPE_HSPAP
+     */
+    public int getDataConnectionNetworkType() {
+        return mNetworkType;
+    }
+
+    /**
+     * Get data connection APN type
+     */
+    public String getDataConnectionAPNType() {
+        return mAPNType;
+    }
+
+    /**
+     * Get data connection APN.
+     */
+    public String getDataConnectionAPN() {
+        return mAPN;
+    }
+
+    /**
+     * Get data connection change reason.
+     */
+    public String getDataConnectionChangeReason() {
+        return mReason;
+    }
+
+    /**
+     * Get the properties of the network link.
+     */
+    public LinkProperties getDataConnectionLinkProperties() {
+        return mLinkProperties;
+    }
+
+    /**
+     * Get data connection fail cause, in case there was a failure.
+     */
+    public String getDataConnectionFailCause() {
+        return mFailCause;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mState);
+        out.writeInt(mNetworkType);
+        out.writeString(mAPNType);
+        out.writeString(mAPN);
+        out.writeString(mReason);
+        out.writeParcelable(mLinkProperties, flags);
+        out.writeString(mFailCause);
+    }
+
+    public static final Parcelable.Creator<PreciseDataConnectionState> CREATOR
+            = new Parcelable.Creator<PreciseDataConnectionState>() {
+
+        public PreciseDataConnectionState createFromParcel(Parcel in) {
+            return new PreciseDataConnectionState(in);
+        }
+
+        public PreciseDataConnectionState[] newArray(int size) {
+            return new PreciseDataConnectionState[size];
+        }
+    };
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mState;
+        result = prime * result + mNetworkType;
+        result = prime * result + ((mAPNType == null) ? 0 : mAPNType.hashCode());
+        result = prime * result + ((mAPN == null) ? 0 : mAPN.hashCode());
+        result = prime * result + ((mReason == null) ? 0 : mReason.hashCode());
+        result = prime * result + ((mLinkProperties == null) ? 0 : mLinkProperties.hashCode());
+        result = prime * result + ((mFailCause == null) ? 0 : mFailCause.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        PreciseDataConnectionState other = (PreciseDataConnectionState) obj;
+        if (mAPN == null) {
+            if (other.mAPN != null) {
+                return false;
+            }
+        } else if (!mAPN.equals(other.mAPN)) {
+            return false;
+        }
+        if (mAPNType == null) {
+            if (other.mAPNType != null) {
+                return false;
+            }
+        } else if (!mAPNType.equals(other.mAPNType)) {
+            return false;
+        }
+        if (mFailCause == null) {
+            if (other.mFailCause != null) {
+                return false;
+            }
+        } else if (!mFailCause.equals(other.mFailCause)) {
+            return false;
+        }
+        if (mLinkProperties == null) {
+            if (other.mLinkProperties != null) {
+                return false;
+            }
+        } else if (!mLinkProperties.equals(other.mLinkProperties)) {
+            return false;
+        }
+        if (mNetworkType != other.mNetworkType) {
+            return false;
+        }
+        if (mReason == null) {
+            if (other.mReason != null) {
+                return false;
+            }
+        } else if (!mReason.equals(other.mReason)) {
+            return false;
+        }
+        if (mState != other.mState) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("Data Connection state: " + mState);
+        sb.append(", Network type: " + mNetworkType);
+        sb.append(", APN type: " + mAPNType);
+        sb.append(", APN: " + mAPN);
+        sb.append(", Change reason: " + mReason);
+        sb.append(", Link properties: " + mLinkProperties);
+        sb.append(", Fail cause: " + mFailCause);
+
+        return sb.toString();
+    }
+}
diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java
new file mode 100644
index 0000000..54ab19d
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseDisconnectCause.java
@@ -0,0 +1,102 @@
+/*
+ * 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.telephony;
+
+/**
+ * Contains precise disconnect call causes generated by the
+ * framework and the RIL.
+ *
+ * @hide
+ */
+public class PreciseDisconnectCause {
+
+    /** The disconnect cause is not valid (Not received a disconnect cause)*/
+    public static final int NOT_VALID                      = -1;
+    /** No disconnect cause provided. Generally a local disconnect or an incoming missed call */
+    public static final int NO_DISCONNECT_CAUSE_AVAILABLE  = 0;
+    /**
+     * The destination cannot be reached because the number, although valid,
+     * is not currently assigned
+     */
+    public static final int UNOBTAINABLE_NUMBER            = 1;
+    /** One of the users involved in the call has requested that the call is cleared */
+    public static final int NORMAL                         = 16;
+    /** The called user is unable to accept another call */
+    public static final int BUSY                           = 17;
+    /** The called number is no longer assigned */
+    public static final int NUMBER_CHANGED                 = 22;
+    /** Provided in response to a STATUS ENQUIRY message */
+    public static final int STATUS_ENQUIRY                 = 30;
+    /** Reports a normal disconnect only when no other normal cause applies */
+    public static final int NORMAL_UNSPECIFIED             = 31;
+    /** There is no channel presently available to handle the call */
+    public static final int NO_CIRCUIT_AVAIL               = 34;
+    /**
+     * The network is not functioning correctly and the condition is not likely to last
+     * a long period of time
+     */
+    public static final int TEMPORARY_FAILURE              = 41;
+    /** The switching equipment is experiencing a period of high traffic */
+    public static final int SWITCHING_CONGESTION           = 42;
+    /** The channel cannot be provided */
+    public static final int CHANNEL_NOT_AVAIL              = 44;
+    /** The requested quality of service (ITU-T X.213) cannot be provided */
+    public static final int QOS_NOT_AVAIL                  = 49;
+    /** The requested bearer capability is not available at this time */
+    public static final int BEARER_NOT_AVAIL               = 58;
+    /** The call clearing is due to ACM being greater than or equal to ACMmax */
+    public static final int ACM_LIMIT_EXCEEDED             = 68;
+    /** The call is restricted */
+    public static final int CALL_BARRED                    = 240;
+    /** The call is blocked by the Fixed Dialing Number list */
+    public static final int FDN_BLOCKED                    = 241;
+    /** The given IMSI is not known at the VLR */
+    /** TS 24.008 cause 4 */
+    public static final int IMSI_UNKNOWN_IN_VLR            = 242;
+    /**
+     * The network does not accept emergency call establishment using an IMEI or not accept attach
+     * procedure for emergency services using an IMEI
+     */
+    public static final int IMEI_NOT_ACCEPTED              = 243;
+    /** MS is locked until next power cycle */
+    public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE  = 1000;
+    /** Drop call*/
+    public static final int CDMA_DROP                      = 1001;
+    /** INTERCEPT order received, MS state idle entered */
+    public static final int CDMA_INTERCEPT                 = 1002;
+    /** MS has been redirected, call is cancelled */
+    public static final int CDMA_REORDER                   = 1003;
+    /** Service option rejection */
+    public static final int CDMA_SO_REJECT                 = 1004;
+    /** Requested service is rejected, retry delay is set */
+    public static final int CDMA_RETRY_ORDER               = 1005;
+    /** Unable to obtain access to the CDMA system */
+    public static final int CDMA_ACCESS_FAILURE            = 1006;
+    /** Not a preempted call */
+    public static final int CDMA_PREEMPTED                 = 1007;
+    /** Not an emergency call */
+    public static final int CDMA_NOT_EMERGENCY             = 1008;
+    /** Access Blocked by CDMA network */
+    public static final int CDMA_ACCESS_BLOCKED            = 1009;
+    /** Disconnected due to unspecified reasons */
+    public static final int ERROR_UNSPECIFIED              = 0xffff;
+
+    /** Private constructor to avoid class instantiation. */
+    private PreciseDisconnectCause() {
+        // Do nothing.
+    }
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 8f17e72..ea22bc4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -211,6 +211,267 @@
      */
     public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
 
+    /**
+     * Broadcast intent action indicating that a precise call state
+     * (cellular) on the device has changed.
+     *
+     * <p>
+     * The {@link #EXTRA_RINGING_CALL_STATE} extra indicates the ringing call state.
+     * The {@link #EXTRA_FOREGROUND_CALL_STATE} extra indicates the foreground call state.
+     * The {@link #EXTRA_BACKGROUND_CALL_STATE} extra indicates the background call state.
+     * The {@link #EXTRA_DISCONNECT_CAUSE} extra indicates the disconnect cause.
+     * The {@link #EXTRA_PRECISE_DISCONNECT_CAUSE} extra indicates the precise disconnect cause.
+     *
+     * <p class="note">
+     * Requires the READ_PRECISE_PHONE_STATE permission.
+     *
+     * @see #EXTRA_RINGING_CALL_STATE
+     * @see #EXTRA_FOREGROUND_CALL_STATE
+     * @see #EXTRA_BACKGROUND_CALL_STATE
+     * @see #EXTRA_DISCONNECT_CAUSE
+     * @see #EXTRA_PRECISE_DISCONNECT_CAUSE
+     *
+     * <p class="note">
+     * Requires the READ_PRECISE_PHONE_STATE permission.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PRECISE_CALL_STATE_CHANGED =
+            "android.intent.action.PRECISE_CALL_STATE";
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+     * for an integer containing the state of the current ringing call.
+     *
+     * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+     * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+     * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+     * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+     * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+     * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+     * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_RINGING_CALL_STATE = "ringing_state";
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+     * for an integer containing the state of the current foreground call.
+     *
+     * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+     * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+     * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+     * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+     * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+     * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+     * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_FOREGROUND_CALL_STATE = "foreground_state";
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+     * for an integer containing the state of the current background call.
+     *
+     * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+     * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+     * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+     * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+     * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+     * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+     * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_BACKGROUND_CALL_STATE = "background_state";
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+     * for an integer containing the disconnect cause.
+     *
+     * @see DisconnectCause
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DISCONNECT_CAUSE = "disconnect_cause";
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+     * for an integer containing the disconnect cause provided by the RIL.
+     *
+     * @see PreciseDisconnectCause
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_PRECISE_DISCONNECT_CAUSE = "precise_disconnect_cause";
+
+    /**
+     * Broadcast intent action indicating a data connection has changed,
+     * providing precise information about the connection.
+     *
+     * <p>
+     * The {@link #EXTRA_DATA_STATE} extra indicates the connection state.
+     * The {@link #EXTRA_DATA_NETWORK_TYPE} extra indicates the connection network type.
+     * The {@link #EXTRA_DATA_APN_TYPE} extra indicates the APN type.
+     * The {@link #EXTRA_DATA_APN} extra indicates the APN.
+     * The {@link #EXTRA_DATA_CHANGE_REASON} extra indicates the connection change reason.
+     * The {@link #EXTRA_DATA_IFACE_PROPERTIES} extra indicates the connection interface.
+     * The {@link #EXTRA_DATA_FAILURE_CAUSE} extra indicates the connection fail cause.
+     *
+     * <p class="note">
+     * Requires the READ_PRECISE_PHONE_STATE permission.
+     *
+     * @see #EXTRA_DATA_STATE
+     * @see #EXTRA_DATA_NETWORK_TYPE
+     * @see #EXTRA_DATA_APN_TYPE
+     * @see #EXTRA_DATA_APN
+     * @see #EXTRA_DATA_CHANGE_REASON
+     * @see #EXTRA_DATA_IFACE
+     * @see #EXTRA_DATA_FAILURE_CAUSE
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED =
+            "android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED";
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+     * for an integer containing the state of the current data connection.
+     *
+     * @see TelephonyManager#DATA_UNKNOWN
+     * @see TelephonyManager#DATA_DISCONNECTED
+     * @see TelephonyManager#DATA_CONNECTING
+     * @see TelephonyManager#DATA_CONNECTED
+     * @see TelephonyManager#DATA_SUSPENDED
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DATA_STATE = PhoneConstants.STATE_KEY;
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+     * for an integer containing the network type.
+     *
+     * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
+     * @see TelephonyManager#NETWORK_TYPE_GPRS
+     * @see TelephonyManager#NETWORK_TYPE_EDGE
+     * @see TelephonyManager#NETWORK_TYPE_UMTS
+     * @see TelephonyManager#NETWORK_TYPE_CDMA
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_0
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_A
+     * @see TelephonyManager#NETWORK_TYPE_1xRTT
+     * @see TelephonyManager#NETWORK_TYPE_HSDPA
+     * @see TelephonyManager#NETWORK_TYPE_HSUPA
+     * @see TelephonyManager#NETWORK_TYPE_HSPA
+     * @see TelephonyManager#NETWORK_TYPE_IDEN
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_B
+     * @see TelephonyManager#NETWORK_TYPE_LTE
+     * @see TelephonyManager#NETWORK_TYPE_EHRPD
+     * @see TelephonyManager#NETWORK_TYPE_HSPAP
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DATA_NETWORK_TYPE = PhoneConstants.DATA_NETWORK_TYPE_KEY;
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+     * for an String containing the data APN type.
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getStringExtra(String name)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DATA_APN_TYPE = PhoneConstants.DATA_APN_TYPE_KEY;
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+     * for an String containing the data APN.
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getStringExtra(String name)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DATA_APN = PhoneConstants.DATA_APN_KEY;
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+     * for an String representation of the change reason.
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getStringExtra(String name)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DATA_CHANGE_REASON = PhoneConstants.STATE_CHANGE_REASON_KEY;
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+     * for an String representation of the data interface.
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getParcelableExtra(String name)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DATA_LINK_PROPERTIES_KEY = PhoneConstants.DATA_LINK_PROPERTIES_KEY;
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+     * for the data connection fail cause.
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getStringExtra(String name)}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DATA_FAILURE_CAUSE = PhoneConstants.DATA_FAILURE_CAUSE_KEY;
 
     //
     //
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 3a04ceb..f228d4e 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -20,6 +20,8 @@
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.CellInfo;
+import android.telephony.PreciseCallState;
+import android.telephony.PreciseDataConnectionState;
 
 oneway interface IPhoneStateListener {
     void onServiceStateChanged(in ServiceState serviceState);
@@ -35,5 +37,7 @@
     void onSignalStrengthsChanged(in SignalStrength signalStrength);
     void onOtaspChanged(in int otaspMode);
     void onCellInfoChanged(in List<CellInfo> cellInfo);
+    void onPreciseCallStateChanged(in PreciseCallState callState);
+    void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 59c8472..546ce17 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -41,4 +41,9 @@
     void notifyCellLocation(in Bundle cellLocation);
     void notifyOtaspChanged(in int otaspMode);
     void notifyCellInfo(in List<CellInfo> cellInfo);
+    void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
+            int backgroundCallState);
+    void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause);
+    void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
+            String failCause);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 4163255..1fed417d 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -73,6 +73,8 @@
     public static final String PHONE_NAME_KEY = "phoneName";
     public static final String FAILURE_REASON_KEY = "reason";
     public static final String STATE_CHANGE_REASON_KEY = "reason";
+    public static final String DATA_NETWORK_TYPE_KEY = "networkType";
+    public static final String DATA_FAILURE_CAUSE_KEY = "failCause";
     public static final String DATA_APN_TYPE_KEY = "apnType";
     public static final String DATA_APN_KEY = "apn";
     public static final String DATA_LINK_PROPERTIES_KEY = "linkProperties";