Merge "Fix number picker vertical scroll computations" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index d31a38dc..973a9fdc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -639,13 +639,13 @@
     field public static final int keyPreviewHeight = 16843321; // 0x1010239
     field public static final int keyPreviewLayout = 16843319; // 0x1010237
     field public static final int keyPreviewOffset = 16843320; // 0x1010238
+    field public static final int keySet = 16843739; // 0x10103db
     field public static final int keyTextColor = 16843318; // 0x1010236
     field public static final int keyTextSize = 16843316; // 0x1010234
     field public static final int keyWidth = 16843325; // 0x101023d
     field public static final int keyboardLayout = 16843691; // 0x10103ab
     field public static final int keyboardMode = 16843341; // 0x101024d
     field public static final int keycode = 16842949; // 0x10100c5
-    field public static final int keyset = 16843739; // 0x10103db
     field public static final int killAfterRestore = 16843420; // 0x101029c
     field public static final int label = 16842753; // 0x1010001
     field public static final int labelFor = 16843718; // 0x10103c6
@@ -6522,6 +6522,7 @@
     field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
     field public static final int FLAG_PERSIST_GRANT_URI_PERMISSION = 64; // 0x40
     field public static final int FLAG_RECEIVER_FOREGROUND = 268435456; // 0x10000000
+    field public static final int FLAG_RECEIVER_NO_ABORT = 134217728; // 0x8000000
     field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
     field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
     field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
@@ -19178,7 +19179,7 @@
     field public static final android.print.PrintAttributes.MediaSize NA_LETTER;
     field public static final android.print.PrintAttributes.MediaSize NA_MONARCH;
     field public static final android.print.PrintAttributes.MediaSize NA_QUARTO;
-    field public static final android.print.PrintAttributes.MediaSize NA_TBLOID;
+    field public static final android.print.PrintAttributes.MediaSize NA_TABLOID;
     field public static final android.print.PrintAttributes.MediaSize OM_DAI_PA_KAI;
     field public static final android.print.PrintAttributes.MediaSize OM_JUURO_KU_KAI;
     field public static final android.print.PrintAttributes.MediaSize OM_PA_KAI;
@@ -30010,7 +30011,7 @@
     method public deprecated void onConsoleMessage(java.lang.String, int, java.lang.String);
     method public boolean onConsoleMessage(android.webkit.ConsoleMessage);
     method public boolean onCreateWindow(android.webkit.WebView, boolean, boolean, android.os.Message);
-    method public void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onGeolocationPermissionsHidePrompt();
     method public void onGeolocationPermissionsShowPrompt(java.lang.String, android.webkit.GeolocationPermissions.Callback);
     method public void onHideCustomView();
@@ -30020,7 +30021,7 @@
     method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
     method public deprecated boolean onJsTimeout();
     method public void onProgressChanged(android.webkit.WebView, int);
-    method public void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
     method public void onReceivedTitle(android.webkit.WebView, java.lang.String);
     method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
@@ -30076,12 +30077,12 @@
     method public int getCacheMode();
     method public synchronized java.lang.String getCursiveFontFamily();
     method public synchronized boolean getDatabaseEnabled();
-    method public synchronized java.lang.String getDatabasePath();
+    method public deprecated synchronized java.lang.String getDatabasePath();
     method public synchronized int getDefaultFixedFontSize();
     method public synchronized int getDefaultFontSize();
     method public synchronized java.lang.String getDefaultTextEncodingName();
     method public static java.lang.String getDefaultUserAgent(android.content.Context);
-    method public android.webkit.WebSettings.ZoomDensity getDefaultZoom();
+    method public deprecated android.webkit.WebSettings.ZoomDensity getDefaultZoom();
     method public boolean getDisplayZoomControls();
     method public synchronized boolean getDomStorageEnabled();
     method public synchronized java.lang.String getFantasyFontFamily();
@@ -30118,11 +30119,11 @@
     method public void setCacheMode(int);
     method public synchronized void setCursiveFontFamily(java.lang.String);
     method public synchronized void setDatabaseEnabled(boolean);
-    method public synchronized void setDatabasePath(java.lang.String);
+    method public deprecated synchronized void setDatabasePath(java.lang.String);
     method public synchronized void setDefaultFixedFontSize(int);
     method public synchronized void setDefaultFontSize(int);
     method public synchronized void setDefaultTextEncodingName(java.lang.String);
-    method public void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
+    method public deprecated void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
     method public void setDisplayZoomControls(boolean);
     method public synchronized void setDomStorageEnabled(boolean);
     method public deprecated void setEnableSmoothTransition(boolean);
@@ -30165,9 +30166,10 @@
   public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
     method public static android.webkit.WebSettings.LayoutAlgorithm valueOf(java.lang.String);
     method public static final android.webkit.WebSettings.LayoutAlgorithm[] values();
-    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
+    enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
     enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NORMAL;
     enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
+    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm TEXT_AUTOSIZING;
   }
 
   public static final class WebSettings.PluginState extends java.lang.Enum {
@@ -30220,7 +30222,7 @@
     method public long getUsage();
   }
 
-  public static abstract interface WebStorage.QuotaUpdater {
+  public static abstract deprecated interface WebStorage.QuotaUpdater {
     method public abstract void updateQuota(long);
   }
 
@@ -30248,7 +30250,7 @@
     method public boolean canGoForward();
     method public deprecated boolean canZoomIn();
     method public deprecated boolean canZoomOut();
-    method public android.graphics.Picture capturePicture();
+    method public deprecated android.graphics.Picture capturePicture();
     method public void clearCache(boolean);
     method public void clearFormData();
     method public void clearHistory();
@@ -30265,7 +30267,7 @@
     method public void findAllAsync(java.lang.String);
     method public void findNext(boolean);
     method public void flingScroll(int, int);
-    method public void freeMemory();
+    method public deprecated void freeMemory();
     method public android.net.http.SslCertificate getCertificate();
     method public int getContentHeight();
     method public android.graphics.Bitmap getFavicon();
@@ -31610,6 +31612,8 @@
     ctor public NumberPicker(android.content.Context);
     ctor public NumberPicker(android.content.Context, android.util.AttributeSet);
     ctor public NumberPicker(android.content.Context, android.util.AttributeSet, int);
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
     method public java.lang.String[] getDisplayedValues();
     method public int getMaxValue();
     method public int getMinValue();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7925123..dcc6328 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3588,6 +3588,12 @@
      */
     public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
     /**
+     * If this is an ordered broadcast, don't allow receivers to abort the broadcast.
+     * They can still propagate results through to later receivers, but they can not prevent
+     * later receivers from seeing the broadcast.
+     */
+    public static final int FLAG_RECEIVER_NO_ABORT = 0x08000000;
+    /**
      * If set, when sending a broadcast <i>before boot has completed</i> only
      * registered receivers will be called -- no BroadcastReceiver components
      * will be launched.  Sticky intent state will be recorded properly even
@@ -3600,14 +3606,14 @@
      *
      * @hide
      */
-    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x08000000;
+    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x04000000;
     /**
      * Set when this broadcast is for a boot upgrade, a special mode that
      * allows the broadcast to be sent before the system is ready and launches
      * the app process with no providers running in it.
      * @hide
      */
-    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x04000000;
+    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000;
 
     /**
      * @hide Flags that can't be changed with PendingIntent.
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index efe6b15..e61fe89 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -391,7 +391,7 @@
         public static final MediaSize NA_LEDGER =
                 new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
         /** North America Tabloid media size: 11" x 17" (279mm × 432mm) */
-        public static final MediaSize NA_TBLOID =
+        public static final MediaSize NA_TABLOID =
                 new MediaSize("NA_TABLOID", "android",
                         R.string.mediaSize_na_tabloid, 11000, 17000);
         /** North America Index Card 3x5 media size: 3" x 5" (76mm x 127mm) */
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 21b0578..aa57423 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -238,9 +238,10 @@
     * @param totalQuota The total quota for all origins, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onExceededDatabaseQuota(String url, String databaseIdentifier,
             long quota, long estimatedDatabaseSize, long totalQuota,
             WebStorage.QuotaUpdater quotaUpdater) {
@@ -263,9 +264,10 @@
     * @param quota the current maximum Application Cache size, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
             WebStorage.QuotaUpdater quotaUpdater) {
         quotaUpdater.updateQuota(quota);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 7a38a16..98ef66e 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -33,14 +33,17 @@
     /**
      * Enum for controlling the layout of html.
      * <ul>
-     *   <li>NORMAL means no rendering changes.</li>
+     *   <li>NORMAL means no rendering changes. This is the recommended choice for maximum
+     *       compatibility across different platforms and Android versions.</li>
      *   <li>SINGLE_COLUMN moves all content into one column that is the width of the
      *       view.</li>
-     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible.</li>
+     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible. Only use
+     *       this for API levels prior to {@link android.os.Build.VERSION_CODES#KITKAT}.</li>
      *   <li>TEXT_AUTOSIZING boosts font size of paragraphs based on heuristics to make
      *       the text readable when viewing a wide-viewport layout in the overview mode.
      *       It is recommended to enable zoom support {@link #setSupportZoom} when
-     *       using this mode.</li>
+     *       using this mode. Supported from API level
+     *       {@link android.os.Build.VERSION_CODES#KITKAT}</li>
      * </ul>
      */
     // XXX: These must match LayoutAlgorithm in Settings.h in WebCore.
@@ -51,10 +54,11 @@
          */
         @Deprecated
         SINGLE_COLUMN,
-        NARROW_COLUMNS,
         /**
-         * @hide
+         * @deprecated This algorithm is now obsolete.
          */
+        @Deprecated
+        NARROW_COLUMNS,
         TEXT_AUTOSIZING
     }
 
@@ -510,7 +514,10 @@
      * and {@link #setUseWideViewPort} can be used.
      *
      * @param zoom the zoom density
+     * @deprecated This method is no longer supported, see the function documentation for
+     *             recommended alternatives.
      */
+    @Deprecated
     public void setDefaultZoom(ZoomDensity zoom) {
         throw new MustOverrideException();
     }
@@ -523,6 +530,7 @@
      *
      * @return the zoom density
      * @see #setDefaultZoom
+     * @deprecated Will only return the default value.
      */
     public ZoomDensity getDefaultZoom() {
         throw new MustOverrideException();
@@ -1059,10 +1067,13 @@
      *
      * @param databasePath a path to the directory where databases should be
      *                     saved.
+     * @deprecated Database paths are managed by the implementation and calling this method
+     *             will have no effect.
      */
     // This will update WebCore when the Sync runs in the C++ side.
     // Note that the WebCore Database Tracker only allows the path to be set
     // once.
+    @Deprecated
     public synchronized void setDatabasePath(String databasePath) {
         throw new MustOverrideException();
     }
@@ -1161,7 +1172,9 @@
      *
      * @return the String path to the database storage API databases
      * @see #setDatabasePath
+     * @deprecated Database paths are managed by the implementation this method is obsolete.
      */
+    @Deprecated
     public synchronized String getDatabasePath() {
         throw new MustOverrideException();
     }
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 7d9373c..3bfe9cf 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -41,12 +41,9 @@
      * See
      * {@link WebChromeClient#onExceededDatabaseQuota} and
      * {@link WebChromeClient#onReachedMaxAppCacheSize}.
+     * @deprecated This class is obsolete and no longer used.
      */
-    // We primarily want this to allow us to call back the sleeping WebCore
-    // thread from outside the WebViewCore class (as the native call is
-    // private). It is imperative that the setDatabaseQuota method is
-    // executed after a decision to either allow or deny new quota is made,
-    // otherwise the WebCore thread will remain asleep.
+    @Deprecated
     public interface QuotaUpdater {
         /**
          * Provides a new quota, specified in bytes.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 15331dc..20fb1a7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1058,9 +1058,20 @@
      * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and
      * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} inclusive, the
      * picture does not include fixed position elements or scrollable divs.
+     * <p>
+     * Note that from {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} the returned picture
+     * should only be drawn into bitmap-backed Canvas - using any other type of Canvas will involve
+     * additional conversion at a cost in memory and performance. Also the
+     * {@link android.graphics.Picture#createFromStream} and
+     * {@link android.graphics.Picture#writeToStream} methods are not supported on the
+     * returned object.
+     *
+     * @deprecated Use {@link #onDraw} to obtain a bitmap snapshot of the WebView, or
+     * {@link #saveWebArchive} to save the content to a file.
      *
      * @return a picture that captures the current contents of this WebView
      */
+    @Deprecated
     public Picture capturePicture() {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "capturePicture");
@@ -1342,7 +1353,10 @@
     /**
      * Informs this WebView that memory is low so that it can free any available
      * memory.
+     * @deprecated Memory caches are automatically dropped when no longer needed, and in response
+     *             to system memory pressure.
      */
+    @Deprecated
     public void freeMemory() {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "freeMemory");
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 8819237..497c0c6 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -280,6 +280,9 @@
     }
 
     void startSelected(int which, boolean always) {
+        if (isFinishing()) {
+            return;
+        }
         ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
         Intent intent = mAdapter.intentForPosition(which);
         onIntentSelected(ri, intent, always);
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 80810d5..b20f5ba 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1821,7 +1821,9 @@
         <attr name="value" />
     </declare-styleable>
 
-    <attr name="keyset" />
+    <!-- Groups signing keys into a {@code KeySet} for easier reference in
+            other APIs. However, currently no APIs use this. -->
+    <attr name="keySet" />
     <declare-styleable name="PublicKey">
         <attr name="value" />
     </declare-styleable>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c5d4810..ef7f2b7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2058,7 +2058,7 @@
     =============================================================== -->
   <eat-comment />
 
-  <public type="attr" name="keyset" />
+  <public type="attr" name="keySet" />
   <public type="attr" name="targetId" />
   <public type="attr" name="fromScene" />
   <public type="attr" name="toScene" />
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 2846e61..0d9a386 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -138,7 +138,8 @@
     DroidSansHebrew-Regular.ttf \
     DroidSansHebrew-Bold.ttf \
     DroidSansArmenian.ttf \
-    DroidSansGeorgian.ttf
+    DroidSansGeorgian.ttf \
+    AndroidEmoji.ttf
 
 endif # !MINIMAL_FONT
 
diff --git a/data/fonts/AndroidEmoji.ttf b/data/fonts/AndroidEmoji.ttf
new file mode 100644
index 0000000..98f72e7
--- /dev/null
+++ b/data/fonts/AndroidEmoji.ttf
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 69db6aa..ede7ef4 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -186,6 +186,11 @@
     </family>
     <family>
         <fileset>
+            <file>AndroidEmoji.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoColorEmoji.ttf</file>
         </fileset>
     </family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index a677c4f..05cca13 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -43,6 +43,7 @@
     DroidSansMono.ttf \
     DroidSansArmenian.ttf \
     DroidSansGeorgian.ttf \
+    AndroidEmoji.ttf \
     Clockopia.ttf \
     AndroidClock.ttf \
     AndroidClock_Highlight.ttf \
diff --git a/packages/PrintSpooler/res/color/item_text_color.xml b/packages/PrintSpooler/res/color/item_text_color.xml
new file mode 100644
index 0000000..f580fbd
--- /dev/null
+++ b/packages/PrintSpooler/res/color/item_text_color.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+   <item android:state_enabled="true" android:color="#333333" />
+   <item android:color="#888888"/>
+</selector>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
index 7817094..98b5cfe 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
@@ -14,10 +14,10 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.printspooler.PrintDialogFrame xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/content_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center"
     android:background="@color/container_background">
-</FrameLayout>
+</com.android.printspooler.PrintDialogFrame>
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
index abf3c03..83019b9 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
@@ -15,17 +15,16 @@
 -->
 
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
+    android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical"
     android:scrollbars="vertical"
     android:background="@color/editable_background">
 
-    <GridLayout
-        android:layout_width="wrap_content"
+    <LinearLayout
+        android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:columnCount="2">
+        android:orientation="vertical">
 
         <!-- Destination -->
 
@@ -37,190 +36,179 @@
             android:layout_marginTop="24dip"
             android:layout_marginStart="24dip"
             android:layout_marginEnd="24dip"
-            android:layout_row="0"
-            android:layout_column="0"
-            android:layout_columnSpan="2"
             android:minHeight="?android:attr/listPreferredItemHeightSmall">
         </Spinner>
 
-        <!-- Copies -->
-
-        <view
-            class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
-            android:id="@+id/copies_edittext"
+        <LinearLayout
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_marginStart="24dip"
-            android:layout_marginEnd="6dip"
-            android:layout_row="2"
-            android:layout_column="0"
-            android:layout_gravity="bottom|fill_horizontal"
-            style="@style/PrintOptionEditTextStyle"
-            android:inputType="numberDecimal">
-        </view>
+            android:orientation="horizontal"
+            android:baselineAligned="false">
 
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="12dip"
-            android:layout_marginStart="36dip"
-            android:layout_marginEnd="6dip"
-            android:layout_row="1"
-            android:layout_column="0"
-            style="@style/PrintOptionTextViewStyle"
-            android:labelFor="@id/copies_edittext"
-            android:text="@string/label_copies">
-        </TextView>
+            <LinearLayout
+                android:layout_width="0dip"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:orientation="vertical">
 
-        <!-- Paper size -->
+                <!-- Copies -->
 
-        <Spinner
-            android:id="@+id/paper_size_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="6dip"
-            android:layout_marginEnd="24dip"
-            android:layout_row="2"
-            android:layout_column="1"
-            android:layout_gravity="fill_horizontal"
-            style="@style/PrintOptionSpinnerStyle">
-        </Spinner>
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="12dip"
+                    android:layout_marginStart="36dip"
+                    android:layout_marginEnd="6dip"
+                    android:textAppearance="@style/PrintOptionTitleTextAppearance"
+                    android:labelFor="@+id/copies_edittext"
+                    android:text="@string/label_copies">
+                </TextView>
 
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="12dip"
-            android:layout_marginStart="18dip"
-            android:layout_marginEnd="24dip"
-            android:layout_row="1"
-            android:layout_column="1"
-            style="@style/PrintOptionTextViewStyle"
-            android:labelFor="@id/paper_size_spinner"
-            android:text="@string/label_paper_size">
-        </TextView>
+                <view
+                    class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+                    android:id="@+id/copies_edittext"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="24dip"
+                    android:layout_marginEnd="6dip"
+                    style="@style/PrintOptionEditTextStyle"
+                    android:inputType="numberDecimal">
+                </view>
 
-        <!-- Color -->
+                <!-- Color -->
 
-        <Spinner
-            android:id="@+id/color_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="24dip"
-            android:layout_marginEnd="6dip"
-            android:layout_row="4"
-            android:layout_column="0"
-            android:layout_gravity="fill_horizontal"
-            style="@style/PrintOptionSpinnerStyle">
-        </Spinner>
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="12dip"
+                    android:layout_marginStart="36dip"
+                    android:layout_marginEnd="6dip"
+                    android:textAppearance="@style/PrintOptionTitleTextAppearance"
+                    android:labelFor="@+id/color_spinner"
+                    android:text="@string/label_color">
+                </TextView>
 
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="12dip"
-            android:layout_marginStart="36dip"
-            android:layout_marginEnd="6dip"
-            android:layout_row="3"
-            android:layout_column="0"
-            style="@style/PrintOptionTextViewStyle"
-            android:labelFor="@id/color_spinner"
-            android:text="@string/label_color">
-        </TextView>
+                <Spinner
+                    android:id="@+id/color_spinner"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="24dip"
+                    android:layout_marginEnd="6dip"
+                    style="@style/PrintOptionSpinnerStyle">
+                </Spinner>
 
-        <!-- Orientation -->
+                <!-- Range options -->
 
-        <Spinner
-            android:id="@+id/orientation_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="6dip"
-            android:layout_marginEnd="24dip"
-            android:layout_row="4"
-            android:layout_column="1"
-            android:layout_gravity="fill_horizontal"
-            style="@style/PrintOptionSpinnerStyle">
-        </Spinner>
+                <TextView
+                    android:id="@+id/range_options_title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="12dip"
+                    android:layout_marginStart="36dip"
+                    android:textAppearance="@style/PrintOptionTitleTextAppearance"
+                    android:labelFor="@+id/range_options_spinner"
+                    android:text="@string/label_pages">
+                </TextView>
 
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="12dip"
-            android:layout_marginStart="18dip"
-            android:layout_marginEnd="24dip"
-            android:layout_row="3"
-            android:layout_column="1"
-            style="@style/PrintOptionTextViewStyle"
-            android:labelFor="@id/orientation_spinner"
-            android:text="@string/label_orientation">
-        </TextView>
+                <Spinner
+                    android:id="@+id/range_options_spinner"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="24dip"
+                    android:layout_marginEnd="6dip"
+                    style="@style/PrintOptionSpinnerStyle">
+                </Spinner>
 
-        <!-- Range options -->
+            </LinearLayout>
 
-        <Spinner
-            android:id="@+id/range_options_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="24dip"
-            android:layout_marginEnd="6dip"
-            android:layout_row="6"
-            android:layout_column="0"
-            android:layout_gravity="fill_horizontal"
-            style="@style/PrintOptionSpinnerStyle">
-        </Spinner>
+            <LinearLayout
+                android:layout_width="0dip"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:orientation="vertical">
 
-        <TextView
-            android:id="@+id/range_options_title"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="12dip"
-            android:layout_marginStart="36dip"
-            android:layout_row="5"
-            android:layout_column="0"
-            style="@style/PrintOptionTextViewStyle"
-            android:labelFor="@id/range_options_spinner"
-            android:text="@string/label_pages">
-        </TextView>
+                <!-- Paper size -->
 
-        <!-- Pages -->
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="12dip"
+                    android:layout_marginStart="18dip"
+                    android:layout_marginEnd="24dip"
+                    android:textAppearance="@style/PrintOptionTitleTextAppearance"
+                    android:labelFor="@+id/paper_size_spinner"
+                    android:text="@string/label_paper_size">
+                </TextView>
 
-        <view
-            class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
-            android:id="@+id/page_range_edittext"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="6dip"
-            android:layout_marginEnd="24dip"
-            android:layout_row="6"
-            android:layout_column="1"
-            android:layout_gravity="bottom|fill_horizontal"
-            style="@style/PrintOptionEditTextStyle"
-            android:visibility="gone"
-            android:inputType="textNoSuggestions">
-        </view>
+                <Spinner
+                    android:id="@+id/paper_size_spinner"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="6dip"
+                    android:layout_marginEnd="24dip"
+                    style="@style/PrintOptionSpinnerStyle">
+                </Spinner>
 
-       <TextView
-            android:id="@+id/page_range_title"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="12dip"
-            android:layout_marginStart="12dip"
-            android:layout_marginEnd="24dip"
-            android:layout_row="5"
-            android:layout_column="1"
-            style="@style/PrintOptionTextViewStyle"
-            android:labelFor="@id/page_range_edittext"
-            android:text="@string/pages_range_example"
-            android:textAllCaps="false">
-        </TextView>
+                <!-- Orientation -->
 
-       <!-- Print button -->
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="12dip"
+                    android:layout_marginStart="18dip"
+                    android:layout_marginEnd="24dip"
+                    android:textAppearance="@style/PrintOptionTitleTextAppearance"
+                    android:labelFor="@+id/orientation_spinner"
+                    android:text="@string/label_orientation">
+                </TextView>
+
+                <Spinner
+                    android:id="@+id/orientation_spinner"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="6dip"
+                    android:layout_marginEnd="24dip"
+                    style="@style/PrintOptionSpinnerStyle">
+                </Spinner>
+
+                <!-- Pages -->
+
+               <TextView
+                    android:id="@+id/page_range_title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="12dip"
+                    android:layout_marginStart="12dip"
+                    android:layout_marginEnd="24dip"
+                    android:textAppearance="@style/PrintOptionTitleTextAppearance"
+                    android:text="@string/pages_range_example"
+                    android:labelFor="@+id/page_range_edittext"
+                    android:textAllCaps="false">
+                </TextView>
+
+                <view
+                    class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+                    android:id="@+id/page_range_edittext"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="6dip"
+                    android:layout_marginEnd="24dip"
+                    android:layout_gravity="bottom|fill_horizontal"
+                    style="@style/PrintOptionEditTextStyle"
+                    android:visibility="gone"
+                    android:inputType="textNoSuggestions">
+                </view>
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <!-- Print button -->
 
         <ImageView
-            android:layout_width="wrap_content"
+            android:layout_width="fill_parent"
             android:layout_height="1dip"
             android:layout_marginTop="24dip"
-            android:layout_row="7"
-            android:layout_column="0"
-            android:layout_columnSpan="2"
             android:layout_gravity="fill_horizontal"
             android:background="@color/separator"
             android:contentDescription="@null">
@@ -229,18 +217,14 @@
         <Button
             android:id="@+id/print_button"
             style="?android:attr/buttonBarButtonStyle"
-            android:layout_width="wrap_content"
+            android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="fill_horizontal"
-            android:layout_row="8"
-            android:layout_column="0"
-            android:layout_columnSpan="2"
             android:text="@string/print_button"
             android:textSize="16sp"
-            android:textColor="@color/important_text">
+            android:textColor="@color/item_text_color">
         </Button>
 
-    </GridLayout>
+    </LinearLayout>
 
 </ScrollView>
-
diff --git a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
index 48189bd..f00da0d 100644
--- a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:paddingStart="8dip"
@@ -32,7 +32,8 @@
         android:ellipsize="end"
         android:textIsSelectable="false"
         android:gravity="top|left"
-        android:textColor="@color/important_text">
+        android:textColor="@color/item_text_color"
+        android:duplicateParentState="true">
     </TextView>
 
     <TextView
@@ -44,7 +45,8 @@
         android:ellipsize="end"
         android:textIsSelectable="false"
         android:visibility="gone"
-        android:textColor="@color/important_text">
+        android:textColor="@color/item_text_color"
+        android:duplicateParentState="true">
 
     </TextView>
 
diff --git a/packages/PrintSpooler/res/values/constants.xml b/packages/PrintSpooler/res/values/constants.xml
index 96cdeb1..e5a9d5d 100644
--- a/packages/PrintSpooler/res/values/constants.xml
+++ b/packages/PrintSpooler/res/values/constants.xml
@@ -24,4 +24,6 @@
         <item>@integer/page_option_value_page_range</item>
     </integer-array>
 
+    <dimen name="print_dialog_frame_max_width_dip">400dip</dimen>
+
 </resources>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/values/styles.xml b/packages/PrintSpooler/res/values/styles.xml
index fe11c93..f6db6be 100644
--- a/packages/PrintSpooler/res/values/styles.xml
+++ b/packages/PrintSpooler/res/values/styles.xml
@@ -26,22 +26,14 @@
     <style name="PrintOptionSpinnerStyle">
         <item name="android:paddingTop">0dip</item>
         <item name="android:paddingBottom">0dip</item>
-        <item name="android:minWidth">150dip</item>
-        <item name="android:maxWidth">200dip</item>
         <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
     </style>
 
     <style name="PrintOptionEditTextStyle">
          <item name="android:selectAllOnFocus">true</item>
          <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
-         <item name="android:maxWidth">200dip</item>
          <item name="android:singleLine">true</item>
          <item name="android:ellipsize">end</item>
     </style>
 
-    <style name="PrintOptionTextViewStyle">
-         <item name="android:textAppearance">@style/PrintOptionTitleTextAppearance</item>
-         <item name="android:maxWidth">200dip</item>
-    </style>
-
 </resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
index 0431b94..72f6f0a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.Loader;
 import android.os.AsyncTask;
-import android.os.Build;
 import android.print.PrintManager;
 import android.print.PrinterDiscoverySession;
 import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
@@ -34,8 +33,6 @@
 
 import com.android.internal.util.FastXmlSerializer;
 
-import libcore.io.IoUtils;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -50,6 +47,8 @@
 import java.util.List;
 import java.util.Map;
 
+import libcore.io.IoUtils;
+
 /**
  * This class is responsible for loading printers by doing discovery
  * and merging the discovered printers with the previously used ones.
@@ -86,38 +85,44 @@
         mPersistenceManager.addPrinterAndWritePrinterHistory(printer);
     }
 
-    private void computeAndDeliverResult() {
+    private void computeAndDeliverResult(Map<PrinterId, PrinterInfo> discoveredPrinters) {
         if (!isStarted()) {
             return;
         }
 
         List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
 
-        // We want the first few favorite printers on top of the list.
-        final int favoriteCount = Math.min(mFavoritePrinters.size(),
-                MAX_FAVORITE_PRINTER_COUNT);
-        for (int i = 0; i < favoriteCount; i++) {
-            printers.add(mFavoritePrinters.get(i));
+        // Add the updated favorite printers.
+        final int favoritePrinterCount = mFavoritePrinters.size();
+        for (int i = 0; i < favoritePrinterCount; i++) {
+            PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
+            PrinterInfo updatedPrinter = discoveredPrinters.remove(
+                    favoritePrinter.getId());
+            if (updatedPrinter != null) {
+                printers.add(updatedPrinter);
+            } else {
+                printers.add(favoritePrinter);
+            }
         }
 
-        // Add discovered printers updating favorites if needed.
+        // Add other updated printers.
         final int printerCount = mPrinters.size();
         for (int i = 0; i < printerCount; i++) {
-            PrinterInfo discoveredPrinter = mPrinters.get(i);
-            boolean printerHandled = false;
-            for (int j = 0; j< favoriteCount; j++) {
-                PrinterInfo favoritePrinter = printers.get(j);
-                if (favoritePrinter.getId().equals(discoveredPrinter.getId())) {
-                    printers.set(j, discoveredPrinter);
-                    printerHandled = true;
-                    break;
-                }
-            }
-            if (!printerHandled) {
-                printers.add(discoveredPrinter);
+            PrinterInfo printer = mPrinters.get(i);
+            PrinterInfo updatedPrinter = discoveredPrinters.remove(
+                    printer.getId());
+            if (updatedPrinter != null) {
+                printers.add(updatedPrinter);
             }
         }
 
+        // Add the new printers, i.e. what is left.
+        printers.addAll(discoveredPrinters.values());
+
+        // Update the list of printers.
+        mPrinters.clear();
+        mPrinters.addAll(printers);
+
         // Deliver the printers.
         deliverResult(printers);
     }
@@ -129,8 +134,8 @@
         }
         // The contract is that if we already have a valid,
         // result the we have to deliver it immediately.
-        if (!mPrinters.isEmpty() || !mFavoritePrinters.isEmpty()) {
-            computeAndDeliverResult();
+        if (!mPrinters.isEmpty()) {
+            deliverResult(new ArrayList<PrinterInfo>(mPrinters));
         }
         // Always load the data to ensure discovery period is
         // started and to make sure obsolete printers are updated.
@@ -161,17 +166,22 @@
             mDiscoverySession.setOnPrintersChangeListener(new OnPrintersChangeListener() {
                 @Override
                 public void onPrintersChanged() {
-                    mPrinters.clear();
-                    mPrinters.addAll(mDiscoverySession.getPrinters());
-                    computeAndDeliverResult();
+                    ArrayMap<PrinterId, PrinterInfo> printersMap =
+                            new ArrayMap<PrinterId, PrinterInfo>();
+                    List<PrinterInfo> printers = mDiscoverySession.getPrinters();
+                    final int printerCount = printers.size();
+                    for (int i = 0; i < printerCount; i++) {
+                        PrinterInfo printer = printers.get(i);
+                        printersMap.put(printer.getId(), printer);
+                    }
+                    computeAndDeliverResult(printersMap);
                 }
             });
             mPersistenceManager.readPrinterHistory();
         }
         if (mPersistenceManager.isReadHistoryCompleted()
                 && !mDiscoverySession.isPrinterDiscoveryStarted()) {
-            final int favoriteCount = Math.min(MAX_FAVORITE_PRINTER_COUNT,
-                    mFavoritePrinters.size());
+            final int favoriteCount = mFavoritePrinters.size();
             List<PrinterId> printerIds = new ArrayList<PrinterId>(favoriteCount);
             for (int i = 0; i < favoriteCount; i++) {
                 printerIds.add(mFavoritePrinters.get(i).getId());
@@ -322,7 +332,8 @@
             Collections.sort(favoriteRecords);
 
             // Write the favorites to the output.
-            final int favoriteCount = favoriteRecords.size();
+            final int favoriteCount = Math.min(favoriteRecords.size(),
+                    MAX_FAVORITE_PRINTER_COUNT);
             List<PrinterInfo> favoritePrinters = new ArrayList<PrinterInfo>(favoriteCount);
             for (int i = 0; i < favoriteCount; i++) {
                 PrinterInfo printer = favoriteRecords.get(i).printer;
@@ -362,13 +373,15 @@
                 mHistoricalPrinters = printers;
 
                 // Compute the favorite printers.
-                mFavoritePrinters.addAll(computeFavoritePrinters(printers));
+                mFavoritePrinters.clear();
+                mFavoritePrinters.addAll(computeFavoritePrinters(mHistoricalPrinters));
 
                 mReadHistoryInProgress = false;
                 mReadHistoryCompleted = true;
 
                 // Deliver the favorites.
-                computeAndDeliverResult();
+                Map<PrinterId, PrinterInfo> discoveredPrinters = Collections.emptyMap();
+                computeAndDeliverResult(discoveredPrinters);
 
                 // Start loading the available printers.
                 loadInternal();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java b/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
new file mode 100644
index 0000000..6dd8aa0a
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+public class PrintDialogFrame extends FrameLayout {
+
+    public final int mMaxWidth;
+
+    public PrintDialogFrame(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mMaxWidth = context.getResources().getDimensionPixelSize(
+                R.dimen.print_dialog_frame_max_width_dip);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        if (widthMode == MeasureSpec.AT_MOST) {
+            final int receivedWidth = MeasureSpec.getSize(widthMeasureSpec);
+            final int computedWidth = Math.min(mMaxWidth, receivedWidth);
+            widthMeasureSpec = MeasureSpec.makeMeasureSpec(computedWidth,
+                    MeasureSpec.EXACTLY);
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+}
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
index 4bf1db8..596435a 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -25,6 +25,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
 import java.net.ProxySelector;
@@ -198,9 +199,15 @@
 
                 while (mIsRunning) {
                     try {
-                        ProxyConnection parser = new ProxyConnection(serverSocket.accept());
+                        Socket socket = serverSocket.accept();
+                        // Only receive local connections.
+                        if (socket.getInetAddress().isLoopbackAddress()) {
+                            ProxyConnection parser = new ProxyConnection(socket);
 
-                        threadExecutor.execute(parser);
+                            threadExecutor.execute(parser);
+                        } else {
+                            socket.close();
+                        }
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 37fbb13..fea7623 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -143,6 +143,7 @@
      * Information about services for a single user.
      */
     class ServiceMap extends Handler {
+        final int mUserId;
         final ArrayMap<ComponentName, ServiceRecord> mServicesByName
                 = new ArrayMap<ComponentName, ServiceRecord>();
         final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent
@@ -165,6 +166,10 @@
 
         static final int MSG_BG_START_TIMEOUT = 1;
 
+        ServiceMap(int userId) {
+            mUserId = userId;
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -224,6 +229,9 @@
                 Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
                 sendMessageAtTime(msg, when);
             }
+            if (mStartingBackground.size() < mMaxStartingBackground) {
+                mAm.backgroundServicesFinishedLocked(mUserId);
+            }
         }
     }
 
@@ -239,10 +247,15 @@
         return getServiceMap(callingUser).mServicesByName.get(name);
     }
 
+    boolean hasBackgroundServices(int callingUser) {
+        ServiceMap smap = mServiceMap.get(callingUser);
+        return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;
+    }
+
     private ServiceMap getServiceMap(int callingUser) {
         ServiceMap smap = mServiceMap.get(callingUser);
         if (smap == null) {
-            smap = new ServiceMap();
+            smap = new ServiceMap(callingUser);
             mServiceMap.put(callingUser, smap);
         }
         return smap;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 80f4b00..f08b5b9 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -21,12 +21,12 @@
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
 import android.app.AppOpsManager;
 import android.appwidget.AppWidgetManager;
 import android.util.ArrayMap;
-
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
@@ -52,7 +52,6 @@
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.StackBox;
 import com.android.server.wm.WindowManagerService;
-
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -155,7 +154,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.format.Time;
-import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
@@ -519,7 +517,7 @@
      * This is the process holding what we currently consider to be
      * the "home" activity.
      */
-    ArraySet<ProcessRecord> mHomeProcess = new ArraySet<ProcessRecord>();
+    ProcessRecord mHomeProcess;
 
     /**
      * This is the process holding the activity the user last visited that
@@ -1903,8 +1901,8 @@
     private ActivityManagerService() {
         Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
 
-        mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
-        mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);
+        mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT, false);
+        mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT, true);
         mBroadcastQueues[0] = mFgBroadcastQueue;
         mBroadcastQueues[1] = mBgBroadcastQueue;
 
@@ -4910,6 +4908,7 @@
                         final int userId = mStartedUsers.keyAt(i);
                         Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                        intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
                         broadcastIntentLocked(null, null, intent, null,
                                 new IIntentReceiver.Stub() {
                                     @Override
@@ -4924,7 +4923,7 @@
                                 },
                                 0, null, null,
                                 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
-                                AppOpsManager.OP_NONE, false, false, MY_PID, Process.SYSTEM_UID,
+                                AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID,
                                 userId);
                     }
                 }
@@ -9121,8 +9120,8 @@
         // with a home activity running in the process to prevent a repeatedly crashing app
         // from blocking the user to manually clear the list.
         final ArrayList<ActivityRecord> activities = app.activities;
-        if (mHomeProcess.contains(app) && activities.size() > 0
-                    && (app.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+        if (app == mHomeProcess && activities.size() > 0
+                    && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if (r.isHomeActivity()) {
@@ -10399,20 +10398,13 @@
                 pw.print("  mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
             }
         }
-        if (!mHomeProcess.isEmpty()) {
-            final int size = mHomeProcess.size();
-            ProcessRecord[] processes = new ProcessRecord[size];
-            mHomeProcess.toArray(processes);
-            for (int processNdx = 0; processNdx < size; ++processNdx) {
-                final ProcessRecord app = processes[processNdx];
-                if (dumpPackage == null || app.pkgList.containsKey(dumpPackage)) {
-                    if (needSep) {
-                        pw.println();
-                        needSep = false;
-                    }
-                    pw.println("  mHomeProcess[" + processNdx + "]: " + app);
-                }
+        if (mHomeProcess != null && (dumpPackage == null
+                || mHomeProcess.pkgList.containsKey(dumpPackage))) {
+            if (needSep) {
+                pw.println();
+                needSep = false;
             }
+            pw.println("  mHomeProcess: " + mHomeProcess);
         }
         if (mPreviousProcess != null && (dumpPackage == null
                 || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
@@ -11942,8 +11934,6 @@
         }
         mHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget();
 
-        mHomeProcess.remove(app);
-
         // If the caller is restarting this app, then leave it in its
         // current lists and let the caller take care of it.
         if (restarting) {
@@ -11973,8 +11963,8 @@
                 "Clean-up removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
-        if (mHomeProcess.contains(app)) {
-            mHomeProcess.remove(app);
+        if (app == mHomeProcess) {
+            mHomeProcess = null;
         }
         if (app == mPreviousProcess) {
             mPreviousProcess = null;
@@ -12578,14 +12568,13 @@
             boolean doTrim = false;
 
             synchronized(this) {
-                ReceiverList rl
-                = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
+                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                 if (rl != null) {
                     if (rl.curBroadcast != null) {
                         BroadcastRecord r = rl.curBroadcast;
                         final boolean doNext = finishReceiverLocked(
                                 receiver.asBinder(), r.resultCode, r.resultData,
-                                r.resultExtras, r.resultAbort, true);
+                                r.resultExtras, r.resultAbort);
                         if (doNext) {
                             doTrim = true;
                             r.queue.processNextBroadcast(false);
@@ -13212,16 +13201,20 @@
     }
 
     private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
-            String resultData, Bundle resultExtras, boolean resultAbort,
-            boolean explicit) {
+            String resultData, Bundle resultExtras, boolean resultAbort) {
         final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver);
         if (r == null) {
             Slog.w(TAG, "finishReceiver called but not found on queue");
             return false;
         }
 
-        return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort,
-                explicit);
+        return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, false);
+    }
+
+    void backgroundServicesFinishedLocked(int userId) {
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            queue.backgroundServicesFinishedLocked(userId);
+        }
     }
 
     public void finishReceiver(IBinder who, int resultCode, String resultData,
@@ -13236,7 +13229,7 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             boolean doNext = false;
-            BroadcastRecord r = null;
+            BroadcastRecord r;
 
             synchronized(this) {
                 r = broadcastRecordForReceiverLocked(who);
@@ -13900,7 +13893,7 @@
             }
         }
 
-        if (mHomeProcess.contains(app)) {
+        if (app == mHomeProcess) {
             if (adj > ProcessList.HOME_APP_ADJ) {
                 // This process is hosting what we currently consider to be the
                 // home app, so we don't want to let it go into the background.
@@ -13967,7 +13960,7 @@
                 if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
                     procState = ActivityManager.PROCESS_STATE_SERVICE;
                 }
-                if (app.hasShownUi && !mHomeProcess.contains(app)) {
+                if (app.hasShownUi && app != mHomeProcess) {
                     // If this process has shown some UI, let it immediately
                     // go to the LRU list because it may be pretty heavy with
                     // UI stuff.  We'll tag it with a label just to help
@@ -14030,7 +14023,7 @@
                         if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
                             // Not doing bind OOM management, so treat
                             // this guy more like a started service.
-                            if (app.hasShownUi && !mHomeProcess.contains(app)) {
+                            if (app.hasShownUi && app != mHomeProcess) {
                                 // If this process has shown some UI, let it immediately
                                 // go to the LRU list because it may be pretty heavy with
                                 // UI stuff.  We'll tag it with a label just to help
@@ -14085,7 +14078,7 @@
                             // about letting this process get into the LRU
                             // list to be killed and restarted if needed for
                             // memory.
-                            if (app.hasShownUi && !mHomeProcess.contains(app)
+                            if (app.hasShownUi && app != mHomeProcess
                                     && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                 adjType = "cch-bound-ui-services";
                             } else {
@@ -14199,7 +14192,7 @@
                     clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
                 }
                 if (adj > clientAdj) {
-                    if (app.hasShownUi && !mHomeProcess.contains(app)
+                    if (app.hasShownUi && app != mHomeProcess
                             && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                         app.adjType = "cch-ui-provider";
                     } else {
@@ -15061,7 +15054,7 @@
                             // to be good enough at this point that destroying
                             // activities causes more harm than good.
                             if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
-                                    && !mHomeProcess.contains(app) && app != mPreviousProcess) {
+                                    && app != mHomeProcess && app != mPreviousProcess) {
                                 // Need to do this on its own message because the stack may not
                                 // be in a consistent state at this point.
                                 // For these apps we will also finish their activities
@@ -15704,10 +15697,11 @@
                 final int userId = uss.mHandle.getIdentifier();
                 Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
                 broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null,
                         android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
-                        false, false, MY_PID, Process.SYSTEM_UID, userId);
+                        true, false, MY_PID, Process.SYSTEM_UID, userId);
             }
             int num = mUserLru.size();
             int i = 0;
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 6e50808..4359895 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -143,9 +143,6 @@
     private boolean inHistory;  // are we in the history stack?
     final ActivityStackSupervisor mStackSupervisor;
 
-    /** Launch the home activity rather than the activity at the top of stack */
-    boolean mLaunchHomeTaskNext;
-
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
         pw.print(prefix); pw.print("packageName="); pw.print(packageName);
@@ -243,6 +240,8 @@
         pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
                 pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
                 pw.print(" forceNewConfig="); pw.println(forceNewConfig);
+        pw.print(prefix); pw.print("mActivityType=");
+                pw.println(activityTypeToString(mActivityType));
         pw.print(prefix); pw.print("thumbHolder: ");
                 pw.print(Integer.toHexString(System.identityHashCode(thumbHolder)));
                 if (thumbHolder != null) {
@@ -1040,6 +1039,15 @@
         return null;
     }
 
+    private String activityTypeToString(int type) {
+        switch (type) {
+            case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
+            case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
+            case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
+            default: return Integer.toString(type);
+        }
+    }
+
     @Override
     public String toString() {
         if (stringName != null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 1f64101..1482440 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1000,7 +1000,8 @@
         boolean behindFullscreen = !mStackSupervisor.isFrontStack(this) &&
                 !(forceHomeShown && isHomeStack());
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if (r.finishing) {
@@ -1083,7 +1084,7 @@
                         // At this point, nothing else needs to be shown
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
                         behindFullscreen = true;
-                    } else if (r.mLaunchHomeTaskNext) {
+                    } else if (task.mOnTopOfHome) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
                         showHomeBehindStack = true;
                         behindFullscreen = true;
@@ -1224,7 +1225,7 @@
 
         final TaskRecord nextTask = next.task;
         final TaskRecord prevTask = prev != null ? prev.task : null;
-        if (prevTask != null && prev.mLaunchHomeTaskNext && prev.finishing && prev.frontOfTask) {
+        if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
             if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
             if (prevTask == nextTask) {
                 ArrayList<ActivityRecord> activities = prevTask.mActivities;
@@ -1234,7 +1235,6 @@
                     // r is usually the same as next, but what if two activities were launched
                     // before prev finished?
                     if (!r.finishing) {
-                        r.mLaunchHomeTaskNext = true;
                         r.frontOfTask = true;
                         break;
                     }
@@ -1243,7 +1243,7 @@
                 // This task is going away but it was supposed to return to the home task.
                 // Now the task above it has to return to the home task instead.
                 final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
-                mTaskHistory.get(taskNdx).mActivities.get(0).mLaunchHomeTaskNext = true;
+                mTaskHistory.get(taskNdx).mOnTopOfHome = true;
             } else {
                 if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next");
                 return mStackSupervisor.resumeHomeActivity(prev);
@@ -2254,7 +2254,7 @@
                 if (r.state == ActivityState.RESUMED
                         || r.state == ActivityState.PAUSING
                         || r.state == ActivityState.PAUSED) {
-                    if (!r.isHomeActivity() || !mService.mHomeProcess.contains(r.app)) {
+                    if (!r.isHomeActivity() || mService.mHomeProcess != r.app) {
                         Slog.w(TAG, "  Force finishing activity "
                                 + r.intent.getComponent().flattenToShortString());
                         finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
@@ -2933,7 +2933,7 @@
             if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
                 // Caller wants the home activity moved with it.  To accomplish this,
                 // we'll just indicate that this task returns to the home task.
-                task.mActivities.get(0).mLaunchHomeTaskNext = true;
+                task.mOnTopOfHome = true;
             }
             moveTaskToFrontLocked(task, null, options);
             return true;
@@ -2994,17 +2994,17 @@
      * If a watcher is installed, the action is preflighted and the watcher has an opportunity
      * to premeptively cancel the move.
      *
-     * @param task The taskId to collect and move to the bottom.
+     * @param taskId The taskId to collect and move to the bottom.
      * @return Returns true if the move completed, false if not.
      */
-    final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
-        Slog.i(TAG, "moveTaskToBack: " + task);
+    final boolean moveTaskToBackLocked(int taskId, ActivityRecord reason) {
+        Slog.i(TAG, "moveTaskToBack: " + taskId);
 
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
         if (mStackSupervisor.isFrontStack(this) && mService.mController != null) {
-            ActivityRecord next = topRunningActivityLocked(null, task);
+            ActivityRecord next = topRunningActivityLocked(null, taskId);
             if (next == null) {
                 next = topRunningActivityLocked(null, 0);
             }
@@ -3024,9 +3024,9 @@
         }
 
         if (DEBUG_TRANSITION) Slog.v(TAG,
-                "Prepare to back transition: task=" + task);
+                "Prepare to back transition: task=" + taskId);
 
-        final TaskRecord tr = taskForIdLocked(task);
+        final TaskRecord tr = taskForIdLocked(taskId);
         if (tr == null) {
             return false;
         }
@@ -3038,28 +3038,15 @@
         // We make sure here that some activity in the stack will launch home.
         ActivityRecord lastActivity = null;
         int numTasks = mTaskHistory.size();
-        int taskNdx;
-        for (taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
-            int activityNdx;
-            for (activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.mLaunchHomeTaskNext) {
-                    break;
-                }
-                if (taskNdx == 1 && activityNdx == 0) {
-                    // Final activity before tr task.
-                    lastActivity = r;
-                }
-            }
-            if (activityNdx >= 0) {
-                // Early exit, we found an activity that will launchHomeTaskNext.
+        for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.mOnTopOfHome) {
                 break;
             }
-        }
-        if (lastActivity != null) {
-            // No early exit, we did not find an activity that will launchHomeTaskNext, set one.
-            lastActivity.mLaunchHomeTaskNext = true;
+            if (taskNdx == 1) {
+                // Set the last task before tr to go to home.
+                task.mOnTopOfHome = true;
+            }
         }
 
         if (reason != null &&
@@ -3072,15 +3059,15 @@
         } else {
             mWindowManager.prepareAppTransition(AppTransition.TRANSIT_TASK_TO_BACK, false);
         }
-        mWindowManager.moveTaskToBottom(task);
+        mWindowManager.moveTaskToBottom(taskId);
 
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
 
-        if (numTasks <= 1 || (mResumedActivity != null && mResumedActivity.task == tr &&
-                mResumedActivity.mLaunchHomeTaskNext)) {
-            mResumedActivity.mLaunchHomeTaskNext = false;
+        final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
+        if (task == tr && task.mOnTopOfHome || numTasks <= 1) {
+            task.mOnTopOfHome = false;
             return mStackSupervisor.resumeHomeActivity(null);
         }
 
@@ -3427,7 +3414,7 @@
         }
         final ActivityRecord top = topRunningActivityLocked(null);
         final boolean launchHomeTaskNext =
-                top != null && top.app == app && top.mLaunchHomeTaskNext;
+                top != null && top.app == app && top.task.mOnTopOfHome;
 
         // Remove this application's activities from active lists.
         boolean hasVisibleActivities = removeHistoryRecordsForAppLocked(app);
@@ -3534,6 +3521,11 @@
     }
 
     boolean removeTask(TaskRecord task) {
+        final int taskNdx = mTaskHistory.indexOf(task);
+        final int topTaskNdx = mTaskHistory.size() - 1;
+        if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
+            mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
+        }
         mTaskHistory.remove(task);
         return mTaskHistory.isEmpty();
     }
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 7756ff9..219cb85 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -282,7 +282,7 @@
     boolean resumeHomeActivity(ActivityRecord prev) {
         moveHomeStack(true);
         if (prev != null) {
-            prev.mLaunchHomeTaskNext = false;
+            prev.task.mOnTopOfHome = false;
         }
         mHomeStack.moveHomeTaskToTop();
         ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
@@ -304,7 +304,7 @@
                 r = stack.topRunningActivityLocked(null);
             }
             if (r != null && !r.isHomeActivity() && r.isRootActivity()) {
-                r.mLaunchHomeTaskNext = true;
+                r.task.mOnTopOfHome = true;
             }
         }
     }
@@ -906,7 +906,8 @@
                         r.task.taskId, r.shortComponentName);
             }
             if (r.isHomeActivity() && r.isNotResolverActivity()) {
-                mService.mHomeProcess.add(app);
+                // Home process is the root process of the task.
+                mService.mHomeProcess = r.task.mActivities.get(0).app;
             }
             mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             r.sleeping = false;
@@ -1429,7 +1430,7 @@
                                     (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                     == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                                 // Caller wants to appear on home activity.
-                                r.mLaunchHomeTaskNext = true;
+                                intentActivity.task.mOnTopOfHome = true;
                             }
                             targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
                             options = null;
@@ -1543,7 +1544,7 @@
                         // sure we have correctly resumed the top activity.
                         if (doResume) {
                             // Reset flag so it gets correctly reevaluated.
-                            intentActivity.mLaunchHomeTaskNext = false;
+                            intentActivity.task.mOnTopOfHome = false;
                             setLaunchHomeTaskNextFlag(sourceRecord, intentActivity, targetStack);
                             targetStack.resumeTopActivityLocked(null, options);
                         } else {
@@ -1640,7 +1641,7 @@
                         == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
                     // Caller wants to appear on home activity, so before starting
                     // their own activity we will bring home to the front.
-                    r.mLaunchHomeTaskNext = true;
+                    r.task.mOnTopOfHome = true;
                 }
             }
         } else if (sourceRecord != null) {
@@ -1949,7 +1950,7 @@
         // makes sense to.
         if (r.app != null && fgApp != null && r.app != fgApp
                 && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
-                && !mService.mHomeProcess.contains(r.app)) {
+                && r.app != mService.mHomeProcess) {
             mService.mPreviousProcess = r.app;
             mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
         }
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 254a219..b35ca79 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -54,8 +54,9 @@
     static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
     static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
 
-    static final int MAX_BROADCAST_HISTORY = 25;
-    static final int MAX_BROADCAST_SUMMARY_HISTORY = 100;
+    static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 25;
+    static final int MAX_BROADCAST_SUMMARY_HISTORY
+            = ActivityManager.isLowRamDeviceStatic() ? 25 : 100;
 
     final ActivityManagerService mService;
 
@@ -70,14 +71,20 @@
     final long mTimeoutPeriod;
 
     /**
+     * If true, we can delay broadcasts while waiting services to finish in the previous
+     * receiver's process.
+     */
+    final boolean mDelayBehindServices;
+
+    /**
      * Lists of all active broadcasts that are to be executed immediately
      * (without waiting for another broadcast to finish).  Currently this only
      * contains broadcasts to registered receivers, to avoid spinning up
      * a bunch of processes to execute IntentReceiver components.  Background-
      * and foreground-priority broadcasts are queued separately.
      */
-    final ArrayList<BroadcastRecord> mParallelBroadcasts
-            = new ArrayList<BroadcastRecord>();
+    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();
+
     /**
      * List of all active broadcasts that are to be executed one at a time.
      * The object at the top of the list is the currently activity broadcasts;
@@ -85,20 +92,17 @@
      * broadcasts, separate background- and foreground-priority queues are
      * maintained.
      */
-    final ArrayList<BroadcastRecord> mOrderedBroadcasts
-            = new ArrayList<BroadcastRecord>();
+    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();
 
     /**
      * Historical data of past broadcasts, for debugging.
      */
-    final BroadcastRecord[] mBroadcastHistory
-            = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+    final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
 
     /**
      * Summary of historical data of past broadcasts, for debugging.
      */
-    final Intent[] mBroadcastSummaryHistory
-            = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
+    final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
 
     /**
      * Set when we current have a BROADCAST_INTENT_MSG in flight.
@@ -128,10 +132,6 @@
     static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
 
     final Handler mHandler = new Handler() {
-        //public Handler() {
-        //    if (localLOGV) Slog.v(TAG, "Handler started!");
-        //}
-
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case BROADCAST_INTENT_MSG: {
@@ -163,10 +163,12 @@
         }
     }
 
-    BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) {
+    BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod,
+            boolean allowDelayBehindServices) {
         mService = service;
         mQueueName = name;
         mTimeoutPeriod = timeoutPeriod;
+        mDelayBehindServices = allowDelayBehindServices;
     }
 
     public boolean isPendingBroadcastProcessLocked(int pid) {
@@ -260,7 +262,7 @@
                         + br.curComponent.flattenToShortString(), e);
                 logBroadcastReceiverDiscardLocked(br);
                 finishReceiverLocked(br, br.resultCode, br.resultData,
-                        br.resultExtras, br.resultAbort, true);
+                        br.resultExtras, br.resultAbort, false);
                 scheduleBroadcastsLocked();
                 // We need to reset the state if we failed to start the receiver.
                 br.state = BroadcastRecord.IDLE;
@@ -289,7 +291,7 @@
             // let the broadcast continue.
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
+                    r.resultExtras, r.resultAbort, false);
             reschedule = true;
         }
 
@@ -299,7 +301,7 @@
                     "[" + mQueueName + "] skip & discard pending app " + r);
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
+                    r.resultExtras, r.resultAbort, false);
             reschedule = true;
         }
         if (reschedule) {
@@ -330,14 +332,11 @@
     }
 
     public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
-            String resultData, Bundle resultExtras, boolean resultAbort,
-            boolean explicit) {
-        int state = r.state;
+            String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
+        final int state = r.state;
         r.state = BroadcastRecord.IDLE;
         if (state == BroadcastRecord.IDLE) {
-            if (explicit) {
-                Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
-            }
+            Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
         }
         r.receiver = null;
         r.intent.setComponent(null);
@@ -348,15 +347,35 @@
             r.curFilter.receiverList.curBroadcast = null;
         }
         r.curFilter = null;
-        r.curApp = null;
-        r.curComponent = null;
         r.curReceiver = null;
+        r.curApp = null;
         mPendingBroadcast = null;
 
         r.resultCode = resultCode;
         r.resultData = resultData;
         r.resultExtras = resultExtras;
-        r.resultAbort = resultAbort;
+        if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
+            r.resultAbort = resultAbort;
+        } else {
+            r.resultAbort = false;
+        }
+
+        if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
+                && r.queue.mOrderedBroadcasts.size() > 0
+                && r.queue.mOrderedBroadcasts.get(0) == r) {
+            // In this case, we are ready to process the next receiver for the current broadcast,
+            // but are on a queue that would like to wait for services to finish before moving
+            // on.  If there are background services currently starting, then we will go into a
+            // special state where we hold off on continuing this broadcast until they are done.
+            if (mService.mServices.hasBackgroundServices(r.userId)) {
+                Slog.i(ActivityManagerService.TAG, "Delay finish: "
+                        + r.curComponent.flattenToShortString());
+                r.state = BroadcastRecord.WAITING_SERVICES;
+                return false;
+            }
+        }
+
+        r.curComponent = null;
 
         // We will process the next receiver right now if this is finishing
         // an app receiver (which is always asynchronous) or after we have
@@ -365,6 +384,18 @@
                 || state == BroadcastRecord.CALL_DONE_RECEIVE;
     }
 
+    public void backgroundServicesFinishedLocked(int userId) {
+        if (mOrderedBroadcasts.size() > 0) {
+            BroadcastRecord br = mOrderedBroadcasts.get(0);
+            if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
+                Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast");
+                br.curComponent = null;
+                br.state = BroadcastRecord.IDLE;
+                processNextBroadcast(false);
+            }
+        }
+    }
+
     private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
             Intent intent, int resultCode, String data, Bundle extras,
             boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
@@ -821,7 +852,7 @@
                     // sent the broadcast.
                     logBroadcastReceiverDiscardLocked(r);
                     finishReceiverLocked(r, r.resultCode, r.resultData,
-                            r.resultExtras, r.resultAbort, true);
+                            r.resultExtras, r.resultAbort, false);
                     scheduleBroadcastsLocked();
                     // We need to reset the state if we failed to start the receiver.
                     r.state = BroadcastRecord.IDLE;
@@ -850,7 +881,7 @@
                         + r.intent + ": process is bad");
                 logBroadcastReceiverDiscardLocked(r);
                 finishReceiverLocked(r, r.resultCode, r.resultData,
-                        r.resultExtras, r.resultAbort, true);
+                        r.resultExtras, r.resultAbort, false);
                 scheduleBroadcastsLocked();
                 r.state = BroadcastRecord.IDLE;
                 return;
@@ -917,7 +948,21 @@
             }
         }
 
-        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+        BroadcastRecord br = mOrderedBroadcasts.get(0);
+        if (br.state == BroadcastRecord.WAITING_SERVICES) {
+            // In this case the broadcast had already finished, but we had decided to wait
+            // for started services to finish as well before going on.  So if we have actually
+            // waited long enough time timeout the broadcast, let's give up on the whole thing
+            // and just move on to the next.
+            Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null
+                    ? br.curComponent.flattenToShortString() : "(null)"));
+            br.curComponent = null;
+            br.state = BroadcastRecord.IDLE;
+            processNextBroadcast(false);
+            return;
+        }
+
+        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r. receiver
                 + ", started " + (now - r.receiverTime) + "ms ago");
         r.receiverTime = now;
         r.anrCount++;
@@ -957,7 +1002,7 @@
 
         // Move on to the next receiver.
         finishReceiverLocked(r, r.resultCode, r.resultData,
-                r.resultExtras, r.resultAbort, true);
+                r.resultExtras, r.resultAbort, false);
         scheduleBroadcastsLocked();
 
         if (anrMessage != null) {
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index db61e88..b2cfd7a 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -70,6 +70,7 @@
     static final int APP_RECEIVE = 1;
     static final int CALL_IN_RECEIVE = 2;
     static final int CALL_DONE_RECEIVE = 3;
+    static final int WAITING_SERVICES = 4;
 
     // The following are set when we are calling a receiver (one that
     // was found in our list of registered receivers).
@@ -153,6 +154,7 @@
                 case APP_RECEIVE:       stateStr=" (APP_RECEIVE)"; break;
                 case CALL_IN_RECEIVE:   stateStr=" (CALL_IN_RECEIVE)"; break;
                 case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
+                case WAITING_SERVICES:  stateStr=" (WAITING_SERVICES)"; break;
             }
             pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
         }
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 479665c..f0bba4f 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -60,6 +60,9 @@
     /** Takes on same set of values as ActivityRecord.mActivityType */
     private int mTaskType;
 
+    /** Launch the home activity when leaving this task. */
+    boolean mOnTopOfHome = false;
+
     TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
         taskId = _taskId;
         affinity = info.taskAffinity;
@@ -411,11 +414,12 @@
     }
 
     void dump(PrintWriter pw, String prefix) {
-        if (numActivities != 0 || rootWasReset || userId != 0) {
+        if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) {
             pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
                     pw.print(" rootWasReset="); pw.print(rootWasReset);
                     pw.print(" userId="); pw.print(userId);
-                    pw.print(" numFullscreen="); pw.println(numFullscreen);
+                    pw.print(" numFullscreen="); pw.print(numFullscreen);
+                    pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
         }
         if (affinity != null) {
             pw.print(prefix); pw.print("affinity="); pw.println(affinity);