Merge "Just in case we're behind a NAT router/firewall, attempt to poke holes into it for future incoming RTP/RTCP packets to pass through." into gingerbread
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 9494a06..c185007 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -104,6 +104,10 @@
     // Only show an annoying dialog at most every 30 seconds
     private static final long MIN_DIALOG_INTERVAL_MS = 30000;
 
+    // How many offending stacks to keep track of (and time) per loop
+    // of the Looper.
+    private static final int MAX_OFFENSES_PER_LOOP = 10;
+
     // Thread-policy:
 
     /**
@@ -680,6 +684,17 @@
         }
     }
 
+    private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
+            new ThreadLocal<ArrayList<ViolationInfo>>() {
+        @Override protected ArrayList<ViolationInfo> initialValue() {
+            return new ArrayList<ViolationInfo>();
+        }
+    };
+
+    private static boolean tooManyViolationsThisLoop() {
+        return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP;
+    }
+
     private static class AndroidBlockGuardPolicy implements BlockGuard.Policy {
         private int mPolicyMask;
 
@@ -707,6 +722,9 @@
             if ((mPolicyMask & DETECT_DISK_WRITE) == 0) {
                 return;
             }
+            if (tooManyViolationsThisLoop()) {
+                return;
+            }
             BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
             e.fillInStackTrace();
             startHandlingViolationException(e);
@@ -717,6 +735,9 @@
             if ((mPolicyMask & DETECT_DISK_READ) == 0) {
                 return;
             }
+            if (tooManyViolationsThisLoop()) {
+                return;
+            }
             BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
             e.fillInStackTrace();
             startHandlingViolationException(e);
@@ -727,6 +748,9 @@
             if ((mPolicyMask & DETECT_NETWORK) == 0) {
                 return;
             }
+            if (tooManyViolationsThisLoop()) {
+                return;
+            }
             BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
             e.fillInStackTrace();
             startHandlingViolationException(e);
@@ -747,13 +771,6 @@
             handleViolationWithTimingAttempt(info);
         }
 
-        private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
-                new ThreadLocal<ArrayList<ViolationInfo>>() {
-            @Override protected ArrayList<ViolationInfo> initialValue() {
-                return new ArrayList<ViolationInfo>();
-            }
-        };
-
         // Attempts to fill in the provided ViolationInfo's
         // durationMillis field if this thread has a Looper we can use
         // to measure with.  We measure from the time of violation
@@ -780,7 +797,7 @@
 
             MessageQueue queue = Looper.myQueue();
             final ArrayList<ViolationInfo> records = violationsBeingTimed.get();
-            if (records.size() >= 10) {
+            if (records.size() >= MAX_OFFENSES_PER_LOOP) {
                 // Not worth measuring.  Too many offenses in one loop.
                 return;
             }
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 87271e7..f9c1679 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -493,6 +493,11 @@
                 + " info: " + info);
         }
 
+        if (info != null) {
+            native_update_network_state(info.isConnected(), info.getType(),
+                    info.isRoaming(), info.getExtraInfo());
+        }
+
         if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
                 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
             String apnName = info.getExtraInfo();
@@ -1601,4 +1606,7 @@
     private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
             int lac, int cid);
     private native void native_agps_set_id(int type, String setid);
+
+    private native void native_update_network_state(boolean connected, int type,
+            boolean roaming, String extraInfo);
 }
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index bd722d7..43e8467 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -586,6 +586,23 @@
     return result;
 }
 
+static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj,
+        jboolean connected, int type, jboolean roaming, jstring extraInfo)
+{
+    const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj);
+    if (interface &&
+            (interface->size > ((char *)&interface->update_network_state - (char *)&interface)) &&
+            interface->update_network_state) {
+        if (extraInfo) {
+            const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
+            interface->update_network_state(connected, type, roaming, extraInfoStr);
+            env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
+        } else {
+            interface->update_network_state(connected, type, roaming, NULL);
+        }
+    }
+}
+
 static JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
@@ -611,6 +628,7 @@
     {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
     {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
     {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
+    {"native_update_network_state", "(ZIZLjava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
 };
 
 int register_android_server_location_GpsLocationProvider(JNIEnv* env)
diff --git a/telephony/mockril/src/com/android/internal/telephony/mockril/MockRilController.java b/telephony/mockril/src/com/android/internal/telephony/mockril/MockRilController.java
index 9b6a850..99f0abe 100644
--- a/telephony/mockril/src/com/android/internal/telephony/mockril/MockRilController.java
+++ b/telephony/mockril/src/com/android/internal/telephony/mockril/MockRilController.java
@@ -134,17 +134,15 @@
         return curstate == state;
     }
 
-
-
     /**
-     * Set an MT call
+     * Start an incoming call for the given phone number
      *
-     * @param phoneNumber for the number shown
+     * @param phoneNumber is the number to show as incoming call
+     * @return true if the incoming call is started successfully, false if it fails.
      */
-    public boolean setMTCall(String phoneNumber) {
+    public boolean startIncomingCall(String phoneNumber) {
         RilCtrlCmds.CtrlReqSetMTCall req = new RilCtrlCmds.CtrlReqSetMTCall();
 
-        // Check whether it is a valid number
         req.setPhoneNumber(phoneNumber);
         if (!sendCtrlCommand(RilCtrlCmds.CTRL_CMD_SET_MT_CALL, 0, 0, req)) {
             Log.v(TAG, "send CMD_SET_MT_CALL request failed");
@@ -153,4 +151,68 @@
         return true;
     }
 
+    /**
+     * Hang up a connection remotelly for the given call fail cause
+     *
+     * @param connectionID is the connection to be hung up
+     * @param failCause is the call fail cause defined in ril.h
+     * @return true if the hangup is successful, false if it fails
+     */
+    public boolean hangupRemote(int connectionId, int failCause) {
+        RilCtrlCmds.CtrlHangupConnRemote req = new RilCtrlCmds.CtrlHangupConnRemote();
+        req.setConnectionId(connectionId);
+        req.setCallFailCause(failCause);
+
+        if (!sendCtrlCommand(RilCtrlCmds.CTRL_CMD_HANGUP_CONN_REMOTE, 0, 0, req)) {
+            Log.v(TAG, "send CTRL_CMD_HANGUP_CONN_REMOTE request failed");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Set call transition flag to the Mock Ril
+     *
+     * @param flag is a boolean value for the call transiton flag
+     *             true: call transition: dialing->alert, alert->active is controlled
+     *             false: call transition is automatically handled by Mock Ril
+     * @return true if the request is successful, false if it failed to set the flag
+     */
+    public boolean setCallTransitionFlag(boolean flag) {
+        RilCtrlCmds.CtrlSetCallTransitionFlag req = new RilCtrlCmds.CtrlSetCallTransitionFlag();
+
+        req.setFlag(flag);
+
+        if (!sendCtrlCommand(RilCtrlCmds.CTRL_CMD_SET_CALL_TRANSITION_FLAG, 0, 0, req)) {
+            Log.v(TAG, "send CTRL_CMD_SET_CALL_TRANSITION_FLAG request failed");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Set the dialing call to alert if the call transition flag is true
+     *
+     * @return true if the call transition is successful, false if it fails
+     */
+    public boolean setDialCallToAlert() {
+        if (!sendCtrlCommand(RilCtrlCmds.CTRL_CMD_SET_CALL_ALERT, 0, 0, null)) {
+            Log.v(TAG, "send CTRL_CMD_SET_CALL_ALERT request failed");
+            return false;
+        }
+        return true;
+   }
+
+   /**
+    * Set the alert call to active if the call transition flag is true
+    *
+    * @return true if the call transition is successful, false if it fails
+    */
+   public boolean setAlertCallToActive() {
+        if (!sendCtrlCommand(RilCtrlCmds.CTRL_CMD_SET_CALL_ACTIVE, 0, 0, null)) {
+            Log.v(TAG, "send CTRL_CMD_SET_CALL_ACTIVE request failed");
+            return false;
+        }
+        return true;
+   }
 }
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java
index f0d5b31..3149ee1 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/mockril/MockRilTest.java
@@ -55,7 +55,7 @@
     }
 
     /**
-     * Test protobuf serialization and deserialization
+     * Test Case 1: Test protobuf serialization and deserialization
      * @throws InvalidProtocolBufferMicroException
      */
     public void testProtobufSerDes() throws InvalidProtocolBufferMicroException {
@@ -77,7 +77,7 @@
     }
 
     /**
-     * Test echo command works using writeMsg & readMsg
+     * Test case 2: Test echo command works using writeMsg & readMsg
      */
     public void testEchoMsg() throws IOException {
         log("testEchoMsg E");
@@ -110,7 +110,7 @@
     }
 
     /**
-     * Test get as
+     * Test case 3: Test get as
      */
     public void testGetAs() {
         log("testGetAs E");
@@ -150,6 +150,9 @@
         log("testGetAs X");
     }
 
+    /**
+     * Test case 3: test get radio state
+     */
     public void testGetRadioState() throws IOException {
         log("testGetRadioState E");
 
@@ -175,6 +178,9 @@
         log("testGetRadioState X");
     }
 
+    /**
+     * Test case 5: test set radio state
+     */
     public void testSetRadioState() throws IOException {
         log("testSetRadioState E");
 
@@ -187,6 +193,9 @@
         Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_RADIO_STATE, 0, 0, cmdrs);
 
         Msg resp = Msg.recv(mMockRilChannel);
+        log("get response status :" + resp.getStatus());
+        log("get response for command: " + resp.getCmd());
+        log("get command token: " + resp.getToken());
 
         RilCtrlCmds.CtrlRspRadioState rsp = resp.getDataAs(RilCtrlCmds.CtrlRspRadioState.class);
 
@@ -194,4 +203,102 @@
         log("get response for testSetRadioState: " + state);
         assertTrue(RilCmds.RADIOSTATE_SIM_NOT_READY == state);
     }
+
+    /**
+     * Test case 6: test start incoming call and hangup it.
+     */
+    public void testStartIncomingCallAndHangup() throws IOException {
+        log("testStartIncomingCallAndHangup");
+        RilCtrlCmds.CtrlReqSetMTCall cmd = new RilCtrlCmds.CtrlReqSetMTCall();
+        String incomingCall = "6502889108";
+        // set the MT call
+        cmd.setPhoneNumber(incomingCall);
+        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_MT_CALL, 0, 0, cmd);
+        // get response
+        Msg resp = Msg.recv(mMockRilChannel);
+        log("Get response status: " + resp.getStatus());
+        assertTrue("The ril is not in a proper state to set MT calls.",
+                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);
+
+        // allow the incoming call alerting for some time
+        try {
+            Thread.sleep(5000);
+        } catch (InterruptedException e) {}
+
+        // we are playing a trick to assume the current is 1
+        RilCtrlCmds.CtrlHangupConnRemote hangupCmd = new RilCtrlCmds.CtrlHangupConnRemote();
+        hangupCmd.setConnectionId(1);
+        hangupCmd.setCallFailCause(16);   // normal hangup
+        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_HANGUP_CONN_REMOTE, 0, 0, hangupCmd);
+
+        // get response
+        resp = Msg.recv(mMockRilChannel);
+        log("Get response for hangup connection: " + resp.getStatus());
+        assertTrue("CTRL_CMD_HANGUP_CONN_REMOTE failed",
+                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);
+    }
+
+    /**
+     * Test case 7: test set call transition flag
+     */
+    public void testSetCallTransitionFlag() throws IOException {
+        log("testSetCallTransitionFlag");
+        // Set flag to true:
+        RilCtrlCmds.CtrlSetCallTransitionFlag cmd = new RilCtrlCmds.CtrlSetCallTransitionFlag();
+        cmd.setFlag(true);
+        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_CALL_TRANSITION_FLAG, 0, 0, cmd);
+
+        Msg resp = Msg.recv(mMockRilChannel);
+        log("Get response status: " + resp.getStatus());
+        assertTrue("Set call transition flag failed",
+                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);
+
+        // add a dialing call
+        RilCtrlCmds.CtrlReqAddDialingCall cmdDialCall = new RilCtrlCmds.CtrlReqAddDialingCall();
+        String phoneNumber = "5102345678";
+        cmdDialCall.setPhoneNumber(phoneNumber);
+        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_ADD_DIALING_CALL, 0, 0, cmdDialCall);
+        resp = Msg.recv(mMockRilChannel);
+        log("Get response status for adding a dialing call: " + resp.getStatus());
+        assertTrue("add dialing call failed",
+                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);
+        try {
+            Thread.sleep(5000);
+        } catch (InterruptedException e) {}
+
+        // send command to force call state change
+        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_CALL_ALERT, 0, 0, null);
+        resp = Msg.recv(mMockRilChannel);
+        log("Get response status: " + resp.getStatus());
+        assertTrue("Set call alert failed",
+                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);
+
+        try {
+            Thread.sleep(2000);
+        } catch (InterruptedException e) {}
+
+        // send command to force call state change
+        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_CALL_ACTIVE, 0, 0, null);
+        resp = Msg.recv(mMockRilChannel);
+        log("Get response status: " + resp.getStatus());
+        assertTrue("Set call active failed",
+                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);
+
+        // hangup the active all remotely
+        RilCtrlCmds.CtrlHangupConnRemote hangupCmd = new RilCtrlCmds.CtrlHangupConnRemote();
+        hangupCmd.setConnectionId(1);
+        hangupCmd.setCallFailCause(16);   // normal hangup
+        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_HANGUP_CONN_REMOTE, 0, 0, hangupCmd);
+        resp = Msg.recv(mMockRilChannel);
+        log("Get response for hangup connection: " + resp.getStatus());
+        assertTrue("CTRL_CMD_HANGUP_CONN_REMOTE failed",
+                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);
+
+        // set the flag to false
+        cmd.setFlag(false);
+        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_CALL_TRANSITION_FLAG, 0, 0, cmd);
+        resp = Msg.recv(mMockRilChannel);
+        assertTrue("Set call transition flag failed",
+                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);
+    }
 }