Merge "Return USIM IMSI as subscriber ID in case of CDMA-LTE mode" into honeycomb-LTE
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index f5651e0..fba3184 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -47,6 +47,7 @@
     public String [] addresses = new String[0];
     public String [] dnses = new String[0];
     public String[] gateways = new String[0];
+    public int suggestedRetryTime = -1;
 
     /**
      * Class returned by onSetupConnectionCompleted.
@@ -77,6 +78,7 @@
         sb.append("DataCallState: {")
            .append("version=").append(version)
            .append(" status=").append(status)
+           .append(" retry=").append(suggestedRetryTime)
            .append(" cid=").append(cid)
            .append(" active=").append(active)
            .append(" type=").append(type)
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 5c030fd..cb8b0e5 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -182,6 +182,18 @@
         }
     }
 
+    public static class CallSetupException extends Exception {
+        private int mRetryOverride = -1;
+
+        CallSetupException (int retryOverride) {
+            mRetryOverride = retryOverride;
+        }
+
+        public int getRetryOverride() {
+            return mRetryOverride;
+        }
+    }
+
     // ***** Event codes for driving the state machine
     protected static final int BASE = Protocol.BASE_DATA_CONNECTION;
     protected static final int EVENT_CONNECT = BASE + 0;
@@ -205,6 +217,7 @@
     protected long createTime;
     protected long lastFailTime;
     protected FailCause lastFailCause;
+    protected int mRetryOverride = -1;
     protected static final String NULL_IP = "0.0.0.0";
     private int mRefCount;
     Object userData;
@@ -288,7 +301,8 @@
         } else {
             lastFailCause = cause;
             lastFailTime = timeStamp;
-            AsyncResult.forMessage(connectionCompletedMsg, cause, new Exception());
+            AsyncResult.forMessage(connectionCompletedMsg, cause,
+                                   new CallSetupException(mRetryOverride));
         }
         if (DBG) log("notifyConnectionCompleted at " + timeStamp + " cause=" + cause);
 
@@ -430,6 +444,7 @@
         createTime = -1;
         lastFailTime = -1;
         lastFailCause = FailCause.NONE;
+        mRetryOverride = -1;
         mRefCount = 0;
 
         mLinkProperties = new LinkProperties();
@@ -482,6 +497,15 @@
         return result;
     }
 
+    private int getSuggestedRetryTime(AsyncResult ar) {
+        int retry = -1;
+        if (ar.exception == null) {
+            DataCallState response = (DataCallState) ar.result;
+            retry =  response.suggestedRetryTime;
+        }
+        return retry;
+    }
+
     private DataCallState.SetupResult setLinkProperties(DataCallState response,
             LinkProperties lp) {
         // Check if system property dns usable
@@ -685,10 +709,12 @@
         private FailCause mFailCause = null;
         private DisconnectParams mDisconnectParams = null;
 
-        public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) {
+        public void setEnterNotificationParams(ConnectionParams cp, FailCause cause,
+                                               int retryOverride) {
             if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
             mConnectionParams = cp;
             mFailCause = cause;
+            mRetryOverride = retryOverride;
         }
 
         public void setEnterNotificationParams(DisconnectParams dp) {
@@ -808,7 +834,7 @@
                             // Vendor ril rejected the command and didn't connect.
                             // Transition to inactive but send notifications after
                             // we've entered the mInactive state.
-                            mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
+                            mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1);
                             transitionTo(mInactiveState);
                             break;
                         case ERR_UnacceptableParameter:
@@ -823,7 +849,8 @@
                             break;
                         case ERR_RilError:
                             // Request failed and mFailCause has the reason
-                            mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
+                            mInactiveState.setEnterNotificationParams(cp, result.mFailCause,
+                                                                      getSuggestedRetryTime(ar));
                             transitionTo(mInactiveState);
                             break;
                         case ERR_Stale:
@@ -848,8 +875,8 @@
                         }
                         // Transition to inactive but send notifications after
                         // we've entered the mInactive state.
-                         mInactiveState.setEnterNotificationParams(cp, cause);
-                         transitionTo(mInactiveState);
+                        mInactiveState.setEnterNotificationParams(cp, cause, -1);
+                        transitionTo(mInactiveState);
                     } else {
                         if (DBG) {
                             log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag="
@@ -1016,7 +1043,7 @@
                         // Transition to inactive but send notifications after
                         // we've entered the mInactive state.
                         mInactiveState.setEnterNotificationParams(cp,
-                                FailCause.UNACCEPTABLE_NETWORK_PARAMETER);
+                                FailCause.UNACCEPTABLE_NETWORK_PARAMETER, -1);
                         transitionTo(mInactiveState);
                     } else {
                         if (DBG) {
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 2e8b709..07780ed 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -3010,6 +3010,7 @@
             }
         } else {
             dataCall.status = p.readInt();
+            dataCall.suggestedRetryTime = p.readInt();
             dataCall.cid = p.readInt();
             dataCall.active = p.readInt();
             dataCall.type = p.readString();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 645bc69..2118095 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1332,7 +1332,8 @@
         return retry;
     }
 
-    private void reconnectAfterFail(FailCause lastFailCauseCode, ApnContext apnContext) {
+    private void reconnectAfterFail(FailCause lastFailCauseCode,
+                                    ApnContext apnContext, int retryOverride) {
         if (apnContext == null) {
             loge("reconnectAfterFail: apnContext == null, impossible");
             return;
@@ -1357,9 +1358,14 @@
                 }
             }
 
-            int nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
+            // If retry needs to be backed off for specific case (determined by RIL/Modem)
+            // use the specified timer instead of pre-configured retry pattern.
+            int nextReconnectDelay = retryOverride;
+            if (nextReconnectDelay < 0) {
+                nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
+                apnContext.getDataConnection().increaseRetryCount();
+            }
             startAlarmForReconnect(nextReconnectDelay, apnContext);
-            apnContext.getDataConnection().increaseRetryCount();
 
             if (!shouldPostNotification(lastFailCauseCode)) {
                 if (DBG) {
@@ -1664,7 +1670,13 @@
                     }
                 } else {
                     if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
-                    startDelayedRetry(cause, apnContext);
+                    // check to see if retry should be overridden for this failure.
+                    int retryOverride = -1;
+                    if (ar.exception instanceof DataConnection.CallSetupException) {
+                        retryOverride =
+                            ((DataConnection.CallSetupException)ar.exception).getRetryOverride();
+                    }
+                    startDelayedRetry(cause, apnContext, retryOverride);
                 }
             } else {
                 if (DBG) log("onDataSetupComplete: Try next APN");
@@ -1936,9 +1948,10 @@
         return result.toString();
     }
 
-    private void startDelayedRetry(GsmDataConnection.FailCause cause, ApnContext apnContext) {
+    private void startDelayedRetry(GsmDataConnection.FailCause cause,
+                                   ApnContext apnContext, int retryOverride) {
         notifyNoData(cause, apnContext);
-        reconnectAfterFail(cause, apnContext);
+        reconnectAfterFail(cause, apnContext, retryOverride);
     }
 
     private void setPreferredApn(int pos) {