Merge "Provisional support for secure decryption of media streams."
diff --git a/api/current.txt b/api/current.txt
index bebbf36..2a64ee1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11924,8 +11924,10 @@
     method public java.lang.String[] getDefaultCipherSuites();
     method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
     method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
+    method public byte[] getNpnSelectedProtocol(java.net.Socket);
     method public java.lang.String[] getSupportedCipherSuites();
     method public void setKeyManagers(javax.net.ssl.KeyManager[]);
+    method public void setNpnProtocols(byte[][]);
     method public void setTrustManagers(javax.net.ssl.TrustManager[]);
   }
 
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 7f94a96..c2c749a 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -332,12 +332,15 @@
         ret = 0;
         // Make the /data/user directory if necessary
         if (access(user_data_dir, R_OK) < 0) {
-            if (mkdir(user_data_dir, 0755) < 0) {
+            if (mkdir(user_data_dir, 0711) < 0) {
                 return -1;
             }
             if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {
                 return -1;
             }
+            if (chmod(user_data_dir, 0711) < 0) {
+                return -1;
+            }
         }
         // Make the /data/user/0 symlink to /data/data if necessary
         if (access(primary_data_dir, R_OK) < 0) {
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 8b55c8fa..52a9293 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -4,18 +4,18 @@
 
 LOCAL_SRC_FILES:=       \
 	stagefright.cpp \
+	jpeg.cpp	\
 	SineSource.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia libmedia_native libutils libbinder libstagefright_foundation \
-        libskia libgui
+        libjpeg libgui
 
 LOCAL_C_INCLUDES:= \
 	frameworks/base/media/libstagefright \
 	frameworks/base/media/libstagefright/include \
 	$(TOP)/frameworks/native/include/media/openmax \
-	external/skia/include/core \
-	external/skia/include/images \
+	external/jpeg \
 
 LOCAL_CFLAGS += -Wno-multichar
 
diff --git a/cmds/stagefright/jpeg.cpp b/cmds/stagefright/jpeg.cpp
new file mode 100644
index 0000000..7e859c3
--- /dev/null
+++ b/cmds/stagefright/jpeg.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdio.h>
+
+extern "C" {
+#include "jpeglib.h"
+}
+
+static inline uint8_t from565to8(uint16_t p, int start, int bits) {
+    uint8_t c = (p >> start) & ((1 << bits) - 1);
+    return (c << (8 - bits)) | (c >> (bits - (8 - bits)));
+}
+
+struct sf_jpeg_error_mgr {
+    struct jpeg_error_mgr jerr;
+    jmp_buf longjmp_buffer;
+};
+
+void sf_jpeg_error_exit(j_common_ptr cinfo) {
+    struct sf_jpeg_error_mgr *sf_err = (struct sf_jpeg_error_mgr *)cinfo->err;
+    longjmp(sf_err->longjmp_buffer, 0);
+}
+
+int writeJpegFile(const char *filename, uint8_t *frame, int width, int height) {
+    struct sf_jpeg_error_mgr sf_err;
+    struct jpeg_compress_struct cinfo;
+    uint8_t row_data[width * 3];
+    JSAMPROW row_pointer = row_data;
+    FILE *f;
+
+    f = fopen(filename, "w");
+    if (!f) {
+        return -errno;
+    }
+
+    cinfo.err = jpeg_std_error(&sf_err.jerr);
+    sf_err.jerr.error_exit = sf_jpeg_error_exit;
+    if (setjmp(sf_err.longjmp_buffer)) {
+        jpeg_destroy_compress(&cinfo);
+        fclose(f);
+        return -1;
+    }
+
+    jpeg_create_compress(&cinfo);
+    jpeg_stdio_dest(&cinfo, f);
+
+    cinfo.image_width = width;
+    cinfo.image_height = height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, 80, TRUE);
+
+    jpeg_start_compress(&cinfo, TRUE);
+
+    for (int row = 0; row < height; row++) {
+        uint16_t *src = (uint16_t *)(frame + row * width * 2);
+        uint8_t *dst = row_data;
+        for (int col = 0; col < width; col++) {
+            dst[0] = from565to8(*src, 11, 5);
+            dst[1] = from565to8(*src, 5, 6);
+            dst[2] = from565to8(*src, 0, 5);
+            dst += 3;
+            src++;
+        }
+        jpeg_write_scanlines(&cinfo, &row_pointer, 1);
+    }
+
+    jpeg_finish_compress(&cinfo);
+    jpeg_destroy_compress(&cinfo);
+
+    fclose(f);
+    return 0;
+}
diff --git a/cmds/stagefright/jpeg.h b/cmds/stagefright/jpeg.h
new file mode 100644
index 0000000..ce86cf2
--- /dev/null
+++ b/cmds/stagefright/jpeg.h
@@ -0,0 +1,6 @@
+#ifndef _STAGEFRIGHT_JPEG_H_
+#define _STAGEFRIGHT_JPEG_H_
+
+int writeJpegFile(const char *filename, uint8_t *frame, int width, int height);
+
+#endif
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index dab2e0f..d70c862 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "jpeg.h"
 #include "SineSource.h"
 
 #include <binder/IServiceManager.h>
@@ -49,8 +50,6 @@
 #include <media/stagefright/MPEG4Writer.h>
 
 #include <private/media/VideoFrame.h>
-#include <SkBitmap.h>
-#include <SkImageEncoder.h>
 
 #include <fcntl.h>
 
@@ -787,16 +786,9 @@
 
                 VideoFrame *frame = (VideoFrame *)mem->pointer();
 
-                SkBitmap bitmap;
-                bitmap.setConfig(
-                        SkBitmap::kRGB_565_Config, frame->mWidth, frame->mHeight);
-
-                bitmap.setPixels((uint8_t *)frame + sizeof(VideoFrame));
-
-                CHECK(SkImageEncoder::EncodeFile(
-                            "/sdcard/out.jpg", bitmap,
-                            SkImageEncoder::kJPEG_Type,
-                            SkImageEncoder::kDefaultQuality));
+                CHECK_EQ(writeJpegFile("/sdcard/out.jpg",
+                            (uint8_t *)frame + sizeof(VideoFrame),
+                            frame->mWidth, frame->mHeight), 0);
             }
 
             {
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 5c4b258..6a4f1f2 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -18,13 +18,11 @@
 
 import android.os.SystemProperties;
 import android.util.Log;
-
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.security.KeyManagementException;
 import java.security.cert.X509Certificate;
-
 import javax.net.SocketFactory;
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
@@ -36,7 +34,6 @@
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
-
 import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl;
 import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
 import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
@@ -89,6 +86,7 @@
     private SSLSocketFactory mSecureFactory = null;
     private TrustManager[] mTrustManagers = null;
     private KeyManager[] mKeyManagers = null;
+    private byte[] mNpnProtocols = null;
 
     private final int mHandshakeTimeoutMillis;
     private final SSLClientSessionCache mSessionCache;
@@ -251,6 +249,60 @@
     }
 
     /**
+     * Sets the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
+     * Protocol Negotiation (NPN)</a> protocols that this peer is interested in.
+     *
+     * <p>For servers this is the sequence of protocols to advertise as
+     * supported, in order of preference. This list is sent unencrypted to
+     * all clients that support NPN.
+     *
+     * <p>For clients this is a list of supported protocols to match against the
+     * server's list. If there is no protocol supported by both client and
+     * server then the first protocol in the client's list will be selected.
+     * The order of the client's protocols is otherwise insignificant.
+     *
+     * @param npnProtocols a possibly-empty list of protocol byte arrays. All
+     *     arrays must be non-empty and of length less than 256.
+     */
+    public void setNpnProtocols(byte[][] npnProtocols) {
+        this.mNpnProtocols = toNpnProtocolsList(npnProtocols);
+    }
+
+    /**
+     * Returns an array containing the concatenation of length-prefixed byte
+     * strings.
+     */
+    static byte[] toNpnProtocolsList(byte[]... npnProtocols) {
+        int totalLength = 0;
+        for (byte[] s : npnProtocols) {
+            if (s.length == 0 || s.length > 255) {
+                throw new IllegalArgumentException("s.length == 0 || s.length > 255: " + s.length);
+            }
+            totalLength += 1 + s.length;
+        }
+        byte[] result = new byte[totalLength];
+        int pos = 0;
+        for (byte[] s : npnProtocols) {
+            result[pos++] = (byte) s.length;
+            for (byte b : s) {
+                result[pos++] = b;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
+     * Protocol Negotiation (NPN)</a> protocol selected by client and server, or
+     * null if no protocol was negotiated.
+     *
+     * @param socket a socket created by this factory.
+     */
+    public byte[] getNpnSelectedProtocol(Socket socket) {
+        return ((OpenSSLSocketImpl) socket).getNpnSelectedProtocol();
+    }
+
+    /**
      * Sets the {@link KeyManager}s to be used for connections made by this factory.
      */
     public void setKeyManagers(KeyManager[] keyManagers) {
@@ -271,6 +323,7 @@
     @Override
     public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
+        s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
         if (mSecure) {
             verifyHostname(s, host);
@@ -289,6 +342,7 @@
     @Override
     public Socket createSocket() throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
+        s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
         return s;
     }
@@ -305,6 +359,7 @@
             throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
                 addr, port, localAddr, localPort);
+        s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
         return s;
     }
@@ -319,6 +374,7 @@
     @Override
     public Socket createSocket(InetAddress addr, int port) throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
+        s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
         return s;
     }
@@ -334,6 +390,7 @@
             throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
                 host, port, localAddr, localPort);
+        s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
         if (mSecure) {
             verifyHostname(s, host);
@@ -350,6 +407,7 @@
     @Override
     public Socket createSocket(String host, int port) throws IOException {
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
+        s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
         if (mSecure) {
             verifyHostname(s, host);
diff --git a/core/java/android/webkit/FindListener.java b/core/java/android/webkit/FindListener.java
deleted file mode 100644
index 124f737..0000000
--- a/core/java/android/webkit/FindListener.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012 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.webkit;
-
-/**
- * @hide
- */
-public interface FindListener {
-    /**
-     * Notify the host application that a find result is available.
-     *
-     * @param numberOfMatches How many matches have been found
-     * @param activeMatchOrdinal The ordinal of the currently selected match
-     * @param isDoneCounting Whether we have finished counting matches
-     */
-    public void onFindResultReceived(int numberOfMatches,
-        int activeMatchOrdinal, boolean isDoneCounting);
-}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index dd373de..d225594 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -312,6 +312,24 @@
     public static final String SCHEME_GEO = "geo:0,0?q=";
 
     /**
+     * Interface to listen for find results.
+     * @hide
+     */
+    public interface FindListener {
+        /**
+         * Notify the listener about progress made by a find operation.
+         *
+         * @param numberOfMatches How many matches have been found.
+         * @param activeMatchOrdinal The zero-based ordinal of the currently selected match.
+         * @param isDoneCounting Whether the find operation has actually completed. The listener
+         * may be notified multiple times while the operation is underway, and the numberOfMatches
+         * value should not be considered final unless isDoneCounting is true.
+         */
+        public void onFindResultReceived(int numberOfMatches, int activeMatchOrdinal,
+            boolean isDoneCounting);
+    }
+
+    /**
      * Interface to listen for new pictures as they change.
      * @deprecated This interface is now obsolete.
      */
@@ -1228,10 +1246,10 @@
     }
 
     /**
-     * Register the interface to be used when a find-on-page result has become
-     * available. This will replace the current handler.
+     * Register the listener to be notified as find-on-page operations progress.
+     * This will replace the current listener.
      *
-     * @param listener An implementation of FindListener
+     * @param listener An implementation of {@link WebView#FindListener}.
      * @hide
      */
     public void setFindListener(FindListener listener) {
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 03329b8..ab2db22 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -1440,7 +1440,7 @@
     private PictureListener mPictureListener;
 
     // Used to notify listeners about find-on-page results.
-    private FindListener mFindListener;
+    private WebView.FindListener mFindListener;
 
     /**
      * Refer to {@link WebView#requestFocusNodeHref(Message)} for more information
@@ -3620,12 +3620,10 @@
     }
 
     /**
-     * Register the interface to be used when a find-on-page result has become
-     * available. This will replace the current handler.
-     *
-     * @param listener An implementation of FindListener
+     * See {@link WebView#setFindListener(WebView.FindListener)}.
+     * @hide
      */
-     public void setFindListener(FindListener listener) {
+     public void setFindListener(WebView.FindListener listener) {
          mFindListener = listener;
      }
 
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 7d47e14..f049198 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -192,7 +192,7 @@
 
     public WebBackForwardList copyBackForwardList();
 
-    public void setFindListener(FindListener listener);
+    public void setFindListener(WebView.FindListener listener);
 
     public void findNext(boolean forward);
 
diff --git a/core/tests/coretests/src/android/net/SSLTest.java b/core/tests/coretests/src/android/net/SSLTest.java
index 810ed0d..c573498 100644
--- a/core/tests/coretests/src/android/net/SSLTest.java
+++ b/core/tests/coretests/src/android/net/SSLTest.java
@@ -16,17 +16,16 @@
 
 package android.net;
 
-import android.net.SSLCertificateSocketFactory;
 import android.test.suitebuilder.annotation.Suppress;
-import junit.framework.TestCase;
-
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.Socket;
+import java.util.Arrays;
+import junit.framework.TestCase;
 
-//This test relies on network resources.
-@Suppress
 public class SSLTest extends TestCase {
+    //This test relies on network resources.
+    @Suppress
     public void testCertificate() throws Exception {
         // test www.fortify.net/sslcheck.html
         Socket ssl = SSLCertificateSocketFactory.getDefault().createSocket("www.fortify.net",443);
@@ -49,4 +48,35 @@
 
         // System.out.println(new String(b));
     }
+
+    public void testStringsToNpnBytes() {
+        byte[] expected = {
+                6, 's', 'p', 'd', 'y', '/', '2',
+                8, 'h', 't', 't', 'p', '/', '1', '.', '1',
+        };
+        assertTrue(Arrays.equals(expected, SSLCertificateSocketFactory.toNpnProtocolsList(
+                new byte[] { 's', 'p', 'd', 'y', '/', '2' },
+                new byte[] { 'h', 't', 't', 'p', '/', '1', '.', '1' })));
+    }
+
+    public void testStringsToNpnBytesEmptyByteArray() {
+        try {
+            SSLCertificateSocketFactory.toNpnProtocolsList(new byte[0]);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    public void testStringsToNpnBytesEmptyArray() {
+        byte[] expected = {};
+        assertTrue(Arrays.equals(expected, SSLCertificateSocketFactory.toNpnProtocolsList()));
+    }
+
+    public void testStringsToNpnBytesOversizedInput() {
+        try {
+            SSLCertificateSocketFactory.toNpnProtocolsList(new byte[256]);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
 }
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
index 38a3e44..0616bf0 100644
--- a/include/media/JetPlayer.h
+++ b/include/media/JetPlayer.h
@@ -18,7 +18,6 @@
 #define JETPLAYER_H_
 
 #include <utils/threads.h>
-#include <nativehelper/jni.h>
 
 #include <libsonivox/jet.h>
 #include <libsonivox/eas_types.h>
@@ -40,7 +39,7 @@
     static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
     static const int JET_PAUSE_UPDATE            = 4;
 
-    JetPlayer(jobject javaJetPlayer,
+    JetPlayer(void *javaJetPlayer,
             int maxTracks = 32,
             int trackBufferSize = 1200);
     ~JetPlayer();
@@ -75,7 +74,7 @@
 
     jetevent_callback   mEventCallback;
 
-    jobject             mJavaJetPlayerRef;
+    void*               mJavaJetPlayerRef;
     Mutex               mMutex; // mutex to sync the render and playback thread with the JET calls
     pid_t               mTid;
     Condition           mCondition;
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 98d6449..70dbfb3 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -2,14 +2,14 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	android_media_SoundPool.cpp \
-	SoundPool.cpp \
-	SoundPoolThread.cpp
+	android_media_SoundPool.cpp
+
+LOCAL_C_INCLUDES := \
+    frameworks/base/media/libmedia
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libutils \
-	libbinder \
 	libandroid_runtime \
 	libnativehelper \
 	libmedia \
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index da3af9d..c6dee06 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -23,7 +23,7 @@
 #include <nativehelper/jni.h>
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
-#include "SoundPool.h"
+#include <SoundPool.h>
 
 using namespace android;
 
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 51c8b68..bdb1a1c 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <new>
+#include <time.h>
 #include <audio_effects/effect_visualizer.h>
 
 
@@ -47,9 +48,9 @@
     VISUALIZER_STATE_ACTIVE,
 };
 
-// maximum number of reads from same buffer before resetting capture buffer. This means
+// maximum time since last capture buffer update before resetting capture buffer. This means
 // that the framework has stopped playing audio and we must start returning silence
-#define MAX_STALL_COUNT 10
+#define MAX_STALL_TIME_MS 1000
 
 struct VisualizerContext {
     const struct effect_interface_s *mItfe;
@@ -59,7 +60,7 @@
     uint8_t mState;
     uint8_t mCurrentBuf;
     uint8_t mLastBuf;
-    uint8_t mStallCount;
+    struct timespec mBufferUpdateTime;
     uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
 };
 
@@ -72,7 +73,7 @@
     pContext->mCaptureIdx = 0;
     pContext->mCurrentBuf = 0;
     pContext->mLastBuf = 1;
-    pContext->mStallCount = 0;
+    pContext->mBufferUpdateTime.tv_sec = 0;
     memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
     memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
 }
@@ -321,6 +322,11 @@
     if (pContext->mCaptureIdx == pContext->mCaptureSize) {
         pContext->mCurrentBuf ^= 1;
         pContext->mCaptureIdx = 0;
+
+        // update last buffer update time stamp
+        if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
+            pContext->mBufferUpdateTime.tv_sec = 0;
+        }
     }
 
     if (inBuffer->raw != outBuffer->raw) {
@@ -453,16 +459,25 @@
                    pContext->mCaptureSize);
             // if audio framework has stopped playing audio although the effect is still
             // active we must clear the capture buffer to return silence
-            if (pContext->mLastBuf == pContext->mCurrentBuf) {
-                if (pContext->mStallCount < MAX_STALL_COUNT) {
-                    if (++pContext->mStallCount == MAX_STALL_COUNT) {
+            if ((pContext->mLastBuf == pContext->mCurrentBuf) &&
+                    (pContext->mBufferUpdateTime.tv_sec != 0)) {
+                struct timespec ts;
+                if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+                    time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
+                    long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
+                    if (nsec < 0) {
+                        --secs;
+                        nsec += 1000000000;
+                    }
+                    uint32_t deltaMs = secs * 1000 + nsec / 1000000;
+                    if (deltaMs > MAX_STALL_TIME_MS) {
+                        ALOGV("capture going to idle");
+                        pContext->mBufferUpdateTime.tv_sec = 0;
                         memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
                                 0x80,
                                 pContext->mCaptureSize);
                     }
                 }
-            } else {
-                pContext->mStallCount = 0;
             }
             pContext->mLastBuf = pContext->mCurrentBuf;
         } else {
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index a758850..c8e1dc7 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -44,7 +44,9 @@
     IEffectClient.cpp \
     AudioEffect.cpp \
     Visualizer.cpp \
-    MemoryLeakTrackUtil.cpp
+    MemoryLeakTrackUtil.cpp \
+    SoundPool.cpp \
+    SoundPoolThread.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat \
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 9b8d7c3..7e6d54b 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -18,7 +18,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <binder/Parcel.h>
-#include <SkBitmap.h>
 #include <media/IMediaMetadataRetriever.h>
 #include <utils/String8.h>
 
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 7fa6bb7..52aee49 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -30,7 +30,7 @@
 static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
 
 //-------------------------------------------------------------------------------------------------
-JetPlayer::JetPlayer(jobject javaJetPlayer, int maxTracks, int trackBufferSize) :
+JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
         mEventCallback(NULL),
         mJavaJetPlayerRef(javaJetPlayer),
         mTid(-1),
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/libmedia/SoundPool.cpp
similarity index 99%
rename from media/jni/soundpool/SoundPool.cpp
rename to media/libmedia/SoundPool.cpp
index 5aed8a1..306c57d 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/libmedia/SoundPool.cpp
@@ -685,7 +685,7 @@
 void SoundChannel::callback(int event, void* user, void *info)
 {
     SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1));
-    
+
     channel->process(event, info, (unsigned long)user & 1);
 }
 
diff --git a/media/jni/soundpool/SoundPool.h b/media/libmedia/SoundPool.h
similarity index 100%
rename from media/jni/soundpool/SoundPool.h
rename to media/libmedia/SoundPool.h
diff --git a/media/jni/soundpool/SoundPoolThread.cpp b/media/libmedia/SoundPoolThread.cpp
similarity index 100%
rename from media/jni/soundpool/SoundPoolThread.cpp
rename to media/libmedia/SoundPoolThread.cpp
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/libmedia/SoundPoolThread.h
similarity index 100%
rename from media/jni/soundpool/SoundPoolThread.h
rename to media/libmedia/SoundPoolThread.h
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 6d345bb..9df15eb 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -31,10 +31,6 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 
-#ifdef ANDROID_SIMULATOR
-#include <jni.h>
-#endif
-
 namespace android {
 
 TimedEventQueue::TimedEventQueue()
@@ -193,27 +189,10 @@
 // static
 void *TimedEventQueue::ThreadWrapper(void *me) {
 
-#ifdef ANDROID_SIMULATOR
-    // The simulator runs everything as one process, so any
-    // Binder calls happen on this thread instead of a thread
-    // in another process. We therefore need to make sure that
-    // this thread can do calls into interpreted code.
-    // On the device this is not an issue because the remote
-    // thread will already be set up correctly for this.
-    JavaVM *vm;
-    int numvms;
-    JNI_GetCreatedJavaVMs(&vm, 1, &numvms);
-    JNIEnv *env;
-    vm->AttachCurrentThread(&env, NULL);
-#endif
-
     androidSetThreadPriority(0, ANDROID_PRIORITY_FOREGROUND);
 
     static_cast<TimedEventQueue *>(me)->threadEntry();
 
-#ifdef ANDROID_SIMULATOR
-    vm->DetachCurrentThread();
-#endif
     return NULL;
 }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 60749b3..37a594e 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3038,7 +3038,7 @@
     }
 
     final void logAppTooSlow(ProcessRecord app, long startTime, String msg) {
-        if (IS_USER_BUILD) {
+        if (true || IS_USER_BUILD) {
             return;
         }
         String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 3ecbf77..e430529 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -89,6 +89,7 @@
 import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.FloatMath;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -5261,8 +5262,8 @@
         synchronized(mWindowMap) {
             long ident = Binder.clearCallingIdentity();
 
-            dw = mAppDisplayWidth;
-            dh = mAppDisplayHeight;
+            dw = mCurDisplayWidth;
+            dh = mCurDisplayHeight;
 
             int aboveAppLayer = mPolicy.windowTypeToLayerLw(
                     WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER
@@ -5382,7 +5383,7 @@
         Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
         Matrix matrix = new Matrix();
         ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
-        matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale));
+        matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
         Canvas canvas = new Canvas(bm);
         canvas.drawBitmap(rawss, matrix, null);
         canvas.setBitmap(null);