Merge "do not merge" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index d7fc03d..1d6feb5 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -76944,11 +76944,11 @@
  visibility="public"
 >
 </field>
-<field name="FOCUS_MODE_CONTINUOUS"
+<field name="FOCUS_MODE_CONTINUOUS_VIDEO"
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;continuous&quot;"
+ value="&quot;continuous-video&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -84729,6 +84729,39 @@
 <parameter name="value" type="short">
 </parameter>
 </method>
+<field name="ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ALREADY_EXISTS"
  type="int"
  transient="false"
@@ -84740,6 +84773,50 @@
  visibility="public"
 >
 </field>
+<field name="CONTENT_TYPE_GAME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_TYPE_MOVIE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_TYPE_MUSIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_TYPE_VOICE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EFFECT_AUXILIARY"
  type="java.lang.String"
  transient="false"
@@ -84888,6 +84965,39 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_AUDIO_SESSION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.extra.AUDIO_SESSION&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_CONTENT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.extra.CONTENT_TYPE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_PACKAGE_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.extra.PACKAGE_NAME&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="NATIVE_EVENT_CONTROL_STATUS"
  type="int"
  transient="false"
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index c424281..b718299 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -36,24 +36,30 @@
 static const int32_t kIFramesIntervalSec = 1;
 static const int32_t kVideoBitRate = 512 * 1024;
 static const int32_t kAudioBitRate = 12200;
-static const int32_t kColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
 static const int64_t kDurationUs = 10000000LL;  // 10 seconds
 
 #if 1
 class DummySource : public MediaSource {
 
 public:
-    DummySource(int width, int height)
+    DummySource(int width, int height, int colorFormat)
         : mWidth(width),
           mHeight(height),
+          mColorFormat(colorFormat),
           mSize((width * height * 3) / 2) {
         mGroup.add_buffer(new MediaBuffer(mSize));
+
+        // Check the color format to make sure
+        // that the buffer size mSize it set correctly above.
+        CHECK(colorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
+              colorFormat == OMX_COLOR_FormatYUV420Planar);
     }
 
     virtual sp<MetaData> getFormat() {
         sp<MetaData> meta = new MetaData;
         meta->setInt32(kKeyWidth, mWidth);
         meta->setInt32(kKeyHeight, mHeight);
+        meta->setInt32(kKeyColorFormat, mColorFormat);
         meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
 
         return meta;
@@ -100,6 +106,7 @@
 private:
     MediaBufferGroup mGroup;
     int mWidth, mHeight;
+    int mColorFormat;
     size_t mSize;
     int64_t mNumFramesOutput;;
 
@@ -139,20 +146,47 @@
     return source;
 }
 
+enum {
+    kYUV420SP = 0,
+    kYUV420P  = 1,
+};
+
+// returns -1 if mapping of the given color is unsuccessful
+// returns an omx color enum value otherwise
+static int translateColorToOmxEnumValue(int color) {
+    switch (color) {
+        case kYUV420SP:
+            return OMX_COLOR_FormatYUV420SemiPlanar;
+        case kYUV420P:
+            return OMX_COLOR_FormatYUV420Planar;
+        default:
+            fprintf(stderr, "Unsupported color: %d\n", color);
+            return -1;
+    }
+}
+
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
     DataSource::RegisterDefaultSniffers();
 
 #if 1
-    if (argc != 2) {
-        fprintf(stderr, "usage: %s filename\n", argv[0]);
+    if (argc != 3) {
+        fprintf(stderr, "usage: %s <filename> <input_color_format>\n", argv[0]);
+        fprintf(stderr, "       <input_color_format>:  0 (YUV420SP) or 1 (YUV420P)\n");
         return 1;
     }
 
+    int colorFormat = translateColorToOmxEnumValue(atoi(argv[2]));
+    if (colorFormat == -1) {
+        fprintf(stderr, "input color format must be 0 (YUV420SP) or 1 (YUV420P)\n");
+        return 1;
+    }
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
 
+    status_t err = OK;
+
 #if 0
     sp<MediaSource> source = createSource(argv[1]);
 
@@ -173,7 +207,7 @@
 #else
     int width = 720;
     int height = 480;
-    sp<MediaSource> decoder = new DummySource(width, height);
+    sp<MediaSource> decoder = new DummySource(width, height, colorFormat);
 #endif
 
     sp<MetaData> enc_meta = new MetaData;
@@ -187,7 +221,7 @@
     enc_meta->setInt32(kKeyStride, width);
     enc_meta->setInt32(kKeySliceHeight, height);
     enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec);
-    enc_meta->setInt32(kKeyColorFormat, kColorFormat);
+    enc_meta->setInt32(kKeyColorFormat, colorFormat);
 
     sp<MediaSource> encoder =
         OMXCodec::Create(
@@ -197,14 +231,14 @@
     sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
     writer->addSource(encoder);
     writer->setMaxFileDuration(kDurationUs);
-    writer->start();
+    CHECK_EQ(OK, writer->start());
     while (!writer->reachedEOS()) {
         fprintf(stderr, ".");
         usleep(100000);
     }
-    writer->stop();
+    err = writer->stop();
 #else
-    encoder->start();
+    CHECK_EQ(OK, encoder->start());
 
     MediaBuffer *buffer;
     while (encoder->read(&buffer) == OK) {
@@ -222,7 +256,7 @@
         buffer = NULL;
     }
 
-    encoder->stop();
+    err = encoder->stop();
 #endif
 
     printf("$\n");
@@ -247,12 +281,16 @@
         buffer = NULL;
     }
 
-    source->stop();
+    err = source->stop();
 
     delete source;
     source = NULL;
 #endif
 
+    if (err != OK && err != ERROR_END_OF_STREAM) {
+        fprintf(stderr, "record failed: %d\n", err);
+        return 1;
+    }
     return 0;
 }
 #else
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d8b5253..3c7bebf 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -363,7 +363,8 @@
         private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
         private static final String ONE_COUNT_COLUMN = "%17s %8d";
         private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
-        private static final String DB_INFO_FORMAT = "  %8d %8d %10d  %s";
+        private static final String TWO_COUNT_COLUMNS_DB = "%20s %8d %20s %8d";
+        private static final String DB_INFO_FORMAT = "  %8d %8d %14d  %s";
 
         // Formatting for checkin service - update version if row format changes
         private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
@@ -806,15 +807,15 @@
             // SQLite mem info
             pw.println(" ");
             pw.println(" SQL");
-            printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "memoryUsed:",
+            printRow(pw, TWO_COUNT_COLUMNS_DB, "heap:", sqliteAllocated, "MEMORY_USED:",
                     stats.memoryUsed / 1024);
-            printRow(pw, TWO_COUNT_COLUMNS, "pageCacheOverflo:", stats.pageCacheOverflo / 1024,
-                    "largestMemAlloc:", stats.largestMemAlloc / 1024);
+            printRow(pw, TWO_COUNT_COLUMNS_DB, "PAGECACHE_OVERFLOW:",
+                    stats.pageCacheOverflo / 1024, "MALLOC_SIZE:", stats.largestMemAlloc / 1024);
             pw.println(" ");
             int N = stats.dbStats.size();
             if (N > 0) {
                 pw.println(" DATABASES");
-                printRow(pw, "  %8s %8s %10s  %s", "Pagesize", "Dbsize", "Lookaside", "Dbname");
+                printRow(pw, "  %8s %8s %14s  %s", "pgsz", "dbsz", "Lookaside(b)", "Dbname");
                 for (int i = 0; i < N; i++) {
                     DbStats dbStats = stats.dbStats.get(i);
                     printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize,
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index 89c3f96..b2a166b 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -134,7 +134,7 @@
 
         public DbStats(String dbName, long pageCount, long pageSize, int lookaside) {
             this.dbName = dbName;
-            this.pageSize = pageSize;
+            this.pageSize = pageSize / 1024;
             dbSize = (pageCount * pageSize) / 1024;
             this.lookaside = lookaside;
         }
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 26600f3..0d8228c 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1182,14 +1182,17 @@
         public static final String FOCUS_MODE_EDOF = "edof";
 
         /**
-         * Continuous auto focus mode. The camera continuously tries to focus.
-         * This is ideal for shooting video or shooting photo of moving object.
-         * Auto focus starts when the parameter is set. Applications should not
-         * call {@link #autoFocus(AutoFocusCallback)} in this mode. To stop
-         * continuous focus, applications should change the focus mode to other
-         * modes.
+         * Continuous auto focus mode intended for video recording. The camera
+         * continuously tries to focus. This is ideal for shooting video.
+         * Applications still can call {@link
+         * #takePicture(Camera.ShutterCallback, Camera.PictureCallback,
+         * Camera.PictureCallback)} in this mode but the subject may not be in
+         * focus. Auto focus starts when the parameter is set. Applications
+         * should not call {@link #autoFocus(AutoFocusCallback)} in this mode.
+         * To stop continuous focus, applications should change the focus mode
+         * to other modes.
          */
-        public static final String FOCUS_MODE_CONTINUOUS = "continuous";
+        public static final String FOCUS_MODE_CONTINUOUS_VIDEO = "continuous-video";
 
         // Indices for focus distance array.
         /**
@@ -2023,7 +2026,7 @@
          * @see #FOCUS_MODE_MACRO
          * @see #FOCUS_MODE_FIXED
          * @see #FOCUS_MODE_EDOF
-         * @see #FOCUS_MODE_CONTINUOUS
+         * @see #FOCUS_MODE_CONTINUOUS_VIDEO
          */
         public String getFocusMode() {
             return get(KEY_FOCUS_MODE);
@@ -2225,8 +2228,8 @@
          * #autoFocus(AutoFocusCallback)}, {@link #cancelAutoFocus}, or {@link
          * #startPreview()}. Applications can call {@link #getParameters()}
          * and this method anytime to get the latest focus distances. If the
-         * focus mode is FOCUS_MODE_CONTINUOUS, focus distances may change from
-         * time to time.
+         * focus mode is FOCUS_MODE_CONTINUOUS_VIDEO, focus distances may change
+         * from time to time.
          *
          * This method is intended to estimate the distance between the camera
          * and the subject. After autofocus, the subject distance may be within
diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java
index 4039a69..3ee8a80 100644
--- a/core/java/android/net/LocalSocket.java
+++ b/core/java/android/net/LocalSocket.java
@@ -70,8 +70,11 @@
         if (!implCreated) {
             synchronized (this) {
                 if (!implCreated) {
-                    implCreated = true;
-                    impl.create(true);
+                    try {
+                        impl.create(true);
+                    } finally {
+                        implCreated = true;
+                    }
                 }
             }
         }
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 5fea6fe..e56e257 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -307,8 +307,10 @@
      * Requires the {@link android.Manifest.permission#REBOOT} permission.
      *
      * @param context      the Context to use
-     * @param packageFile  the update package to install.  Currently
-     * must be on the /cache or /data partitions.
+     * @param packageFile  the update package to install.  Must be on
+     * a partition mountable by recovery.  (The set of partitions
+     * known to recovery may vary from device to device.  Generally,
+     * /cache and /data are safe.)
      *
      * @throws IOException  if writing the recovery command file
      * fails, or if the reboot itself fails.
@@ -316,15 +318,6 @@
     public static void installPackage(Context context, File packageFile)
         throws IOException {
         String filename = packageFile.getCanonicalPath();
-
-        if (filename.startsWith("/cache/")) {
-            filename = "CACHE:" + filename.substring(7);
-        } else if (filename.startsWith("/data/")) {
-            filename = "DATA:" + filename.substring(6);
-        } else {
-            throw new IllegalArgumentException(
-                "Must start with /cache or /data: " + filename);
-        }
         Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
         String arg = "--update_package=" + filename;
         bootCommand(context, arg);
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 871a0441..1e358c9 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -895,6 +895,14 @@
          */
         public static final String COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI = "is_visible_in_downloads_ui";
 
+        /**
+         * If true, the user has confirmed that this download can proceed over the mobile network
+         * even though it exceeds the recommended maximum size.
+         * <P>Type: BOOLEAN</P>
+         */
+        public static final String COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT =
+            "bypass_recommended_size_limit";
+
         /*
          * Lists the destinations that an application can specify for a download.
          */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fd60115..69151df 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3428,6 +3428,15 @@
                 "download_manager_max_bytes_over_mobile";
 
         /**
+         * The recommended maximum size, in bytes, of a download that the download manager should
+         * transfer over a non-wifi connection. Over this size, the use will be warned, but will
+         * have the option to start the download over the mobile connection anyway.
+         * @hide
+         */
+        public static final String DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE =
+                "download_manager_recommended_max_bytes_over_mobile";
+
+        /**
          * ms during which to consume extra events related to Inet connection condition
          * after a transtion to fully-connected
          * @hide
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 456e0d9d..c9835a0 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1284,13 +1284,18 @@
         return mDatabase.getHttpAuthUsernamePassword(host, realm);
     }
 
+    private void clearHelpers() {
+        clearTextEntry(false);
+        selectionDone();
+    }
+
     /**
      * Destroy the internal state of the WebView. This method should be called
      * after the WebView has been removed from the view system. No other
      * methods may be called on a WebView after destroy.
      */
     public void destroy() {
-        clearTextEntry(false);
+        clearHelpers();
         if (mWebViewCore != null) {
             // Set the handlers to null before destroying WebViewCore so no
             // more messages will be posted.
@@ -1608,7 +1613,7 @@
         arg.mUrl = url;
         arg.mExtraHeaders = extraHeaders;
         mWebViewCore.sendMessage(EventHub.LOAD_URL, arg);
-        clearTextEntry(false);
+        clearHelpers();
     }
 
     /**
@@ -1637,7 +1642,7 @@
             arg.mUrl = url;
             arg.mPostData = postData;
             mWebViewCore.sendMessage(EventHub.POST_URL, arg);
-            clearTextEntry(false);
+            clearHelpers();
         } else {
             loadUrl(url);
         }
@@ -1693,7 +1698,7 @@
         arg.mEncoding = encoding;
         arg.mHistoryUrl = historyUrl;
         mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
-        clearTextEntry(false);
+        clearHelpers();
     }
 
     /**
@@ -1710,7 +1715,7 @@
      * Reload the current url.
      */
     public void reload() {
-        clearTextEntry(false);
+        clearHelpers();
         switchOutDrawHistory();
         mWebViewCore.sendMessage(EventHub.RELOAD);
     }
@@ -1790,7 +1795,7 @@
 
     private void goBackOrForward(int steps, boolean ignoreSnapshot) {
         if (steps != 0) {
-            clearTextEntry(false);
+            clearHelpers();
             mWebViewCore.sendMessage(EventHub.GO_BACK_FORWARD, steps,
                     ignoreSnapshot ? 1 : 0);
         }
@@ -4421,7 +4426,7 @@
 
     @Override
     protected void onDetachedFromWindow() {
-        clearTextEntry(false);
+        clearHelpers();
         dismissZoomControl();
         if (hasWindowFocus()) setActive(false);
         super.onDetachedFromWindow();
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index f09421b..487a00d 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -35,6 +35,7 @@
             android:label="@string/permlab_testDenied"
             android:description="@string/permdesc_testDenied" />
 
+    <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
diff --git a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java
index ee0f5f1..a7ec7d5 100644
--- a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java
@@ -27,6 +27,7 @@
 import android.net.DownloadManager.Query;
 import android.net.DownloadManager.Request;
 import android.net.wifi.WifiManager;
+import android.os.Bundle;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
@@ -43,9 +44,12 @@
 import java.io.IOException;
 import java.net.URL;
 import java.util.concurrent.TimeoutException;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
+import java.util.Set;
 import java.util.Vector;
 
 import junit.framework.AssertionFailedError;
@@ -67,6 +71,7 @@
 
     protected static final String LOG_TAG = "android.net.DownloadManagerBaseTest";
     protected static final int HTTP_OK = 200;
+    protected static final int HTTP_REDIRECT = 307;
     protected static final int HTTP_PARTIAL_CONTENT = 206;
     protected static final int HTTP_NOT_FOUND = 404;
     protected static final int HTTP_SERVICE_UNAVAILABLE = 503;
@@ -119,6 +124,7 @@
 
     public static class MultipleDownloadsCompletedReceiver extends BroadcastReceiver {
         private volatile int mNumDownloadsCompleted = 0;
+        private Set<Long> downloadIds = Collections.synchronizedSet(new HashSet<Long>());
 
         /**
          * {@inheritDoc}
@@ -129,6 +135,8 @@
                 ++mNumDownloadsCompleted;
                 Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " +
                         intent.getAction() + " --> total count: " + mNumDownloadsCompleted);
+                Bundle extras = intent.getExtras();
+                downloadIds.add(new Long(extras.getLong(DownloadManager.EXTRA_DOWNLOAD_ID)));
             }
         }
 
@@ -142,6 +150,18 @@
         public int numDownloadsCompleted() {
             return mNumDownloadsCompleted;
         }
+
+        /**
+         * Gets the list of download IDs.
+         * @return A Set<Long> with the ids of the completed downloads.
+         */
+        public Set<Long> getDownloadIds() {
+            synchronized(downloadIds) {
+                Set<Long> returnIds = new HashSet<Long>(downloadIds);
+                return returnIds;
+            }
+        }
+
     }
 
     public static class WiFiChangedReceiver extends BroadcastReceiver {
@@ -196,6 +216,17 @@
     }
 
     /**
+     * Helper to enqueue a response from the MockWebServer with no body.
+     *
+     * @param status The HTTP status code to return for this response
+     * @return Returns the mock web server response that was queued (which can be modified)
+     */
+    protected MockResponse enqueueResponse(int status) {
+        return doEnqueueResponse(status);
+
+    }
+
+    /**
      * Helper to enqueue a response from the MockWebServer.
      *
      * @param status The HTTP status code to return for this response
diff --git a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java b/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java
index be3cbf7..a61f02d 100644
--- a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.Cursor;
+import android.net.DownloadManager;
 import android.net.DownloadManager.Query;
 import android.net.DownloadManager.Request;
 import android.net.DownloadManagerBaseTest.DataType;
@@ -28,6 +29,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.os.StatFs;
 import android.os.SystemClock;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -36,10 +38,13 @@
 import android.util.Log;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.net.URL;
+import java.util.Iterator;
 import java.util.Random;
+import java.util.Set;
 
 import junit.framework.AssertionFailedError;
 
@@ -51,8 +56,11 @@
  */
 public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest {
 
-    private static String LOG_TAG = "android.net.DownloadManagerIntegrationTest";
-    private static String PROHIBITED_DIRECTORY = "/system";
+    private final static String LOG_TAG = "android.net.DownloadManagerIntegrationTest";
+    private final static String PROHIBITED_DIRECTORY =
+            Environment.getRootDirectory().getAbsolutePath();
+    private final static String CACHE_DIR =
+            Environment.getDownloadCacheDirectory().getAbsolutePath();
     protected MultipleDownloadsCompletedReceiver mReceiver = null;
 
     /**
@@ -74,25 +82,48 @@
     public void tearDown() throws Exception {
         super.tearDown();
         setWiFiStateOn(true);
+        removeAllCurrentDownloads();
 
         if (mReceiver != null) {
             mContext.unregisterReceiver(mReceiver);
             mReceiver = null;
-            removeAllCurrentDownloads();
         }
     }
 
     /**
      * Helper that does the actual basic download verification.
      */
-    protected void doBasicDownload(byte[] blobData) throws Exception {
+    protected long doBasicDownload(byte[] blobData) throws Exception {
         long dlRequest = doStandardEnqueue(blobData);
 
         // wait for the download to complete
         waitForDownloadOrTimeout(dlRequest);
 
-        verifyAndCleanupSingleFileDownload(dlRequest, blobData);
         assertEquals(1, mReceiver.numDownloadsCompleted());
+        return dlRequest;
+    }
+
+    /**
+     * Verifies a particular error code was received from a download
+     *
+     * @param uri The uri to enqueue to the DownloadManager
+     * @param error The error code expected
+     * @throws an Exception if the test fails
+     */
+    @LargeTest
+    public void doErrorTest(Uri uri, int error) throws Exception {
+        Request request = new Request(uri);
+        request.setTitle(DEFAULT_FILENAME);
+
+        long dlRequest = mDownloadManager.enqueue(request);
+        waitForDownloadOrTimeout(dlRequest);
+
+        Cursor cursor = getCursor(dlRequest);
+        try {
+            verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE, error);
+        } finally {
+            cursor.close();
+        }
     }
 
     /**
@@ -103,7 +134,8 @@
         int fileSize = 500 * 1024;  // 500k
         byte[] blobData = generateData(fileSize, DataType.BINARY);
 
-        doBasicDownload(blobData);
+        long dlRequest = doBasicDownload(blobData);
+        verifyAndCleanupSingleFileDownload(dlRequest, blobData);
     }
 
     /**
@@ -114,7 +146,8 @@
         int fileSize = 300000;
         byte[] blobData = generateData(fileSize, DataType.TEXT);
 
-        doBasicDownload(blobData);
+        long dlRequest = doBasicDownload(blobData);
+        verifyAndCleanupSingleFileDownload(dlRequest, blobData);
     }
 
     /**
@@ -348,34 +381,209 @@
     }
 
     /**
-     * Tests trying to download two large files (50M bytes, followed by 60M bytes)
+     * Tests downloading a file to cache when there isn't enough space in the cache to hold the
+     * entire file.
      */
     @LargeTest
-    public void testInsufficientSpaceSingleFiles() throws Exception {
-        long fileSize1 = 50000000L;
-        long fileSize2 = 60000000L;
-        File largeFile1 = createFileOnSD(null, fileSize1, DataType.TEXT, null);
-        File largeFile2 = createFileOnSD(null, fileSize2, DataType.TEXT, null);
+    public void testDownloadToCache_whenFull() throws Exception {
+        int DOWNLOAD_FILE_SIZE = 500000;
+
+        StatFs fs = new StatFs(CACHE_DIR);
+        Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks());
+        Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize());
+
+        int blockSize = fs.getBlockSize();
+        int availableBlocks = fs.getAvailableBlocks();
+        int availableBytes = blockSize * availableBlocks;
+        File outFile = null;
 
         try {
-            long dlRequest = doStandardEnqueue(largeFile1);
-            waitForDownloadOrTimeout(dlRequest);
-            ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
-            verifyFileContents(pfd, largeFile1);
-            verifyFileSize(pfd, largeFile1.length());
+            // fill cache to ensure we don't have enough space - take half the size of the
+            // download size, and leave that much freespace left on the cache partition
+            if (DOWNLOAD_FILE_SIZE <= availableBytes) {
+                int writeSizeBytes = availableBytes - (DOWNLOAD_FILE_SIZE / 2);
 
-            dlRequest = doStandardEnqueue(largeFile2);
-            waitForDownloadOrTimeout(dlRequest);
-            Cursor cursor = getCursor(dlRequest);
-            try {
-                verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE,
-                        DownloadManager.ERROR_INSUFFICIENT_SPACE);
-            } finally {
-                cursor.close();
+                int writeSizeBlocks = writeSizeBytes / blockSize;
+                int remainderSizeBlocks = availableBlocks - writeSizeBlocks;
+
+                FileOutputStream fo = null;
+                try {
+                    outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR));
+                    Log.v(LOG_TAG, "writing " + writeSizeBlocks + " blocks to file "
+                            + outFile.getAbsolutePath());
+
+                    fo = new FileOutputStream(outFile);
+
+                    byte[] buffer = new byte[blockSize];
+                    while (fs.getAvailableBlocks() >= remainderSizeBlocks) {
+                        fo.write(buffer);
+                        fs.restat(CACHE_DIR);
+                    }
+                } catch (IOException e) {
+                    Log.e(LOG_TAG, "error filling file: ", e);
+                    throw e;
+                } finally {
+                    if (fo != null) {
+                        fo.close();
+                    }
+                }
             }
+
+            assertTrue(DOWNLOAD_FILE_SIZE > (fs.getAvailableBlocks() * blockSize));
+            byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT);
+            long dlRequest = doBasicDownload(blobData);
+            verifyAndCleanupSingleFileDownload(dlRequest, blobData);
+
         } finally {
-            largeFile1.delete();
-            largeFile2.delete();
+            if (outFile != null) {
+                outFile.delete();
+            }
+        }
+    }
+
+    /**
+     * Tests that files are not deleted when DOWNLOAD_CACHE_NON_PURGEABLE is set, even if we've
+     * run out of space.
+     */
+    @LargeTest
+    public void testDownloadCacheNonPurgeable() throws Exception {
+        int fileSize = 10000000;
+        byte[] blobData = generateData(fileSize, DataType.BINARY);
+        long dlRequest = -1;
+
+        // Fill up the cache partition until there's not enough room for another download.
+        // Note that we need to initiate a download first, then check for the available space. This
+        // is b/c there could be some files that are still left in the cache that can (and will be)
+        // cleared out, but not until DM gets a request for a download and reclaims that
+        // space first.
+        boolean spaceAvailable = true;
+        while (spaceAvailable) {
+            dlRequest = doStandardEnqueue(blobData);
+            waitForDownloadOrTimeout(dlRequest);
+
+            // Check if we've filled up the cache yet
+            StatFs fs = new StatFs(CACHE_DIR);
+            Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks());
+            Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize());
+            int availableBytes = fs.getBlockSize() * fs.getAvailableBlocks();
+            spaceAvailable = (availableBytes > fileSize) ? true : false;
+        }
+
+        // Now add one more download (should not fit in the space left over)
+        dlRequest = doStandardEnqueue(blobData);
+        waitForDownloadOrTimeout(dlRequest);
+
+        // For the last download we should have failed b/c there is not enough space left in cache
+        Cursor cursor = getCursor(dlRequest);
+        try {
+            verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE,
+                    DownloadManager.ERROR_INSUFFICIENT_SPACE);
+        } finally {
+            cursor.close();
+        }
+    }
+
+    /**
+     * Tests that we get the correct download ID from the download notification.
+     */
+    @LargeTest
+    public void testGetDownloadIdOnNotification() throws Exception {
+        byte[] blobData = generateData(3000, DataType.TEXT);  // file size = 3000 bytes
+
+        MockResponse response = enqueueResponse(HTTP_OK, blobData);
+        long dlRequest = doCommonStandardEnqueue();
+        waitForDownloadOrTimeout(dlRequest);
+
+        Set<Long> ids = mReceiver.getDownloadIds();
+        assertEquals(1, ids.size());
+        Iterator<Long> it = ids.iterator();
+        assertEquals("Download ID received from notification does not match initial id!",
+                dlRequest, it.next().longValue());
+    }
+
+    /**
+     * Tests the download failure error after too many redirects (>5).
+     */
+    @LargeTest
+    public void testErrorTooManyRedirects() throws Exception {
+        Uri uri = getServerUri(DEFAULT_FILENAME);
+
+        // force 6 redirects
+        for (int i = 0; i < 6; ++i) {
+            MockResponse response = enqueueResponse(HTTP_REDIRECT);
+            response.addHeader("Location", uri.toString());
+        }
+        doErrorTest(uri, DownloadManager.ERROR_TOO_MANY_REDIRECTS);
+    }
+
+    /**
+     * Tests the download failure error from an unhandled HTTP status code
+     */
+    @LargeTest
+    public void testErrorUnhandledHttpCode() throws Exception {
+        Uri uri = getServerUri(DEFAULT_FILENAME);
+        MockResponse response = enqueueResponse(HTTP_PARTIAL_CONTENT);
+
+        doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE);
+    }
+
+    /**
+     * Tests the download failure error from an unhandled HTTP status code
+     */
+    @LargeTest
+    public void testErrorHttpDataError_invalidRedirect() throws Exception {
+        Uri uri = getServerUri(DEFAULT_FILENAME);
+        MockResponse response = enqueueResponse(HTTP_REDIRECT);
+        response.addHeader("Location", "://blah.blah.blah.com");
+
+        doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR);
+    }
+
+    /**
+     * Tests that we can remove a download from the download manager.
+     */
+    @LargeTest
+    public void testRemoveDownload() throws Exception {
+        int fileSize = 100 * 1024;  // 100k
+        byte[] blobData = generateData(fileSize, DataType.BINARY);
+
+        long dlRequest = doBasicDownload(blobData);
+        Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest));
+        try {
+            assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount());
+            mDownloadManager.remove(dlRequest);
+            cursor.requery();
+            assertEquals("The count of downloads with this ID is not 0!", 0, cursor.getCount());
+        } finally {
+            cursor.close();
+        }
+    }
+
+    /**
+     * Tests that we can set the title of a download.
+     */
+    @LargeTest
+    public void testSetTitle() throws Exception {
+        int fileSize = 50 * 1024;  // 50k
+        byte[] blobData = generateData(fileSize, DataType.BINARY);
+        MockResponse response = enqueueResponse(HTTP_OK, blobData);
+
+        // An arbitrary unicode string title
+        final String title = "\u00a5123;\"\u0152\u017d \u054b \u0a07 \ucce0 \u6820\u03a8\u5c34" +
+                "\uf4ad\u0da9\uc0c5\uc1a8 \uf4c5 \uf4aa\u0023\'";
+
+        Uri uri = getServerUri(DEFAULT_FILENAME);
+        Request request = new Request(uri);
+        request.setTitle(title);
+
+        long dlRequest = mDownloadManager.enqueue(request);
+        waitForDownloadOrTimeout(dlRequest);
+
+        Cursor cursor = getCursor(dlRequest);
+        try {
+            verifyString(cursor, DownloadManager.COLUMN_TITLE, title);
+        } finally {
+            cursor.close();
         }
     }
 }
diff --git a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java
index ed280c9..df781bf 100644
--- a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java
+++ b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java
@@ -54,8 +54,10 @@
     private static final String EXTERNAL_DOWNLOAD_URI_KEY = "external_download_uri";
     // Note: External environment variable ANDROID_TEST_EXTERNAL_URI must be set to point to the
     // external URI under which the files downloaded by the tests can be found. Note that the Uri
-    // must be accessible by the device during a test run.
-    private static String EXTERNAL_DOWNLOAD_URI_VALUE = null;
+    // must be accessible by the device during a test run. Correspondingly,
+    // ANDROID_TEST_EXTERNAL_LARGE_URI should point to the external URI of the folder containing
+    // large files.
+    private static String externalDownloadUriValue = null;
 
     Hashtable<String, String> mExtraParams = null;
 
@@ -69,8 +71,8 @@
         // ensure apk path has been set before test is run
         assertNotNull(getTestAppPath());
         mPMUtils = new PackageManagerHostTestUtils(getDevice());
-        EXTERNAL_DOWNLOAD_URI_VALUE = System.getenv("ANDROID_TEST_EXTERNAL_URI");
-        assertNotNull(EXTERNAL_DOWNLOAD_URI_VALUE);
+        externalDownloadUriValue = System.getenv("ANDROID_TEST_EXTERNAL_URI");
+        assertNotNull(externalDownloadUriValue);
         mExtraParams = getExtraParams();
     }
 
@@ -79,7 +81,7 @@
      */
     protected Hashtable<String, String> getExtraParams() {
         Hashtable<String, String> extraParams = new Hashtable<String, String>();
-        extraParams.put(EXTERNAL_DOWNLOAD_URI_KEY, EXTERNAL_DOWNLOAD_URI_VALUE);
+        extraParams.put(EXTERNAL_DOWNLOAD_URI_KEY, externalDownloadUriValue);
         return extraParams;
     }
 
@@ -198,4 +200,19 @@
                 DOWNLOAD_TEST_RUNNER_NAME, mExtraParams);
         assertTrue(testPassed);
     }
+
+    /**
+     * Spawns a device-based function to test 15 concurrent downloads of 5,000,000-byte files
+     *
+     * @throws Exception if the test failed at any point
+     */
+    public void testDownloadMultipleSimultaneously() throws Exception {
+        mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(),
+                File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true);
+
+        boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
+                FILE_DOWNLOAD_CLASS, "runDownloadMultipleSimultaneously",
+                DOWNLOAD_TEST_RUNNER_NAME, mExtraParams);
+        assertTrue(testPassed);
+    }
 }
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
index ef81353..0293ded 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
@@ -35,6 +35,7 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
+import java.util.HashSet;
 
 import coretestutils.http.MockResponse;
 import coretestutils.http.MockWebServer;
@@ -55,8 +56,13 @@
     protected static String DOWNLOAD_10MB_FILENAME = "External10mb.apk";
     protected static long DOWNLOAD_10MB_FILESIZE = 10258741;
 
+    private static final String FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX = "file";
+    private static final String FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION = ".bin";
+    protected static long CONCURRENT_DOWNLOAD_FILESIZE = 1000000;
+
     // Values to be obtained from TestRunner
     private String externalDownloadUriValue = null;
+    private String externalLargeDownloadUriValue = null;
 
     /**
      * {@inheritDoc }
@@ -65,12 +71,24 @@
     public void setUp() throws Exception {
         super.setUp();
         DownloadManagerTestRunner mRunner = (DownloadManagerTestRunner)getInstrumentation();
-        externalDownloadUriValue = mRunner.externalDownloadUriValue;
+        externalDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue);
         assertNotNull(externalDownloadUriValue);
 
-        if (!externalDownloadUriValue.endsWith("/")) {
-            externalDownloadUriValue += "/";
+        externalLargeDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue);
+        assertNotNull(externalLargeDownloadUriValue);
+    }
+
+    /**
+     * Normalizes a uri to ensure it ends with a "/"
+     *
+     * @param uri The uri to normalize (or null)
+     * @return The normalized uri, or null if null was passed in
+     */
+    public String normalizeUri(String uri) {
+        if (uri != null && !uri.endsWith("/")) {
+            uri += "/";
         }
+        return uri;
     }
 
     /**
@@ -460,4 +478,37 @@
             downloadedFile.delete();
         }
     }
+
+    /**
+     * Tests 15 concurrent downloads of 1,000,000-byte files.
+     *
+     * @throws Exception if test failed
+     */
+    public void runDownloadMultipleSimultaneously() throws Exception {
+        final int TOTAL_DOWNLOADS = 15;
+        HashSet<Long> downloadIds = new HashSet<Long>(TOTAL_DOWNLOADS);
+        MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver();
+
+        // Make sure there are no pending downloads currently going on
+        removeAllCurrentDownloads();
+
+        try {
+            for (int i = 0; i < TOTAL_DOWNLOADS; ++i) {
+                long dlRequest = -1;
+                String filename = FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX + i
+                        + FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION;
+                Uri remoteUri = getExternalFileUri(filename);
+                Request request = new Request(remoteUri);
+                request.setTitle(filename);
+                dlRequest = mDownloadManager.enqueue(request);
+                assertTrue(dlRequest != -1);
+                downloadIds.add(dlRequest);
+            }
+
+            waitForDownloadsOrTimeout(DEFAULT_WAIT_POLL_TIME, 15 * 60 * 2000);  // wait 15 mins max
+            assertEquals(TOTAL_DOWNLOADS, receiver.numDownloadsCompleted());
+        } finally {
+            removeAllCurrentDownloads();
+        }
+    }
 }
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java
index 0f16619..27bf7e1 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java
@@ -30,7 +30,7 @@
  *
  * To run the download manager tests:
  *
- * adb shell am instrument -e external_download_1mb_uri <uri> external_download_500k_uri <uri> \
+ * adb shell am instrument -e external_download_uri <uri> external_large_download_uri <uri> \
  *     -w com.android.frameworks.downloadmanagertests/.DownloadManagerTestRunner
  */
 
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 7c5371a..53039a0 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -380,12 +380,14 @@
     // continuously. Applications should not call
     // CameraHardwareInterface.autoFocus in this mode.
     static const char FOCUS_MODE_EDOF[];
-    // Continuous auto focus mode. The camera continuously tries to focus. This
-    // is ideal for shooting video or shooting photo of moving object. Auto
-    // focus starts when the parameter is set. Applications should not call
-    // CameraHardwareInterface.autoFocus in this mode.  To stop continuous
-    // focus, applications should change the focus mode to other modes.
-    static const char FOCUS_MODE_CONTINUOUS[];
+    // Continuous auto focus mode intended for video recording. The camera
+    // continuously tries to focus. This is ideal for shooting video.
+    // Applications still can call CameraHardwareInterface.takePicture in this
+    // mode but the subject may not be in focus. Auto focus starts when the
+    // parameter is set. Applications should not call
+    // CameraHardwareInterface.autoFocus in this mode. To stop continuous focus,
+    // applications should change the focus mode to other modes.
+    static const char FOCUS_MODE_CONTINUOUS_VIDEO[];
 
 private:
     DefaultKeyedVector<String8,String8>    mMap;
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 362d9ee..83e5e57f 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -142,7 +142,7 @@
 const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
 const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
 const char CameraParameters::FOCUS_MODE_EDOF[] = "edof";
-const char CameraParameters::FOCUS_MODE_CONTINUOUS[] = "continuous";
+const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video";
 
 CameraParameters::CameraParameters()
                 : mMap()
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
index ae67114..ed7601e 100644
--- a/media/java/android/media/AudioEffect.java
+++ b/media/java/android/media/AudioEffect.java
@@ -847,39 +847,40 @@
     // -------------------------------------------------------------------------
 
     /**
-     *  This intent launches an audio effect control panel UI. The goal of this intent is to enable
-     *  separate implementations of music/media player applications and audio effect control
-     *  application or services. This will allow platform vendors to offer more advanced control
-     *  options for standard effects or control for platform specific effects.
+     *  Intent to launch an audio effect control panel UI.
+     *  <p>The goal of this intent is to enable separate implementations of music/media player
+     *  applications and audio effect control application or services.
+     *  This will allow platform vendors to offer more advanced control options for standard effects
+     *  or control for platform specific effects.
      *  <p>The intent carries a number of extras used by the player application to communicate
      *  necessary pieces of information to the control panel application.
      *  <p>The calling application must use the
      *  {@link android.app.Activity#startActivityForResult(Intent, int)} method to launch the
      *  control panel so that its package name is indicated and used by the control panel
      *  application to keep track of changes for this particular application.
-     *  <p>The android.media.EXTRA_AUDIO_SESSION extra will indicate an audio session to which the
+     *  <p>The {@link #EXTRA_AUDIO_SESSION} extra will indicate an audio session to which the
      *  audio effects should be applied. If no audio session is specified, either one of the
      *  follownig will happen:
-     *  - If an audio session was previously opened by the calling application with
+     *  <p>- If an audio session was previously opened by the calling application with
      *  {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intent, the effect changes will
      *  be applied to that session.
-     *  - If no audio session is opened, the changes will be stored in the package specific storage
-     *  area and applied whenever a new audio session is opened by this application.
-     *  <p>The android.media.EXTRA_CONTENT_TYPE extra will help the control panel application
+     *  <p>- If no audio session is opened, the changes will be stored in the package specific
+     *  storage area and applied whenever a new audio session is opened by this application.
+     *  <p>The {@link #EXTRA_CONTENT_TYPE} extra will help the control panel application
      *  customize both the UI layout and the default audio effect settings if none are already
      *  stored for the calling application.
-     *  {@hide} pending API council approval
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL =
         "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL";
 
     /**
-     *  This intent indicates to the effect control application or service that a new audio session
-     *  is opened and requires audio effects to be applied. This is different from
-     *  {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no UI should be displayed in
-     *  this case. Music player applications can broadcast this intent before starting playback
-     *  to make sure that any audio effect settings previously selected by the user are applied.
+     *  Intent to signal to the effect control application or service that a new audio session
+     *  is opened and requires audio effects to be applied.
+     *  <p>This is different from {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no
+     *  UI should be displayed in this case. Music player applications can broadcast this intent
+     *  before starting playback to make sure that any audio effect settings previously selected
+     *  by the user are applied.
      *  <p>The effect control application receiving this intent will look for previously stored
      *  settings for the calling application, create all required audio effects and apply the
      *  effect settings to the specified audio session.
@@ -888,48 +889,50 @@
      *  <p>If no stored settings are found for the calling application, default settings for the
      *  content type indicated by {@link #EXTRA_CONTENT_TYPE} will be applied. The default settings
      *  for a given content type are platform specific.
-     *  {@hide} pending API council approval
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION =
         "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION";
 
     /**
-     *  This intent indicates to the effect control application or service that an audio session
+     *  Intent to signal to the effect control application or service that an audio session
      *  is closed and that effects should not be applied anymore.
-     *  <p>The effect control application receiving this intent will delete all effects on this
-     *  session and store current settings in package specific storage.
+     *  <p>The effect control application receiving this intent will delete all effects on
+     *  this session and store current settings in package specific storage.
      *  <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the
      *  audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory.
      *  <p>It is good practice for applications to broadcast this intent when music playback stops
      *  and/or when exiting to free system resources consumed by audio effect engines.
-     *  {@hide} pending API council approval
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION =
         "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION";
 
     /**
-     * This extra indicates the ID of the audio session the effects should be applied to.
+     * Contains the ID of the audio session the effects should be applied to.
+     * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL},
+     * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
+     * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents.
      * <p>The extra value is of type int and is the audio session ID.
-     *  @see android.media.MediaPlayer#setAudioSessionId(int) for details on audio sessions.
-     *  {@hide} pending API council approval
+     *
+     *  @see android.media.MediaPlayer#setAudioSessionId(int)
      */
      public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION";
 
     /**
-     * This extra indicates the package name of the calling application for
-     * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
+     * Contains the package name of the calling application.
+     * <p>This extra is for use with {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
      * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents.
      * <p>The extra value is a string containing the full package name.
-     *  {@hide} pending API council approval
      */
     public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME";
 
     /**
-     * This extra indicates which type of content is played by the application. This information is
-     * used by the effect control application to customize UI and default effect settings.
-     * The content type is one of the following:
+     * Indicates which type of content is played by the application.
+     * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} and
+     * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intents.
+     * <p>This information is used by the effect control application to customize UI and select
+     * appropriate default effect settings. The content type is one of the following:
      * <ul>
      *   <li>{@link #CONTENT_TYPE_MUSIC}</li>
      *   <li>{@link #CONTENT_TYPE_MOVIE}</li>
@@ -937,28 +940,23 @@
      *   <li>{@link #CONTENT_TYPE_VOICE}</li>
      * </ul>
      * If omitted, the content type defaults to {@link #CONTENT_TYPE_MUSIC}.
-     *  {@hide} pending API council approval
      */
     public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE";
 
     /**
      * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is music
-     *  {@hide} pending API council approval
      */
     public static final int  CONTENT_TYPE_MUSIC = 0;
     /**
-     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video of movie
-     *  {@hide} pending API council approval
+     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video or movie
      */
     public static final int  CONTENT_TYPE_MOVIE = 1;
     /**
      * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is game audio
-     *  {@hide} pending API council approval
      */
     public static final int  CONTENT_TYPE_GAME = 2;
     /**
      * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is voice audio
-     *  {@hide} pending API council approval
      */
     public static final int  CONTENT_TYPE_VOICE = 3;
 
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index c5b51c0..e4ed5e6 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -123,6 +123,8 @@
     mAnchorTimeUs = 0;
     mNumSamplesOutput = 0;
     mStarted = true;
+    mNumDecodedBuffers = 0;
+    mUpsamplingFactor = 2;
 
     return OK;
 }
@@ -207,22 +209,65 @@
 
     Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
 
-    // Check on the sampling rate to see whether it is changed.
-    int32_t sampleRate;
-    CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
-    if (mConfig->samplingRate != sampleRate) {
-        mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
-        LOGW("Sample rate was %d, but now is %d",
-                sampleRate, mConfig->samplingRate);
-        buffer->release();
-        mInputBuffer->release();
-        mInputBuffer = NULL;
-        return INFO_FORMAT_CHANGED;
+    /*
+     * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
+     * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
+     * rate system and the sampling rate in the final output is actually
+     * doubled compared with the core AAC decoder sampling rate.
+     *
+     * Explicit signalling is done by explicitly defining SBR audio object
+     * type in the bitstream. Implicit signalling is done by embedding
+     * SBR content in AAC extension payload specific to SBR, and hence
+     * requires an AAC decoder to perform pre-checks on actual audio frames.
+     *
+     * Thus, we could not say for sure whether a stream is
+     * AAC+/eAAC+ until the first data frame is decoded.
+     */
+    if (++mNumDecodedBuffers <= 2) {
+        LOGV("audio/extended audio object type: %d + %d",
+            mConfig->audioObjectType, mConfig->extendedAudioObjectType);
+        LOGV("aac+ upsampling factor: %d desired channels: %d",
+            mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels);
+
+        CHECK(mNumDecodedBuffers > 0);
+        if (mNumDecodedBuffers == 1) {
+            mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor;
+            // Check on the sampling rate to see whether it is changed.
+            int32_t sampleRate;
+            CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
+            if (mConfig->samplingRate != sampleRate) {
+                mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
+                LOGW("Sample rate was %d Hz, but now is %d Hz",
+                        sampleRate, mConfig->samplingRate);
+                buffer->release();
+                mInputBuffer->release();
+                mInputBuffer = NULL;
+                return INFO_FORMAT_CHANGED;
+            }
+        } else {  // mNumDecodedBuffers == 2
+            if (mConfig->extendedAudioObjectType == MP4AUDIO_AAC_LC ||
+                mConfig->extendedAudioObjectType == MP4AUDIO_LTP) {
+                if (mUpsamplingFactor == 2) {
+                    // The stream turns out to be not aacPlus mode anyway
+                    LOGW("Disable AAC+/eAAC+ since extended audio object type is %d",
+                        mConfig->extendedAudioObjectType);
+                    mConfig->aacPlusEnabled = 0;
+                }
+            } else {
+                if (mUpsamplingFactor == 1) {
+                    // aacPlus mode does not buy us anything, but to cause
+                    // 1. CPU load to increase, and
+                    // 2. a half speed of decoding
+                    LOGW("Disable AAC+/eAAC+ since upsampling factor is 1");
+                    mConfig->aacPlusEnabled = 0;
+                }
+            }
+        }
     }
 
     size_t numOutBytes =
         mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
-    if (mConfig->aacPlusUpsamplingFactor == 2) {
+    if (mUpsamplingFactor == 2) {
         if (mConfig->desiredChannels == 1) {
             memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
         }
diff --git a/media/libstagefright/include/AACDecoder.h b/media/libstagefright/include/AACDecoder.h
index 200f93c..886a3b7 100644
--- a/media/libstagefright/include/AACDecoder.h
+++ b/media/libstagefright/include/AACDecoder.h
@@ -53,6 +53,8 @@
     int64_t mAnchorTimeUs;
     int64_t mNumSamplesOutput;
     status_t mInitCheck;
+    int64_t  mNumDecodedBuffers;
+    int32_t  mUpsamplingFactor;
 
     MediaBuffer *mInputBuffer;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
index 7ccf210..0fc092e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
@@ -711,21 +711,20 @@
                 ConnectivityManager.EXTRA_NETWORK_INFO));
         int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
         Slog.d(TAG, "got CONNECTIVITY_ACTION - info=" + info + ", status = " + connectionStatus);
-        if (info.isConnected() == false) return;
+
+        int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
 
         switch (info.getType()) {
         case ConnectivityManager.TYPE_MOBILE:
-            if (info.isConnected()) {
-                updateDataNetType(info.getSubtype(), connectionStatus);
-                updateDataIcon();
-                updateSignalStrength(); // apply any change in connectionStatus
-            }
+            mInetCondition = inetCondition;
+            updateDataNetType(info.getSubtype());
+            updateDataIcon();
+            updateSignalStrength(); // apply any change in connectionStatus
             break;
         case ConnectivityManager.TYPE_WIFI:
+            mInetCondition = inetCondition;
             if (info.isConnected()) {
                 mIsWifiConnected = true;
-                mInetCondition =
-                        (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
                 int iconId;
                 if (mLastWifiSignalLevel == -1) {
                     iconId = sWifiSignalImages[mInetCondition][0];
@@ -738,7 +737,6 @@
             } else {
                 mLastWifiSignalLevel = -1;
                 mIsWifiConnected = false;
-                mInetCondition = 0;
                 int iconId = sWifiSignalImages[0][0];
 
                 mService.setIcon("wifi", iconId, 0);
@@ -777,9 +775,8 @@
         @Override
         public void onDataConnectionStateChanged(int state, int networkType) {
             mDataState = state;
-            updateDataNetType(networkType, 0);
+            updateDataNetType(networkType);
             updateDataIcon();
-            updateSignalStrength(); // apply the change in connection status
         }
 
         @Override
@@ -940,8 +937,7 @@
         return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
     }
 
-    private final void updateDataNetType(int net, int inetCondition) {
-        mInetCondition = (inetCondition > INET_CONDITION_THRESHOLD ? 1 : 0);
+    private final void updateDataNetType(int net) {
         switch (net) {
         case TelephonyManager.NETWORK_TYPE_EDGE:
             mDataIconList = sDataNetType_e[mInetCondition];
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
index 55d31ec..29df28e 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
@@ -30,6 +30,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.hardware.Usb;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -70,11 +71,11 @@
     static final boolean localLOGV = false;
 
     /** Used to detect when the USB cable is unplugged, so we can call finish() */
-    private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mUsbStateReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent.getAction() == Intent.ACTION_BATTERY_CHANGED) {
-                handleBatteryChanged(intent);
+            if (intent.getAction().equals(Usb.ACTION_USB_STATE)) {
+                handleUsbStateChanged(intent);
             }
         }
     };
@@ -139,7 +140,7 @@
         super.onResume();
 
         mStorageManager.registerListener(mStorageListener);
-        registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        registerReceiver(mUsbStateReceiver, new IntentFilter(Usb.ACTION_USB_STATE));
         try {
             switchDisplay(mStorageManager.isUsbMassStorageEnabled());
         } catch (Exception ex) {
@@ -151,15 +152,15 @@
     protected void onPause() {
         super.onPause();
         
-        unregisterReceiver(mBatteryReceiver);
+        unregisterReceiver(mUsbStateReceiver);
         if (mStorageManager == null && mStorageListener != null) {
             mStorageManager.unregisterListener(mStorageListener);
         }
     }
 
-    private void handleBatteryChanged(Intent intent) {
-        int pluggedType = intent.getIntExtra("plugged", 0);
-        if (pluggedType == 0) {
+    private void handleUsbStateChanged(Intent intent) {
+        boolean connected = intent.getExtras().getBoolean(Usb.USB_CONNECTED);
+        if (!connected) {
             // It was disconnected from the plug, so finish
             finish();
         }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 8603e51..f38748b 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -920,11 +920,19 @@
             newNet = tryFailover(prevNetType);
             if (newNet != null) {
                 NetworkInfo switchTo = newNet.getNetworkInfo();
+                if (!switchTo.isConnected()) {
+                    // if the other net is connected they've already reset this and perhaps even gotten
+                    // a positive report we don't want to overwrite, but if not we need to clear this now
+                    // to turn our cellular sig strength white
+                    mDefaultInetConditionPublished = 0;
+                }
                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
             } else {
+                mDefaultInetConditionPublished = 0; // we're not connected anymore
                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
             }
         }
+        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
         // do this before we broadcast the change
         handleConnectivityChange(prevNetType);
 
@@ -1083,12 +1091,20 @@
             newNet = tryFailover(info.getType());
             if (newNet != null) {
                 NetworkInfo switchTo = newNet.getNetworkInfo();
+                if (!switchTo.isConnected()) {
+                    // if the other net is connected they've already reset this and perhaps even gotten
+                    // a positive report we don't want to overwrite, but if not we need to clear this now
+                    // to turn our cellular sig strength white
+                    mDefaultInetConditionPublished = 0;
+                }
                 intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
             } else {
+                mDefaultInetConditionPublished = 0;
                 intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
             }
         }
 
+        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
         sendStickyBroadcast(intent);
         /*
          * If the failover network is already connected, then immediately send
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 87329e3..c047e10 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -173,6 +173,7 @@
     private static final int MESSAGE_STOP_ACCESS_POINT  = 7;
     private static final int MESSAGE_SET_CHANNELS       = 8;
     private static final int MESSAGE_ENABLE_NETWORKS    = 9;
+    private static final int MESSAGE_START_SCAN         = 10;
 
 
     private final  WifiHandler mWifiHandler;
@@ -385,23 +386,12 @@
 
     /**
      * see {@link android.net.wifi.WifiManager#startScan()}
-     * @return {@code true} if the operation succeeds
      */
-    public boolean startScan(boolean forceActive) {
+    public void startScan(boolean forceActive) {
         enforceChangePermission();
+        if (mWifiHandler == null) return;
 
-        switch (mWifiStateTracker.getSupplicantState()) {
-            case DISCONNECTED:
-            case INACTIVE:
-            case SCANNING:
-            case DORMANT:
-                break;
-            default:
-                mWifiStateTracker.setScanResultHandling(
-                        WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);
-                break;
-        }
-        return mWifiStateTracker.scan(forceActive);
+        Message.obtain(mWifiHandler, MESSAGE_START_SCAN, forceActive ? 1 : 0, 0).sendToTarget();
     }
 
     /**
@@ -2001,6 +1991,21 @@
                     mWifiStateTracker.enableAllNetworks(getConfiguredNetworks());
                     break;
 
+                case MESSAGE_START_SCAN:
+                    boolean forceActive = (msg.arg1 == 1);
+                    switch (mWifiStateTracker.getSupplicantState()) {
+                        case DISCONNECTED:
+                        case INACTIVE:
+                        case SCANNING:
+                        case DORMANT:
+                            break;
+                        default:
+                            mWifiStateTracker.setScanResultHandling(
+                                    WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);
+                            break;
+                    }
+                    mWifiStateTracker.scan(forceActive);
+                    break;
             }
         }
     }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0ee559e..198b1e6 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -42,7 +42,7 @@
 
     boolean pingSupplicant();
 
-    boolean startScan(boolean forceActive);
+    void startScan(boolean forceActive);
 
     List<ScanResult> getScanResults();
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index dd162f2..f883588 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -570,7 +570,8 @@
      */
     public boolean startScan() {
         try {
-            return mService.startScan(false);
+            mService.startScan(false);
+            return true;
         } catch (RemoteException e) {
             return false;
         }
@@ -588,7 +589,8 @@
      */
     public boolean startScanActive() {
         try {
-            return mService.startScan(true);
+            mService.startScan(true);
+            return true;
         } catch (RemoteException e) {
             return false;
         }