Merge "Hold wake lock while shutting down."
diff --git a/api/current.xml b/api/current.xml
index 4146859..2e434af 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -114301,6 +114301,23 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
+<method name="dumpService"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<parameter name="args" type="java.lang.String[]">
+</parameter>
+</method>
 <method name="enableEmulatorTraceOutput"
  return="void"
  abstract="false"
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 2974981..dfd4024 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -261,7 +261,7 @@
     public static final int MAX_SQL_CACHE_SIZE = 250;
     private int mMaxSqlCacheSize = MAX_SQL_CACHE_SIZE; // max cache size per Database instance
     private int mCacheFullWarnings;
-    private static final int MAX_WARNINGS_ON_CACHESIZE_CONDITION = 5;
+    private static final int MAX_WARNINGS_ON_CACHESIZE_CONDITION = 1;
 
     /** maintain stats about number of cache hits and misses */
     private int mNumCacheHits;
@@ -1909,43 +1909,28 @@
             }
             // add this <sql, compiledStatement> to the cache
             if (mCompiledQueries.size() == mMaxSqlCacheSize) {
-                /* reached max cachesize. before adding new entry, remove an entry from the
-                 * cache. we don't want to wipe out the entire cache because of this:
-                 * GCing {@link SQLiteCompiledSql} requires call to sqlite3_finalize
-                 * JNI method. If entire cache is wiped out, it could cause a big GC activity
-                 * just because a (rogue) process is using the cache incorrectly.
+                /*
+                 * cache size of {@link #mMaxSqlCacheSize} is not enough for this app.
+                 * log a warning MAX_WARNINGS_ON_CACHESIZE_CONDITION times
+                 * chances are it is NOT using ? for bindargs - so caching is useless.
+                 * TODO: either let the callers set max cchesize for their app, or intelligently
+                 * figure out what should be cached for a given app.
                  */
-                Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " +
-                        getPath() + "; i.e., NO space for this sql statement in cache: " +
-                        sql + ". Please change your sql statements to use '?' for " +
-                        "bindargs, instead of using actual values");
-                
-                /* increment the number of times this warnings has been printed.
-                 * if this warning is printed too many times, clear the whole cache - the app
-                 * is doing something weird or incorrect and printing more warnings will only
-                 * flood the logfile.
-                 */
-                if (++mCacheFullWarnings > MAX_WARNINGS_ON_CACHESIZE_CONDITION) {
-                    mCacheFullWarnings = 0;
-                    // clear the cache
-                    mCompiledQueries.clear();
-                    Log.w(TAG, "Compiled-sql statement cache for database: " +
-                            getPath() + " hit MAX size-limit too many times. " +
-                            "Removing all compiled-sql statements from the cache.");
-                } else {
-                    // clear just a single entry from cache
-                    Set<String> keySet = mCompiledQueries.keySet();
-                    for (String s : keySet) {
-                        mCompiledQueries.remove(s);
-                        break;
-                    }
+                if (++mCacheFullWarnings == MAX_WARNINGS_ON_CACHESIZE_CONDITION) {
+                    Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " +
+                            getPath() + "; i.e., NO space for this sql statement in cache: " +
+                            sql + ". Please change your sql statements to use '?' for " +
+                            "bindargs, instead of using actual values");
+                }
+                // don't add this entry to cache
+            } else {
+                // cache is NOT full. add this to cache.
+                mCompiledQueries.put(sql, compiledStatement);
+                if (SQLiteDebug.DEBUG_SQL_CACHE) {
+                    Log.v(TAG, "|adding_sql_to_cache|" + getPath() + "|" +
+                            mCompiledQueries.size() + "|" + sql);
                 }
             }
-            mCompiledQueries.put(sql, compiledStatement);
-        }
-        if (SQLiteDebug.DEBUG_SQL_CACHE) {
-            Log.v(TAG, "|adding_sql_to_cache|" + getPath() + "|" + mCompiledQueries.size() + "|" +
-                    sql);
         }
         return;
     }
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 389e15e..6636473 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -58,11 +58,10 @@
         db.addSQLiteClosable(this);
         this.nHandle = db.mNativeHandle;
 
-        // shouldn't reuse compiled-plans of PRAGMA sql statements
-        // because sqlite returns OLD values if compiled-pragma-statements are reused
-        //TODO: remove this code when sqlite fixes it (and add tests too)
+        // only cache CRUD statements
         String prefixSql = mSql.substring(0, 6);
-        if (prefixSql.toLowerCase().startsWith("pragma")) {
+        if (!prefixSql.equalsIgnoreCase("INSERT") && !prefixSql.equalsIgnoreCase("UPDATE") &&
+                !prefixSql.equalsIgnoreCase("DELETE") && !prefixSql.equalsIgnoreCase("SELECT")) {
             mCompiledSql = new SQLiteCompiledSql(db, sql);
             nStatement = mCompiledSql.nStatement;
             // since it is not in the cache, no need to acquire() it.
diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java
index a572f60..e5bc6e3 100644
--- a/core/java/android/net/WebAddress.java
+++ b/core/java/android/net/WebAddress.java
@@ -57,7 +57,7 @@
             /* scheme    */ "(?:(http|HTTP|https|HTTPS|file|FILE)\\:\\/\\/)?" +
             /* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
             /* host      */ "([-" + GOOD_IRI_CHAR + "%_]+(?:\\.[-" + GOOD_IRI_CHAR + "%_]+)*|\\[[0-9a-fA-F:\\.]+\\])?" +
-            /* port      */ "(?:\\:([0-9]+))?" +
+            /* port      */ "(?:\\:([0-9]*))?" +
             /* path      */ "(\\/?[^#]*)?" +
             /* anchor    */ ".*");
 
@@ -85,7 +85,8 @@
             t = m.group(MATCH_GROUP_HOST);
             if (t != null) mHost = t;
             t = m.group(MATCH_GROUP_PORT);
-            if (t != null) {
+            if (t != null && t.length() > 0) {
+                // The ':' character is not returned by the regex.
                 try {
                     mPort = Integer.parseInt(t);
                 } catch (NumberFormatException ex) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index a4c595d..2e14667 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -57,6 +57,8 @@
  */
 public final class Debug
 {
+    private static final String TAG = "Debug";
+
     /**
      * Flags for startMethodTracing().  These can be ORed together.
      *
@@ -1111,7 +1113,7 @@
                 }
             }
         } else {
-            Log.w("android.os.Debug",
+            Log.wtf(TAG,
                   "setFieldsOn(" + (cl == null ? "null" : cl.getName()) +
                   ") called in non-DEBUG build");
         }
@@ -1127,4 +1129,31 @@
     @Retention(RetentionPolicy.RUNTIME)
     public @interface DebugProperty {
     }
+
+    /**
+     * Get a debugging dump of a system service by name.
+     *
+     * <p>Most services require the caller to hold android.permission.DUMP.
+     *
+     * @param name of the service to dump
+     * @param fd to write dump output to (usually an output log file)
+     * @param args to pass to the service's dump method, may be null
+     * @return true if the service was dumped successfully, false if
+     *     the service could not be found or had an error while dumping
+     */
+    public static boolean dumpService(String name, FileDescriptor fd, String[] args) {
+        IBinder service = ServiceManager.getService(name);
+        if (service == null) {
+            Log.e(TAG, "Can't find service to dump: " + name);
+            return false;
+        }
+
+        try {
+            service.dump(fd, args);
+            return true;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Can't dump service: " + name, e);
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/speech/RecognizerResultsIntent.java b/core/java/android/speech/RecognizerResultsIntent.java
index 4997d50..b45e4b1 100644
--- a/core/java/android/speech/RecognizerResultsIntent.java
+++ b/core/java/android/speech/RecognizerResultsIntent.java
@@ -127,10 +127,11 @@
      * All the values and the keys are {@link String}s. Each key/value pair represents an extra HTTP
      * header. The keys can't be the standard HTTP headers as they are set by the WebView.
      *
-     * A list of size 1 may be provided to apply the same HTTP headers to all html results. A list 
-     * of the same size as {@link #EXTRA_VOICE_SEARCH_RESULT_STRINGS} may be provided to apply 
-     * different HTTP headers to each different html result in the 
-     * {@link #EXTRA_VOICE_SEARCH_RESULT_HTML} list.
+     * A list of size 1 may be provided to apply the same HTTP headers to all web results. A
+     * list of the same size as {@link #EXTRA_VOICE_SEARCH_RESULT_STRINGS} may be provided to
+     * apply different HTTP headers to each different web result in the list. These headers will
+     * only be used in the case that the url for a particular web result (from
+     * {@link #EXTRA_VOICE_SEARCH_RESULT_URLS}) is loaded.
      *
      * @hide not to be exposed immediately as the implementation details may change
      */
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6eca68c..a889476 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3319,7 +3319,7 @@
             if (!animateScroll) {
                 extras = DRAW_EXTRAS_FIND;
             }
-        } else if (mShiftIsPressed) {
+        } else if (mShiftIsPressed && !nativeFocusIsPlugin()) {
             if (!animateZoom && !mPreviewZoomOnly) {
                 extras = DRAW_EXTRAS_SELECTION;
                 nativeSetSelectionRegion(mTouchSelection || mExtendSelection);
@@ -3674,6 +3674,7 @@
         }
 
         if (mShiftIsPressed == false && nativeCursorWantsKeyEvents() == false
+                && !nativeFocusIsPlugin()
                 && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
                 || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) {
             setUpSelectXY();
@@ -3681,8 +3682,11 @@
 
         if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
                 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
-            // always handle the navigation keys in the UI thread
             switchOutDrawHistory();
+            if (nativeFocusIsPlugin()) {
+                letPluginHandleNavKey(keyCode, event.getEventTime(), true);
+                return true;
+            }
             if (mShiftIsPressed) {
                 int xRate = keyCode == KeyEvent.KEYCODE_DPAD_LEFT
                     ? -1 : keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ? 1 : 0;
@@ -3692,7 +3696,7 @@
                 moveSelection(xRate * multiplier, yRate * multiplier);
                 return true;
             }
-            if (navHandledKey(keyCode, 1, false, event.getEventTime(), false)) {
+            if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
                 playSoundEffect(keyCodeToSoundsEffect(keyCode));
                 return true;
             }
@@ -3703,7 +3707,7 @@
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             switchOutDrawHistory();
             if (event.getRepeatCount() == 0) {
-                if (mShiftIsPressed) {
+                if (mShiftIsPressed && !nativeFocusIsPlugin()) {
                     return true; // discard press if copy in progress
                 }
                 mGotCenterDown = true;
@@ -3819,6 +3823,10 @@
 
         if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
                 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
+            if (nativeFocusIsPlugin()) {
+                letPluginHandleNavKey(keyCode, event.getEventTime(), false);
+                return true;
+            }
             // always handle the navigation keys in the UI thread
             // Bubble up the key event as WebView doesn't handle it
             return false;
@@ -3829,7 +3837,7 @@
             mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
             mGotCenterDown = false;
 
-            if (mShiftIsPressed) {
+            if (mShiftIsPressed && !nativeFocusIsPlugin()) {
                 if (mExtendSelection) {
                     commitCopy();
                 } else {
@@ -5014,7 +5022,7 @@
             return true;
         }
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            if (mShiftIsPressed) {
+            if (mShiftIsPressed && !nativeFocusIsPlugin()) {
                 return true; // discard press if copy in progress
             }
             mTrackballDown = true;
@@ -5039,7 +5047,7 @@
             mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
             mTrackballDown = false;
             mTrackballUpTime = time;
-            if (mShiftIsPressed) {
+            if (mShiftIsPressed && !nativeFocusIsPlugin()) {
                 if (mExtendSelection) {
                     commitCopy();
                 } else {
@@ -5177,7 +5185,7 @@
         float yRate = mTrackballRemainsY * 1000 / elapsed;
         int viewWidth = getViewWidth();
         int viewHeight = getViewHeight();
-        if (mShiftIsPressed) {
+        if (mShiftIsPressed && !nativeFocusIsPlugin()) {
             moveSelection(scaleTrackballX(xRate, viewWidth),
                     scaleTrackballY(yRate, viewHeight));
             mTrackballRemainsX = mTrackballRemainsY = 0;
@@ -5215,7 +5223,12 @@
                         + " mTrackballRemainsX=" + mTrackballRemainsX
                         + " mTrackballRemainsY=" + mTrackballRemainsY);
             }
-            if (navHandledKey(selectKeyCode, count, false, time, false)) {
+            if (nativeFocusIsPlugin()) {
+                for (int i = 0; i < count; i++) {
+                    letPluginHandleNavKey(selectKeyCode, time, true);
+                    letPluginHandleNavKey(selectKeyCode, time, false);
+                }
+            } else if (navHandledKey(selectKeyCode, count, false, time)) {
                 playSoundEffect(keyCodeToSoundsEffect(selectKeyCode));
             }
             mTrackballRemainsX = mTrackballRemainsY = 0;
@@ -5692,7 +5705,7 @@
                         return result;
                 }
                 if (mNativeClass != 0 && !nativeHasCursorNode()) {
-                    navHandledKey(fakeKeyDirection, 1, true, 0, true);
+                    navHandledKey(fakeKeyDirection, 1, true, 0);
                 }
             }
         }
@@ -6118,7 +6131,7 @@
                     }
                     break;
                 case MOVE_OUT_OF_PLUGIN:
-                    navHandledKey(msg.arg1, 1, false, 0, true);
+                    navHandledKey(msg.arg1, 1, false, 0);
                     break;
                 case UPDATE_TEXT_ENTRY_MSG_ID:
                     // this is sent after finishing resize in WebViewCore. Make
@@ -6785,21 +6798,34 @@
         invalidate();
     }
 
-    // return true if the key was handled
-    private boolean navHandledKey(int keyCode, int count, boolean noScroll,
-            long time, boolean ignorePlugin) {
-        if (mNativeClass == 0) {
-            return false;
+    /**
+     * Pass the key to the plugin.  This assumes that nativeFocusIsPlugin()
+     * returned true.
+     */
+    private void letPluginHandleNavKey(int keyCode, long time, boolean down) {
+        int keyEventAction;
+        int eventHubAction;
+        if (down) {
+            keyEventAction = KeyEvent.ACTION_DOWN;
+            eventHubAction = EventHub.KEY_DOWN;
+            playSoundEffect(keyCodeToSoundsEffect(keyCode));
+        } else {
+            keyEventAction = KeyEvent.ACTION_UP;
+            eventHubAction = EventHub.KEY_UP;
         }
-        if (ignorePlugin == false && nativeFocusIsPlugin()) {
-            KeyEvent event = new KeyEvent(time, time, KeyEvent.ACTION_DOWN
-                , keyCode, count, (mShiftIsPressed ? KeyEvent.META_SHIFT_ON : 0)
+        KeyEvent event = new KeyEvent(time, time, keyEventAction, keyCode,
+                1, (mShiftIsPressed ? KeyEvent.META_SHIFT_ON : 0)
                 | (false ? KeyEvent.META_ALT_ON : 0) // FIXME
                 | (false ? KeyEvent.META_SYM_ON : 0) // FIXME
                 , 0, 0, 0);
-            mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
-            mWebViewCore.sendMessage(EventHub.KEY_UP, event);
-            return true;
+        mWebViewCore.sendMessage(eventHubAction, event);
+    }
+
+    // return true if the key was handled
+    private boolean navHandledKey(int keyCode, int count, boolean noScroll,
+            long time) {
+        if (mNativeClass == 0) {
+            return false;
         }
         mLastCursorTime = time;
         mLastCursorBounds = nativeGetCursorRingBounds();
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index acb7e02..d80a5e3 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -318,11 +318,7 @@
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         // Let the focused view and/or our descendants get the key first
-        boolean handled = super.dispatchKeyEvent(event);
-        if (handled) {
-            return true;
-        }
-        return executeKeyEvent(event);
+        return super.dispatchKeyEvent(event) || executeKeyEvent(event);
     }
 
     /**
@@ -509,8 +505,11 @@
                     final int deltaX = (int) (mLastMotionX - x);
                     mLastMotionX = x;
 
+                    final int oldX = mScrollX;
+                    final int oldY = mScrollY;                    
                     overscrollBy(deltaX, 0, mScrollX, 0, getScrollRange(), 0,
                             getOverscrollMax(), 0);
+                    onScrollChanged(mScrollX, mScrollY, oldX, oldY);
                 }
                 break;
             case MotionEvent.ACTION_UP:
@@ -524,7 +523,7 @@
                             fling(-initialVelocity);
                         } else {
                             final int right = getScrollRange();
-                            if (mScroller.springback(mScrollX, mScrollY, 0, 0, right, 0)) {
+                            if (mScroller.springback(mScrollX, mScrollY, 0, right, 0, 0)) {
                                 invalidate();
                             }
                         }
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 489c44d..d7dfa86 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -22,7 +22,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.FocusFinder;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -52,8 +51,6 @@
  * <p>ScrollView only supports vertical scrolling.
  */
 public class ScrollView extends FrameLayout {
-    private static final String TAG = "ScrollView";
-
     static final int ANIMATED_SCROLL_GAP = 250;
 
     static final float MAX_SCROLL_FACTOR = 0.5f;
@@ -318,11 +315,7 @@
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         // Let the focused view and/or our descendants get the key first
-        boolean handled = super.dispatchKeyEvent(event);
-        if (handled) {
-            return true;
-        }
-        return executeKeyEvent(event);
+        return super.dispatchKeyEvent(event) || executeKeyEvent(event);
     }
 
     /**
@@ -510,8 +503,11 @@
                     final int deltaY = (int) (mLastMotionY - y);
                     mLastMotionY = y;
 
+                    final int oldX = mScrollX;
+                    final int oldY = mScrollY;
                     overscrollBy(0, deltaY, 0, mScrollY, 0, getScrollRange(),
                             0, getOverscrollMax());
+                    onScrollChanged(mScrollX, mScrollY, oldX, oldY);
                 }
                 break;
             case MotionEvent.ACTION_UP: 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 51e1c57..7b21be5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1376,15 +1376,18 @@
                 dr.mDrawableLeft.setCallback(null);
             }
             dr.mDrawableLeft = left;
-            if (dr.mDrawableTop != left && dr.mDrawableTop != null) {
+
+            if (dr.mDrawableTop != top && dr.mDrawableTop != null) {
                 dr.mDrawableTop.setCallback(null);
             }
             dr.mDrawableTop = top;
-            if (dr.mDrawableRight != left && dr.mDrawableRight != null) {
+
+            if (dr.mDrawableRight != right && dr.mDrawableRight != null) {
                 dr.mDrawableRight.setCallback(null);
             }
             dr.mDrawableRight = right;
-            if (dr.mDrawableBottom != left && dr.mDrawableBottom != null) {
+
+            if (dr.mDrawableBottom != bottom && dr.mDrawableBottom != null) {
                 dr.mDrawableBottom.setCallback(null);
             }
             dr.mDrawableBottom = bottom;
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index bd55e83..44e091d 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -367,7 +367,7 @@
     if (err != SQLITE_OK) {
         LOGE("register_localized_collators() failed setting locale\n");
         throw_sqlite3_exception(env, handle);
-        goto done;
+        goto rollback;
     }
 
     err = sqlite3_exec(handle, "DELETE FROM " ANDROID_TABLE, NULL, NULL, NULL);
@@ -415,7 +415,9 @@
     }
 
 rollback:
-    sqlite3_exec(handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
+    if (err != SQLITE_OK) {
+        sqlite3_exec(handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
+    }
 
 done:
     if (locale8 != NULL) env->ReleaseStringUTFChars(localeString, locale8);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 5090c39..b8a50bf 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1064,6 +1064,8 @@
 }
 
 void AwesomePlayer::onPrepareAsyncEvent() {
+    sp<Prefetcher> prefetcher;
+
     {
         Mutex::Autolock autoLock(mLock);
 
@@ -1075,12 +1077,25 @@
                 return;
             }
         }
-    }
 
-    sp<Prefetcher> prefetcher;
+        if (mVideoTrack != NULL && mVideoSource == NULL) {
+            status_t err = initVideoDecoder();
 
-    {
-        Mutex::Autolock autoLock(mLock);
+            if (err != OK) {
+                abortPrepare(err);
+                return;
+            }
+        }
+
+        if (mAudioTrack != NULL && mAudioSource == NULL) {
+            status_t err = initAudioDecoder();
+
+            if (err != OK) {
+                abortPrepare(err);
+                return;
+            }
+        }
+
         prefetcher = mPrefetcher;
     }
 
@@ -1091,24 +1106,6 @@
 
     Mutex::Autolock autoLock(mLock);
 
-    if (mVideoTrack != NULL && mVideoSource == NULL) {
-        status_t err = initVideoDecoder();
-
-        if (err != OK) {
-            abortPrepare(err);
-            return;
-        }
-    }
-
-    if (mAudioTrack != NULL && mAudioSource == NULL) {
-        status_t err = initAudioDecoder();
-
-        if (err != OK) {
-            abortPrepare(err);
-            return;
-        }
-    }
-
     if (mIsAsyncPrepare) {
         if (mVideoWidth < 0 || mVideoHeight < 0) {
             notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index 9c73f4a..493570a 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -59,6 +59,7 @@
     int64_t mSeekTimeUs;
     int64_t mCacheDurationUs;
     bool mPrefetcherStopped;
+    bool mCurrentlyPrefetching;
 
     List<MediaBuffer *> mCachedBuffers;
 
@@ -205,10 +206,6 @@
             continue;
         }
 
-        if (cacheDurationUs >= kMaxCacheDurationUs) {
-            continue;
-        }
-
         if (minIndex < 0 || cacheDurationUs < minCacheDurationUs) {
             minCacheDurationUs = cacheDurationUs;
             minIndex = i;
@@ -223,13 +220,13 @@
 }
 
 status_t Prefetcher::prepare() {
-    // Buffer about 2 secs worth of data on prepare.
+    // Fill the cache.
 
     int64_t duration;
     bool noMoreData;
     do {
         duration = getCachedDurationUs(&noMoreData);
-    } while (!noMoreData && duration < 2000000);
+    } while (!noMoreData && duration < kMaxCacheDurationUs);
 
     return OK;
 }
@@ -245,7 +242,8 @@
       mReachedEOS(false),
       mSeekTimeUs(0),
       mCacheDurationUs(0),
-      mPrefetcherStopped(false) {
+      mPrefetcherStopped(false),
+      mCurrentlyPrefetching(false) {
 }
 
 PrefetchedSource::~PrefetchedSource() {
@@ -275,6 +273,10 @@
 
     Mutex::Autolock autoLock(mLock);
 
+    while (mCurrentlyPrefetching) {
+        mCondition.wait(mLock);
+    }
+
     clearCache_l();
 
     status_t err = mSource->stop();
@@ -344,15 +346,24 @@
         return;
     }
 
+    mCurrentlyPrefetching = true;
+
     if (mSeekTimeUs >= 0) {
         options.setSeekTo(mSeekTimeUs);
         mSeekTimeUs = -1;
     }
 
+    // Ensure our object does not go away while we're not holding
+    // the lock.
+    sp<PrefetchedSource> me = this;
+
+    mLock.unlock();
     MediaBuffer *buffer;
     status_t err = mSource->read(&buffer, &options);
+    mLock.lock();
 
     if (err != OK) {
+        mCurrentlyPrefetching = false;
         mReachedEOS = true;
         mFinalStatus = err;
         mCondition.signal();
@@ -380,6 +391,8 @@
 
     mCachedBuffers.push_back(copy);
     updateCacheDuration_l();
+
+    mCurrentlyPrefetching = false;
     mCondition.signal();
 }
 
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 4c11c36..a6dbf69 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -45,7 +45,9 @@
         LOGI("Creating physical memory heap failed, reverting to regular heap.");
         mMemoryHeap = new MemoryHeapBase(2 * mFrameSize);
     } else {
-        mMemoryHeap = new MemoryHeapPmem(mMemoryHeap);
+        sp<MemoryHeapPmem> pmemHeap = new MemoryHeapPmem(mMemoryHeap);
+        pmemHeap->slap();
+        mMemoryHeap = pmemHeap;
     }
 
     CHECK(mISurface.get() != NULL);
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 1e9c312..bd131e0 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -60,7 +60,7 @@
 
     <!-- user interface sound effects -->
     <integer name="def_power_sounds_enabled">1</integer>
-    <string name="def_low_battery_sound" translatable="false">/system/media/ui/LowBattery.ogg</string>
+    <string name="def_low_battery_sound" translatable="false">/system/media/audio/ui/LowBattery.ogg</string>
     <integer name="def_dock_sounds_enabled">0</integer>
     <string name="def_desk_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string>
     <string name="def_desk_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string>