Merge "Fix setting audio group mode in SipPhone." into gingerbread
diff --git a/core/java/android/nfc/technology/IsoDep.java b/core/java/android/nfc/technology/IsoDep.java
index 118bff7..52a453fa 100644
--- a/core/java/android/nfc/technology/IsoDep.java
+++ b/core/java/android/nfc/technology/IsoDep.java
@@ -64,19 +64,4 @@
      * 3B only
      */
     public byte[] getAttrib() { return mAttrib; }
-
-    /**
-     * Attempts to select the given application on the tag. Note that this only works
-     * if the tag supports ISO7816-4, which not all IsoDep tags support. If the tag doesn't
-     * support ISO7816-4 this will throw {@link UnsupportedOperationException}.
-     *
-     * This method requires that you call {@link #connect} before calling it.
-     *
-     * @throws IOException, UnsupportedOperationException
-     */
-    public void selectAid(byte[] aid) throws IOException, UnsupportedOperationException {
-        checkConnected();
-
-        throw new UnsupportedOperationException();
-    }
 }
diff --git a/core/java/android/nfc/technology/MifareClassic.java b/core/java/android/nfc/technology/MifareClassic.java
index 8a9ebf1..799f0a78 100644
--- a/core/java/android/nfc/technology/MifareClassic.java
+++ b/core/java/android/nfc/technology/MifareClassic.java
@@ -205,6 +205,15 @@
         return getBlockCount(sector) * 16;
     }
 
+    public int getTotalBlockCount() {
+        int totalBlocks = 0;
+        for (int sec = 0; sec < getSectorCount(); sec++) {
+            totalBlocks += getSectorSize(sec);
+        }
+
+        return totalBlocks;
+    }
+
     public int getBlockCount(int sector) {
         if (sector >= getSectorCount()) {
             throw new IllegalArgumentException("this card only has " + getSectorCount() +
@@ -343,9 +352,27 @@
         checkConnected();
 
         byte addr = (byte) block;
-        byte[] incr_cmd = { (byte) 0xC0, (byte) block };
+        byte[] decr_cmd = { (byte) 0xC0, (byte) block };
 
-        transceive(incr_cmd);
+        transceive(decr_cmd);
+    }
+
+    public void transfer(int block) throws IOException {
+        checkConnected();
+
+        byte addr = (byte) block;
+        byte[] trans_cmd = { (byte) 0xB0, (byte) block };
+
+        transceive(trans_cmd);
+    }
+
+    public void restore(int block) throws IOException {
+        checkConnected();
+
+        byte addr = (byte) block;
+        byte[] rest_cmd = { (byte) 0xC2, (byte) block };
+
+        transceive(rest_cmd);
     }
 
     /**
diff --git a/core/java/android/nfc/technology/Ndef.java b/core/java/android/nfc/technology/Ndef.java
index 53db0c5..05872fe 100644
--- a/core/java/android/nfc/technology/Ndef.java
+++ b/core/java/android/nfc/technology/Ndef.java
@@ -54,9 +54,22 @@
     /** @hide */
     public static final String EXTRA_NDEF_CARDSTATE = "ndefcardstate";
 
+    /** @hide */
+    public static final String EXTRA_NDEF_TYPE = "ndeftype";
+
+    //TODO: consider removing OTHER entirely - and not allowing Ndef to
+    // enumerate for tag types outside of (NFC Forum 1-4, MifareClassic)
+    public static final int OTHER = -1;
+    public static final int NFC_FORUM_TYPE_1 = 1;
+    public static final int NFC_FORUM_TYPE_2 = 2;
+    public static final int NFC_FORUM_TYPE_3 = 3;
+    public static final int NFC_FORUM_TYPE_4 = 4;
+    public static final int MIFARE_CLASSIC = 105;
+
     private final int mMaxNdefSize;
     private final int mCardState;
     private final NdefMessage mNdefMsg;
+    private final int mNdefType;
 
     /**
      * Internal constructor, to be used by NfcAdapter
@@ -68,6 +81,7 @@
             mMaxNdefSize = extras.getInt(EXTRA_NDEF_MAXLENGTH);
             mCardState = extras.getInt(EXTRA_NDEF_CARDSTATE);
             mNdefMsg = extras.getParcelable(EXTRA_NDEF_MSG);
+            mNdefType = extras.getInt(EXTRA_NDEF_TYPE);
         } else {
             throw new NullPointerException("NDEF tech extras are null.");
         }
@@ -92,6 +106,24 @@
     }
 
     /**
+     * Get NDEF tag type.
+     * <p>Returns one of {@link #NFC_FORUM_TYPE_1}, {@link #NFC_FORUM_TYPE_2},
+     * {@link #NFC_FORUM_TYPE_3}, {@link #NFC_FORUM_TYPE_4},
+     * {@link #MIFARE_CLASSIC} or {@link #OTHER}.
+     * <p>Platforms of this API revision will always return one of the above
+     * values. Platforms at future API revisions may return other values, which
+     * can be treated as {@link #OTHER} by applications targeting this API.
+     * <p>Android devices with NFC support must always correctly enumerate
+     * NFC Forum tag types, and may optionally enumerate
+     * {@link #MIFARE_CLASSIC} since it requires proprietary technology.
+     * Devices that cannot enumerate {@link #MIFARE_CLASSIC} will use
+     * {@link #OTHER} instead.
+     */
+    public int getType() {
+        return mNdefType;
+    }
+
+    /**
      * Get maximum NDEF message size in bytes
      */
     public int getMaxSize() {
diff --git a/core/java/android/nfc/technology/NfcB.java b/core/java/android/nfc/technology/NfcB.java
index 64cb08a..de528f8 100644
--- a/core/java/android/nfc/technology/NfcB.java
+++ b/core/java/android/nfc/technology/NfcB.java
@@ -44,6 +44,7 @@
     public NfcB(NfcAdapter adapter, Tag tag, Bundle extras)
             throws RemoteException {
         super(adapter, tag, TagTechnology.NFC_B);
+        mAtqb = extras.getByteArray(EXTRA_ATQB);
     }
 
     /**
diff --git a/core/java/android/nfc/technology/NfcV.java b/core/java/android/nfc/technology/NfcV.java
index 9b6a16a..460de6a 100644
--- a/core/java/android/nfc/technology/NfcV.java
+++ b/core/java/android/nfc/technology/NfcV.java
@@ -36,8 +36,27 @@
  * permission.
  */
 public final class NfcV extends BasicTagTechnology {
+    /** @hide */
+    public static final String EXTRA_RESP_FLAGS = "respflags";
+
+    /** @hide */
+    public static final String EXTRA_DSFID = "dsfid";
+
+    private byte mRespFlags;
+    private byte mDsfId;
+
     public NfcV(NfcAdapter adapter, Tag tag, Bundle extras)
             throws RemoteException {
         super(adapter, tag, TagTechnology.NFC_V);
+        mRespFlags = extras.getByte(EXTRA_RESP_FLAGS);
+        mDsfId = extras.getByte(EXTRA_DSFID);
+    }
+
+    public byte getResponseFlags() {
+        return mRespFlags;
+    }
+
+    public byte getDsfId() {
+        return mDsfId;
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 3d410fd..7d31687 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -370,23 +370,26 @@
                 case EVENT_WAKE_LOCK_TIMEOUT:
                     // Haven't heard back from the last request.  Assume we're
                     // not getting a response and  release the wake lock.
-                    // TODO should we clean up mRequestList and mRequestPending
                     synchronized (mWakeLock) {
                         if (mWakeLock.isHeld()) {
-                            if (RILJ_LOGD) {
-                                synchronized (mRequestsList) {
-                                    int count = mRequestsList.size();
-                                    Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " +
-                                        " mReqPending=" + mRequestMessagesPending +
-                                        " mRequestList=" + count);
-
-                                    for (int i = 0; i < count; i++) {
-                                        rr = mRequestsList.get(i);
-                                        Log.d(LOG_TAG, i + ": [" + rr.mSerial + "] " +
-                                            requestToString(rr.mRequest));
-
-                                    }
-                                }
+                            // The timer of WAKE_LOCK_TIMEOUT is reset with each
+                            // new send request. So when WAKE_LOCK_TIMEOUT occurs
+                            // all requests in mRequestList already waited at
+                            // least DEFAULT_WAKE_LOCK_TIMEOUT but no response.
+                            // Therefore all should be treated as lost requests.
+                            // Those lost requests return GENERIC_FAILURE and
+                            // request list is cleared.
+                            //
+                            // Note: mRequestMessagesPending shows how many
+                            //       requests are waiting to be sent (and before
+                            //       to be added in request list) since star the
+                            //       timer. It should be
+                            //       zero here since all request should already
+                            //       be put in request list while TIMEOUT occurs.
+                            clearRequestsList(GENERIC_FAILURE, true);
+                            if (mRequestMessagesPending != 0) {
+                                Log.e(LOG_TAG, "ERROR: mReqPending is NOT 0 at TIMEOUT, "
+                                    + "mReqPending = " + mRequestMessagesPending);
                             }
                             mWakeLock.release();
                         }
@@ -558,15 +561,7 @@
                 RILRequest.resetSerial();
 
                 // Clear request list on close
-                synchronized (mRequestsList) {
-                    for (int i = 0, sz = mRequestsList.size() ; i < sz ; i++) {
-                        RILRequest rr = mRequestsList.get(i);
-                        rr.onError(RADIO_NOT_AVAILABLE, null);
-                        rr.release();
-                    }
-
-                    mRequestsList.clear();
-                }
+                clearRequestsList(RADIO_NOT_AVAILABLE, false);
             }} catch (Throwable tr) {
                 Log.e(LOG_TAG,"Uncaught exception", tr);
             }
@@ -2061,6 +2056,34 @@
         releaseWakeLockIfDone();
     }
 
+    /**
+     * Release each request in mReqeustsList then clear the list
+     * @param error is the RIL_Errno sent back
+     * @param loggable true means to print all requests in mRequestslist
+     */
+    private void clearRequestsList(int error, boolean loggable) {
+        RILRequest rr;
+        synchronized (mRequestsList) {
+            int count = mRequestsList.size();
+            if (RILJ_LOGD && loggable) {
+                Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " +
+                        " mReqPending=" + mRequestMessagesPending +
+                        " mRequestList=" + count);
+            }
+
+            for (int i = 0; i < count ; i++) {
+                rr = mRequestsList.get(i);
+                if (RILJ_LOGD && loggable) {
+                    Log.d(LOG_TAG, i + ": [" + rr.mSerial + "] " +
+                            requestToString(rr.mRequest));
+                }
+                rr.onError(error, null);
+                rr.release();
+            }
+            mRequestsList.clear();
+        }
+    }
+
     private RILRequest findAndRemoveRequestFromList(int serial) {
         synchronized (mRequestsList) {
             for (int i = 0, s = mRequestsList.size() ; i < s ; i++) {
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 0c8a725..60abf2a 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -63,6 +63,14 @@
 // real jitter buffer. For a stream at 8000Hz it takes 8192 bytes. These numbers
 // are chosen by experiments and each of them can be adjusted as needed.
 
+// Originally a stream does not send packets when it is receive-only or there is
+// nothing to mix. However, this causes some problems with certain firewalls and
+// proxies. A firewall might remove a port mapping when there is no outgoing
+// packet for a preiod of time, and a proxy might wait for incoming packets from
+// both sides before start forwarding. To solve these problems, we send out a
+// silence packet on the stream for every second. It should be good enough to
+// keep the stream alive with relatively low resources.
+
 // Other notes:
 // + We use elapsedRealtime() to get the time. Since we use 32bit variables
 //   instead of 64bit ones, comparison must be done by subtraction.
@@ -110,7 +118,7 @@
     int mSampleRate;
     int mSampleCount;
     int mInterval;
-    int mLogThrottle;
+    int mKeepAlive;
 
     int16_t *mBuffer;
     int mBufferMask;
@@ -262,12 +270,8 @@
     ++mSequence;
     mTimestamp += mSampleCount;
 
-    if (mMode == RECEIVE_ONLY) {
-        return;
-    }
-
     // If there is an ongoing DTMF event, send it now.
-    if (mDtmfEvent != -1) {
+    if (mMode != RECEIVE_ONLY && mDtmfEvent != -1) {
         int duration = mTimestamp - mDtmfStart;
         // Make sure duration is reasonable.
         if (duration >= 0 && duration < mSampleRate * 100) {
@@ -289,43 +293,55 @@
         mDtmfEvent = -1;
     }
 
-    // It is time to mix streams.
-    bool mixed = false;
     int32_t buffer[mSampleCount + 3];
-    memset(buffer, 0, sizeof(buffer));
-    while (chain) {
-        if (chain != this &&
-            chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
-            mixed = true;
+    int16_t samples[mSampleCount];
+    if (mMode == RECEIVE_ONLY) {
+        if ((mTick ^ mKeepAlive) >> 10 == 0) {
+            return;
         }
-        chain = chain->mNext;
-    }
-    if (!mixed) {
-        if ((mTick ^ mLogThrottle) >> 10) {
-            mLogThrottle = mTick;
+        mKeepAlive = mTick;
+        memset(samples, 0, sizeof(samples));
+    } else {
+        // Mix all other streams.
+        bool mixed = false;
+        memset(buffer, 0, sizeof(buffer));
+        while (chain) {
+            if (chain != this &&
+                chain->mix(buffer, tick - mInterval, tick, mSampleRate)) {
+                mixed = true;
+            }
+            chain = chain->mNext;
+        }
+
+        if (mixed) {
+            // Saturate into 16 bits.
+            for (int i = 0; i < mSampleCount; ++i) {
+                int32_t sample = buffer[i];
+                if (sample < -32768) {
+                    sample = -32768;
+                }
+                if (sample > 32767) {
+                    sample = 32767;
+                }
+                samples[i] = sample;
+            }
+        } else {
+            if ((mTick ^ mKeepAlive) >> 10 == 0) {
+                return;
+            }
+            mKeepAlive = mTick;
+            memset(samples, 0, sizeof(samples));
             LOGV("stream[%d] no data", mSocket);
         }
-        return;
     }
 
-    // Cook the packet and send it out.
-    int16_t samples[mSampleCount];
-    for (int i = 0; i < mSampleCount; ++i) {
-        int32_t sample = buffer[i];
-        if (sample < -32768) {
-            sample = -32768;
-        }
-        if (sample > 32767) {
-            sample = 32767;
-        }
-        samples[i] = sample;
-    }
     if (!mCodec) {
         // Special case for device stream.
         send(mSocket, samples, sizeof(samples), MSG_DONTWAIT);
         return;
     }
 
+    // Cook the packet and send it out.
     buffer[0] = htonl(mCodecMagic | mSequence);
     buffer[1] = htonl(mTimestamp);
     buffer[2] = mSsrc;
@@ -883,7 +899,7 @@
     int codecType = -1;
     char codecName[16];
     int sampleRate = -1;
-    sscanf(codecSpec, "%d %[^/]%*c%d", &codecType, codecName, &sampleRate);
+    sscanf(codecSpec, "%d %15[^/]%*c%d", &codecType, codecName, &sampleRate);
     codec = newAudioCodec(codecName);
     int sampleCount = (codec ? codec->set(sampleRate, codecSpec) : -1);
     env->ReleaseStringUTFChars(jCodecSpec, codecSpec);