Merge "Add support for WV plugin"
diff --git a/api/current.xml b/api/current.xml
index 8d8e96f..7360913 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1255,6 +1255,17 @@
  visibility="public"
 >
 </field>
+<field name="WRITE_MEDIA_STORAGE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.WRITE_MEDIA_STORAGE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="WRITE_SECURE_SETTINGS"
  type="java.lang.String"
  transient="false"
@@ -1894,7 +1905,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843549"
+ value="16843550"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1905,7 +1916,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843548"
+ value="16843549"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1916,7 +1927,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843550"
+ value="16843551"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4717,6 +4728,17 @@
  visibility="public"
 >
 </field>
+<field name="homeAsUpIndicator"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843548"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="horizontalDivider"
  type="int"
  transient="false"
@@ -9282,6 +9304,28 @@
  visibility="public"
 >
 </field>
+<field name="textEditNoPasteWindowLayout"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843553"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="textEditPasteWindowLayout"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843552"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="textFilterEnabled"
  type="int"
  transient="false"
@@ -19427,6 +19471,17 @@
  visibility="public"
 >
 </method>
+<method name="getNavigationItemCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getNavigationMode"
  return="int"
  abstract="true"
@@ -19438,6 +19493,17 @@
  visibility="public"
 >
 </method>
+<method name="getSelectedNavigationIndex"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getSelectedNavigationItem"
  return="int"
  abstract="true"
@@ -19445,7 +19511,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -19471,6 +19537,19 @@
  visibility="public"
 >
 </method>
+<method name="getTabAt"
+ return="android.app.ActionBar.Tab"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+</method>
 <method name="getTitle"
  return="java.lang.CharSequence"
  abstract="true"
@@ -19515,6 +19594,17 @@
  visibility="public"
 >
 </method>
+<method name="removeAllTabs"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="removeTab"
  return="void"
  abstract="true"
@@ -19574,12 +19664,40 @@
  synchronized="false"
  static="false"
  final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</method>
+<method name="setCustomView"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
 <parameter name="view" type="android.view.View">
 </parameter>
 </method>
+<method name="setCustomView"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="layoutParams" type="android.app.ActionBar.LayoutParams">
+</parameter>
+</method>
 <method name="setDisplayOptions"
  return="void"
  abstract="true"
@@ -19615,7 +19733,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="adapter" type="android.widget.SpinnerAdapter">
@@ -19630,7 +19748,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="adapter" type="android.widget.SpinnerAdapter">
@@ -19640,6 +19758,34 @@
 <parameter name="defaultSelectedPosition" type="int">
 </parameter>
 </method>
+<method name="setListNavigationCallbacks"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="adapter" type="android.widget.SpinnerAdapter">
+</parameter>
+<parameter name="callback" type="android.app.ActionBar.NavigationCallback">
+</parameter>
+</method>
+<method name="setNavigationMode"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
 <method name="setSelectedNavigationItem"
  return="void"
  abstract="true"
@@ -19660,7 +19806,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -19697,7 +19843,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -19742,6 +19888,39 @@
  type="int"
  transient="false"
  volatile="false"
+ value="4096"
+ static="true"
+ final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="DISPLAY_HOME_AS_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DISPLAY_SHOW_CUSTOM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DISPLAY_SHOW_HOME"
+ type="int"
+ transient="false"
+ volatile="false"
  value="2"
  static="true"
  final="true"
@@ -19749,6 +19928,17 @@
  visibility="public"
 >
 </field>
+<field name="DISPLAY_SHOW_TITLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="DISPLAY_USE_LOGO"
  type="int"
  transient="false"
@@ -19760,18 +19950,18 @@
  visibility="public"
 >
 </field>
-<field name="NAVIGATION_MODE_CUSTOM"
+<field name="NAVIGATION_MODE_DROPDOWN_LIST"
  type="int"
  transient="false"
  volatile="false"
- value="3"
+ value="1"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
-<field name="NAVIGATION_MODE_DROPDOWN_LIST"
+<field name="NAVIGATION_MODE_LIST"
  type="int"
  transient="false"
  volatile="false"
@@ -19805,6 +19995,93 @@
 >
 </field>
 </class>
+<class name="ActionBar.LayoutParams"
+ extends="android.view.ViewGroup.MarginLayoutParams"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="c" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="width" type="int">
+</parameter>
+<parameter name="height" type="int">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="width" type="int">
+</parameter>
+<parameter name="height" type="int">
+</parameter>
+<parameter name="gravity" type="int">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gravity" type="int">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="android.app.ActionBar.LayoutParams">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="android.view.ViewGroup.LayoutParams">
+</parameter>
+</constructor>
+<field name="gravity"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <interface name="ActionBar.NavigationCallback"
  abstract="true"
  static="true"
@@ -19911,7 +20188,7 @@
 >
 </method>
 <method name="setCustomView"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -19924,7 +20201,7 @@
 </parameter>
 </method>
 <method name="setIcon"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -19937,7 +20214,7 @@
 </parameter>
 </method>
 <method name="setTabListener"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -19950,7 +20227,7 @@
 </parameter>
 </method>
 <method name="setTag"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -19963,7 +20240,7 @@
 </parameter>
 </method>
 <method name="setText"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -245105,7 +245382,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 7df9295..66038d8 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -16,8 +16,16 @@
 
 package android.app;
 
+import android.app.ActionBar.Tab;
+import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
 import android.view.Window;
 import android.widget.SpinnerAdapter;
 
@@ -37,9 +45,16 @@
     public static final int NAVIGATION_MODE_STANDARD = 0;
     
     /**
-     * Dropdown list navigation mode. Instead of static title text this mode
-     * presents a dropdown menu for navigation within the activity.
+     * List navigation mode. Instead of static title text this mode
+     * presents a list menu for navigation within the activity.
+     * e.g. this might be presented to the user as a dropdown list.
      */
+    public static final int NAVIGATION_MODE_LIST = 1;
+
+    /**
+     * @deprecated use NAVIGATION_MODE_LIST
+     */
+    @Deprecated
     public static final int NAVIGATION_MODE_DROPDOWN_LIST = 1;
     
     /**
@@ -47,24 +62,77 @@
      * presents a series of tabs for navigation within the activity.
      */
     public static final int NAVIGATION_MODE_TABS = 2;
-    
-    /**
-     * Custom navigation mode. This navigation mode is set implicitly whenever
-     * a custom navigation view is set. See {@link #setCustomNavigationMode(View)}.
-     */
-    public static final int NAVIGATION_MODE_CUSTOM = 3;
 
     /**
      * Use logo instead of icon if available. This flag will cause appropriate
      * navigation modes to use a wider logo in place of the standard icon.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
      */
     public static final int DISPLAY_USE_LOGO = 0x1;
     
     /**
-     * Hide 'home' elements in this action bar, leaving more space for other
+     * Show 'home' elements in this action bar, leaving more space for other
      * navigation elements. This includes logo and icon.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
      */
-    public static final int DISPLAY_HIDE_HOME = 0x2;
+    public static final int DISPLAY_SHOW_HOME = 0x2;
+
+    /**
+     * @deprecated Display flags are now positive for consistency - 'show' instead of 'hide'.
+     *             Use DISPLAY_SHOW_HOME.
+     */
+    @Deprecated
+    public static final int DISPLAY_HIDE_HOME = 0x1000;
+
+    /**
+     * Display the 'home' element such that it appears as an 'up' affordance.
+     * e.g. show an arrow to the left indicating the action that will be taken.
+     *
+     * Set this flag if selecting the 'home' button in the action bar to return
+     * up by a single level in your UI rather than back to the top level or front page.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public static final int DISPLAY_HOME_AS_UP = 0x4;
+
+    /**
+     * Show the activity title and subtitle, if present.
+     *
+     * @see #setTitle(CharSequence)
+     * @see #setTitle(int)
+     * @see #setSubtitle(CharSequence)
+     * @see #setSubtitle(int)
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public static final int DISPLAY_SHOW_TITLE = 0x8;
+
+    /**
+     * Show the custom view if one has been set.
+     * @see #setCustomView(View)
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public static final int DISPLAY_SHOW_CUSTOM = 0x10;
+
+    /**
+     * Set the action bar into custom navigation mode, supplying a view
+     * for custom navigation.
+     *
+     * Custom navigation views appear between the application icon and
+     * any action buttons and may use any space available there. Common
+     * use cases for custom navigation views might include an auto-suggesting
+     * address bar for a browser or other navigation mechanisms that do not
+     * translate well to provided navigation modes.
+     *
+     * @param view Custom navigation view to place in the ActionBar.
+     */
+    public abstract void setCustomView(View view);
 
     /**
      * Set the action bar into custom navigation mode, supplying a view
@@ -77,7 +145,15 @@
      * translate well to provided navigation modes.
      * 
      * @param view Custom navigation view to place in the ActionBar.
+     * @param layoutParams How this custom view should layout in the bar.
      */
+    public abstract void setCustomView(View view, LayoutParams layoutParams);
+
+    /**
+     * @param view
+     * @deprecated Use {@link #setCustomView(View)} and {@link #setDisplayOptions(int)} instead.
+     */
+    @Deprecated
     public abstract void setCustomNavigationMode(View view);
     
     /**
@@ -89,11 +165,31 @@
      *                within the dropdown navigation menu.
      * @param callback A NavigationCallback that will receive events when the user
      *                 selects a navigation item.
+     * @deprecated See setListNavigationCallbacks.
      */
+    @Deprecated
     public abstract void setDropdownNavigationMode(SpinnerAdapter adapter,
             NavigationCallback callback);
 
     /**
+     * Set the adapter and navigation callback for list navigation mode.
+     *
+     * The supplied adapter will provide views for the expanded list as well as
+     * the currently selected item. (These may be displayed differently.)
+     *
+     * The supplied NavigationCallback will alert the application when the user
+     * changes the current list selection.
+     *
+     * @param adapter An adapter that will provide views both to display
+     *                the current navigation selection and populate views
+     *                within the dropdown navigation menu.
+     * @param callback A NavigationCallback that will receive events when the user
+     *                 selects a navigation item.
+     */
+    public abstract void setListNavigationCallbacks(SpinnerAdapter adapter,
+            NavigationCallback callback);
+
+    /**
      * Set the action bar into dropdown navigation mode and supply an adapter that will
      * provide views for navigation choices.
      *
@@ -104,23 +200,41 @@
      *                 selects a navigation item.
      * @param defaultSelectedPosition Position within the provided adapter that should be
      *                                selected from the outset.
+     * @deprecated See setListNavigationCallbacks and setSelectedNavigationItem.
      */
+    @Deprecated
     public abstract void setDropdownNavigationMode(SpinnerAdapter adapter,
             NavigationCallback callback, int defaultSelectedPosition);
 
     /**
-     * Set the selected navigation item in dropdown or tabbed navigation modes.
+     * Set the selected navigation item in list or tabbed navigation modes.
      *
      * @param position Position of the item to select.
      */
     public abstract void setSelectedNavigationItem(int position);
 
     /**
-     * Get the position of the selected navigation item in dropdown or tabbed navigation modes.
+     * Get the position of the selected navigation item in list or tabbed navigation modes.
+     *
+     * @return Position of the selected item.
+     * @deprecated Use {@link #getSelectedNavigationIndex()} instead.
+     */
+    @Deprecated
+    public abstract int getSelectedNavigationItem();
+
+    /**
+     * Get the position of the selected navigation item in list or tabbed navigation modes.
      *
      * @return Position of the selected item.
      */
-    public abstract int getSelectedNavigationItem();
+    public abstract int getSelectedNavigationIndex();
+
+    /**
+     * Get the number of navigation items present in the current navigation mode.
+     *
+     * @return Number of navigation items.
+     */
+    public abstract int getNavigationItemCount();
 
     /**
      * Set the action bar into standard navigation mode, using the currently set title
@@ -128,7 +242,9 @@
      *
      * Standard navigation mode is default. The title is automatically set to the name of
      * your Activity on startup if an action bar is present.
+     * @deprecated See setNavigationMode
      */
+    @Deprecated
     public abstract void setStandardNavigationMode();
 
     /**
@@ -181,10 +297,10 @@
      * Set selected display options. Only the options specified by mask will be changed.
      * To change all display option bits at once, see {@link #setDisplayOptions(int)}.
      * 
-     * <p>Example: setDisplayOptions(0, DISPLAY_HIDE_HOME) will disable the
-     * {@link #DISPLAY_HIDE_HOME} option.
-     * setDisplayOptions(DISPLAY_HIDE_HOME, DISPLAY_HIDE_HOME | DISPLAY_USE_LOGO)
-     * will enable {@link #DISPLAY_HIDE_HOME} and disable {@link #DISPLAY_USE_LOGO}.
+     * <p>Example: setDisplayOptions(0, DISPLAY_SHOW_HOME) will disable the
+     * {@link #DISPLAY_SHOW_HOME} option.
+     * setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_HIDE_HOME | DISPLAY_USE_LOGO)
+     * will enable {@link #DISPLAY_SHOW_HOME} and disable {@link #DISPLAY_USE_LOGO}.
      * 
      * @param options A combination of the bits defined by the DISPLAY_ constants
      *                defined in ActionBar.
@@ -226,9 +342,8 @@
      * Returns the current navigation mode. The result will be one of:
      * <ul>
      * <li>{@link #NAVIGATION_MODE_STANDARD}</li>
-     * <li>{@link #NAVIGATION_MODE_DROPDOWN_LIST}</li>
+     * <li>{@link #NAVIGATION_MODE_LIST}</li>
      * <li>{@link #NAVIGATION_MODE_TABS}</li>
-     * <li>{@link #NAVIGATION_MODE_CUSTOM}</li>
      * </ul>
      *
      * @return The current navigation mode.
@@ -241,7 +356,17 @@
      * @see #setCustomNavigationMode(View)
      */
     public abstract int getNavigationMode();
-    
+
+    /**
+     * Set the current navigation mode.
+     *
+     * @param mode The new mode to set.
+     * @see #NAVIGATION_MODE_STANDARD
+     * @see #NAVIGATION_MODE_LIST
+     * @see #NAVIGATION_MODE_TABS
+     */
+    public abstract void setNavigationMode(int mode);
+
     /**
      * @return The current set of display options. 
      */
@@ -254,6 +379,8 @@
      * @see #insertTab(Tab, int)
      * @see #removeTab(Tab)
      * @see #removeTabAt(int)
+     *
+     * @deprecated See {@link #setNavigationMode(int)}
      */
     public abstract void setTabNavigationMode();
 
@@ -285,22 +412,31 @@
     public abstract void addTab(Tab tab, int position);
 
     /**
-     * Remove a tab from the action bar.
+     * Remove a tab from the action bar. If the removed tab was selected it will be deselected
+     * and another tab will be selected if present.
      *
      * @param tab The tab to remove
      */
     public abstract void removeTab(Tab tab);
 
     /**
-     * Remove a tab from the action bar.
+     * Remove a tab from the action bar. If the removed tab was selected it will be deselected
+     * and another tab will be selected if present.
      *
      * @param position Position of the tab to remove
      */
     public abstract void removeTabAt(int position);
 
     /**
+     * Remove all tabs from the action bar and deselect the current tab.
+     */
+    public abstract void removeAllTabs();
+
+    /**
      * Select the specified tab. If it is not a child of this action bar it will be added.
      *
+     * <p>Note: If you want to select by index, use {@link #setSelectedNavigationItem(int)}.</p>
+     *
      * @param tab Tab to select
      */
     public abstract void selectTab(Tab tab);
@@ -314,6 +450,14 @@
     public abstract Tab getSelectedTab();
 
     /**
+     * Returns the tab at the specified index.
+     *
+     * @param index Index value in the range 0-get
+     * @return
+     */
+    public abstract Tab getTabAt(int index);
+
+    /**
      * Retrieve the current height of the ActionBar.
      *
      * @return The ActionBar's height
@@ -395,24 +539,27 @@
          * Set the icon displayed on this tab.
          *
          * @param icon The drawable to use as an icon
+         * @return The current instance for call chaining
          */
-        public abstract void setIcon(Drawable icon);
+        public abstract Tab setIcon(Drawable icon);
 
         /**
          * Set the text displayed on this tab. Text may be truncated if there is not
          * room to display the entire string.
          *
          * @param text The text to display
+         * @return The current instance for call chaining
          */
-        public abstract void setText(CharSequence text);
+        public abstract Tab setText(CharSequence text);
 
         /**
          * Set a custom view to be used for this tab. This overrides values set by
          * {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}.
          *
          * @param view Custom view to be used as a tab.
+         * @return The current instance for call chaining
          */
-        public abstract void setCustomView(View view);
+        public abstract Tab setCustomView(View view);
 
         /**
          * Retrieve a previously set custom view for this tab.
@@ -425,8 +572,9 @@
          * Give this Tab an arbitrary object to hold for later use.
          *
          * @param obj Object to store
+         * @return The current instance for call chaining
          */
-        public abstract void setTag(Object obj);
+        public abstract Tab setTag(Object obj);
 
         /**
          * @return This Tab's tag object.
@@ -438,8 +586,9 @@
          * All tabs must have a TabListener set before being added to the ActionBar.
          *
          * @param listener Listener to handle tab selection events
+         * @return The current instance for call chaining
          */
-        public abstract void setTabListener(TabListener listener);
+        public abstract Tab setTabListener(TabListener listener);
 
         /**
          * Select this tab. Only valid if the tab has been added to the action bar.
@@ -481,4 +630,65 @@
          */
         public void onTabReselected(Tab tab, FragmentTransaction ft);
     }
+
+    /**
+     * Per-child layout information associated with action bar custom views.
+     *
+     * @attr ref android.R.styleable#ActionBar_LayoutParams_layout_gravity
+     */
+    public static class LayoutParams extends MarginLayoutParams {
+        /**
+         * Gravity for the view associated with these LayoutParams.
+         *
+         * @see android.view.Gravity
+         */
+        @ViewDebug.ExportedProperty(category = "layout", mapping = {
+            @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
+            @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
+            @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
+            @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
+            @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
+            @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
+            @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
+            @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
+            @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
+            @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
+            @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
+            @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
+        })
+        public int gravity = -1;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+
+            TypedArray a = c.obtainStyledAttributes(attrs,
+                    com.android.internal.R.styleable.ActionBar_LayoutParams);
+            gravity = a.getInt(
+                    com.android.internal.R.styleable.ActionBar_LayoutParams_layout_gravity, -1);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+            this.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
+        }
+
+        public LayoutParams(int width, int height, int gravity) {
+            super(width, height);
+            this.gravity = gravity;
+        }
+
+        public LayoutParams(int gravity) {
+            this(WRAP_CONTENT, MATCH_PARENT, gravity);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+
+            this.gravity = source.gravity;
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7315f01..47efddb 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1781,6 +1781,17 @@
         performNewIntents(data.token, data.intents);
     }
 
+    private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
+
+    /**
+     * Return the Intent that's currently being handled by a
+     * BroadcastReceiver on this thread, or null if none.
+     * @hide
+     */
+    public static Intent getIntentBeingBroadcast() {
+        return sCurrentBroadcastIntent.get();
+    }
+
     private final void handleReceiver(ReceiverData data) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
@@ -1820,6 +1831,7 @@
                 + ", dir=" + packageInfo.getAppDir());
 
             ContextImpl context = (ContextImpl)app.getBaseContext();
+            sCurrentBroadcastIntent.set(data.intent);
             receiver.setPendingResult(data);
             receiver.onReceive(context.getReceiverRestrictedContext(),
                     data.intent);
@@ -1832,6 +1844,8 @@
                     "Unable to start receiver " + component
                     + ": " + e.toString(), e);
             }
+        } finally {
+            sCurrentBroadcastIntent.set(null);
         }
 
         if (receiver.getPendingResult() != null) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a29acf1..5ce4cd6 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -265,7 +265,11 @@
     public Resources.Theme getTheme() {
         if (mTheme == null) {
             if (mThemeResource == 0) {
-                mThemeResource = com.android.internal.R.style.Theme;
+                final Context outerContext = getOuterContext();
+                mThemeResource = (outerContext.getApplicationInfo().targetSdkVersion
+                        >= Build.VERSION_CODES.HONEYCOMB)
+                                ? com.android.internal.R.style.Theme_Holo
+                                : com.android.internal.R.style.Theme;
             }
             mTheme = mResources.newTheme();
             mTheme.applyStyle(mThemeResource, true);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c66b2de..556fb10 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -738,6 +738,27 @@
     }
 
     /**
+     * Get the current connection state of the local Bluetooth adapter.
+     * This can be used to check whether the local Bluetooth adapter is connected
+     * to any profile of any other remote Bluetooth Device.
+     *
+     * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
+     * intent to get the connection state of the adapter.
+     *
+     * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED},
+     * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
+     *
+     * @hide
+     */
+    public int getConnectionState() {
+        if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
+        try {
+            return mService.getAdapterConnectionState();
+        } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
+        return BluetoothAdapter.STATE_DISCONNECTED;
+    }
+
+    /**
      * Picks RFCOMM channels until none are left.
      * Avoids reserved channels.
      */
@@ -879,6 +900,7 @@
         return socket;
     }
 
+
     /**
      * Construct an unencrypted, unauthenticated, RFCOMM server socket.
      * Call #accept to retrieve connections to this socket.
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 1eb269d..aefb3f2 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -47,6 +47,8 @@
     boolean isDiscovering();
     byte[] readOutOfBandData();
 
+    int getAdapterConnectionState();
+
     boolean createBond(in String address);
     boolean createBondOutOfBand(in String address, in byte[] hash, in byte[] randomizer);
     boolean cancelBondProcess(in String address);
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 73d9458..e279f64 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -149,7 +149,7 @@
     /*package*/ final CharSequence getResourceText(int ident) {
         synchronized (this) {
             TypedValue tmpValue = mValue;
-            int block = loadResourceValue(ident, tmpValue, true);
+            int block = loadResourceValue(ident, (short) 0, tmpValue, true);
             if (block >= 0) {
                 if (tmpValue.type == TypedValue.TYPE_STRING) {
                     return mStringBlocks[block].get(tmpValue.data);
@@ -190,10 +190,11 @@
 
 
     /*package*/ final boolean getResourceValue(int ident,
+                                               int density,
                                                TypedValue outValue,
                                                boolean resolveRefs)
     {
-        int block = loadResourceValue(ident, outValue, resolveRefs);
+        int block = loadResourceValue(ident, (short) density, outValue, resolveRefs);
         if (block >= 0) {
             if (outValue.type != TypedValue.TYPE_STRING) {
                 return true;
@@ -681,8 +682,8 @@
 
     /** Returns true if the resource was found, filling in mRetStringBlock and
      *  mRetData. */
-    private native final int loadResourceValue(int ident, TypedValue outValue,
-                                               boolean resolve);
+    private native final int loadResourceValue(int ident, short density, TypedValue outValue,
+            boolean resolve);
     /** Returns true if the resource was found, filling in mRetStringBlock and
      *  mRetData. */
     private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 9b23c1e..e6fd039 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -628,6 +628,50 @@
     }
 
     /**
+     * Return a drawable object associated with a particular resource ID for the
+     * given screen density in DPI. This will set the drawable's density to be
+     * the device's density multiplied by the ratio of actual drawable density
+     * to requested density. This allows the drawable to be scaled up to the
+     * correct size if needed. Various types of objects will be returned
+     * depending on the underlying resource -- for example, a solid color, PNG
+     * image, scalable image, etc. The Drawable API hides these implementation
+     * details.
+     * 
+     * @param id The desired resource identifier, as generated by the aapt tool.
+     *            This integer encodes the package, type, and resource entry.
+     *            The value 0 is an invalid identifier.
+     * @param density the desired screen density indicated by the resource as
+     *            found in {@link DisplayMetrics}.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *             not exist.
+     * @return Drawable An object that can be used to draw this resource.
+     * @hide
+     */
+    public Drawable getDrawableForDensity(int id, int density) throws NotFoundException {
+        synchronized (mTmpValue) {
+            TypedValue value = mTmpValue;
+            getValueForDensity(id, density, value, true);
+
+            /*
+             * Pretend the requested density is actually the display density. If
+             * the drawable returned is not the requested density, then force it
+             * to be scaled later by dividing its density by the ratio of
+             * requested density to actual device density. Drawables that have
+             * undefined density or no density don't need to be handled here.
+             */
+            if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
+                if (value.density == density) {
+                    value.density = DisplayMetrics.DENSITY_DEVICE;
+                } else {
+                    value.density = (value.density * DisplayMetrics.DENSITY_DEVICE) / density;
+                }
+            }
+
+            return loadDrawable(value, id);
+        }
+    }
+
+    /**
      * Return a movie object associated with the particular resource ID.
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
@@ -930,7 +974,7 @@
      */
     public void getValue(int id, TypedValue outValue, boolean resolveRefs)
             throws NotFoundException {
-        boolean found = mAssets.getResourceValue(id, outValue, resolveRefs);
+        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
         if (found) {
             return;
         }
@@ -939,6 +983,29 @@
     }
 
     /**
+     * Get the raw value associated with a resource with associated density.
+     * 
+     * @param id resource identifier
+     * @param density density in DPI
+     * @param resolveRefs If true, a resource that is a reference to another
+     *            resource will be followed so that you receive the actual final
+     *            resource data. If false, the TypedValue will be filled in with
+     *            the reference itself.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *             not exist.
+     * @see #getValue(String, TypedValue, boolean)
+     * @hide
+     */
+    public void getValueForDensity(int id, int density, TypedValue outValue, boolean resolveRefs)
+            throws NotFoundException {
+        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
+        if (found) {
+            return;
+        }
+        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+    }
+
+    /**
      * Return the raw data associated with a particular resource ID.
      * See getIdentifier() for information on how names are mapped to resource
      * IDs, and getString(int) for information on how string resources are
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6089013..c0743cfe 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1296,7 +1296,7 @@
             mInShowWindow = false;
         }
     }
-    
+
     void showWindowInner(boolean showInput) {
         boolean doShowInput = false;
         boolean wasVisible = mWindowVisible;
@@ -1311,7 +1311,7 @@
         } else {
             showInput = true;
         }
-        
+
         if (DEBUG) Log.v(TAG, "showWindow: updating UI");
         initialize();
         updateFullscreenMode();
@@ -1343,14 +1343,15 @@
         if (doShowInput) {
             startExtractingText(false);
         }
-        
+
         if (!wasVisible) {
             if (DEBUG) Log.v(TAG, "showWindow: showing!");
+            mImm.setIMEButtonVisible(mToken, true);
             onWindowShown();
             mWindow.show();
         }
     }
-    
+
     public void hideWindow() {
         if (mInputViewStarted) {
             if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
@@ -1364,11 +1365,12 @@
         if (mWindowVisible) {
             mWindow.hide();
             mWindowVisible = false;
+            mImm.setIMEButtonVisible(mToken, false);
             onWindowHidden();
             mWindowWasVisible = false;
         }
     }
-    
+
     /**
      * Called when the input method window has been shown to the user, after
      * previously not being visible.  This is done after all of the UI setup
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 5a6369c..34d3b85 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -17,7 +17,9 @@
 
 import android.animation.ValueAnimator;
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
 import android.app.ApplicationErrorReport;
+import android.content.Intent;
 import android.util.Log;
 import android.util.Printer;
 
@@ -1205,6 +1207,12 @@
         public long violationUptimeMillis;
 
         /**
+         * The action of the Intent being broadcast to somebody's onReceive
+         * on this thread right now, or null.
+         */
+        public String broadcastIntentAction;
+
+        /**
          * Create an uninitialized instance of ViolationInfo
          */
         public ViolationInfo() {
@@ -1220,6 +1228,10 @@
             violationUptimeMillis = SystemClock.uptimeMillis();
             this.policy = policy;
             this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount();
+            Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast();
+            if (broadcastIntent != null) {
+                broadcastIntentAction = broadcastIntent.getAction();
+            }
         }
 
         /**
@@ -1247,6 +1259,7 @@
             violationNumThisLoop = in.readInt();
             numAnimationsRunning = in.readInt();
             violationUptimeMillis = in.readLong();
+            broadcastIntentAction = in.readString();
         }
 
         /**
@@ -1259,6 +1272,7 @@
             dest.writeInt(violationNumThisLoop);
             dest.writeInt(numAnimationsRunning);
             dest.writeLong(violationUptimeMillis);
+            dest.writeString(broadcastIntentAction);
         }
 
 
@@ -1278,6 +1292,9 @@
                 pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning);
             }
             pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis);
+            if (broadcastIntentAction != null) {
+                pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction);
+            }
         }
 
     }
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 65047c0..7289012 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -167,6 +167,8 @@
     private static String mDockAddress;
     private String mDockPin;
 
+    private int mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
+
     private static class RemoteService {
         public String address;
         public ParcelUuid uuid;
@@ -415,6 +417,7 @@
         mProfilesConnected = 0;
         mProfilesConnecting = 0;
         mProfilesDisconnecting = 0;
+        mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
 
         if (saveSetting) {
             persistBluetoothOnSetting(false);
@@ -2737,11 +2740,18 @@
         }
     }
 
+    public int getAdapterConnectionState() {
+        return mAdapterConnectionState;
+    }
+
     public synchronized void sendConnectionStateChange(BluetoothDevice device, int state,
                                                         int prevState) {
         if (updateCountersAndCheckForConnectionStateChange(device, state, prevState)) {
-            state = getAdapterConnectionState(state);
-            prevState = getAdapterConnectionState(prevState);
+            state = translateToAdapterConnectionState(state);
+            prevState = translateToAdapterConnectionState(prevState);
+
+            mAdapterConnectionState = state;
+
             Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
             intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
             intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, state);
@@ -2751,7 +2761,7 @@
         }
     }
 
-    private int getAdapterConnectionState(int state) {
+    private int translateToAdapterConnectionState(int state) {
         switch (state) {
             case BluetoothProfile.STATE_CONNECTING:
                 return BluetoothAdapter.STATE_CONNECTING;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7cb6291..033ee7c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -519,6 +519,15 @@
     }
 
     /** @hide */
+    public void setIMEButtonVisible(IBinder imeToken, boolean visible) {
+        try {
+            mService.setIMEButtonVisible(imeToken, visible);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** @hide */
     public void setFullscreenMode(boolean fullScreen) {
         mFullscreenMode = fullScreen;
     }
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 3d69249..4d582ef 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1483,6 +1483,10 @@
         return mAcceptLanguage;
     }
 
+    /* package */ boolean isNarrowColumnLayout() {
+        return getLayoutAlgorithm() == LayoutAlgorithm.NARROW_COLUMNS;
+    }
+
     /**
      * Tell the WebView whether it needs to set a node to have focus when
      * {@link WebView#requestFocus(int, android.graphics.Rect)} is called.
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 86dfd1f..dd812d4 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -348,7 +348,8 @@
         mZoomCenterY = mWebView.getViewHeight() * .5f;
         mAnchorX = mWebView.viewToContentX((int) mZoomCenterX + mWebView.getScrollX());
         mAnchorY = mWebView.viewToContentY((int) mZoomCenterY + mWebView.getScrollY());
-        return startZoomAnimation(mActualScale * zoomMultiplier, true);
+        return startZoomAnimation(mActualScale * zoomMultiplier, 
+            !mWebView.getSettings().getUseFixedViewport());
     }
 
     /**
@@ -460,7 +461,7 @@
             mInZoomOverview = !exceedsMinScaleIncrement(scale, getZoomOverviewScale());
         }
 
-        if (reflowText) {
+        if (reflowText && !mWebView.getSettings().getUseFixedViewport()) {
             mTextWrapScale = scale;
         }
 
@@ -519,7 +520,7 @@
      *
      * (2) HTML/OTHER: If the taps occur outside a plugin then the following
      * heuristic is used.
-     *   A. If the current scale is not the same as the text wrap scale and the
+     *   A. If the current text wrap scale differs from newly calculated and the
      *      layout algorithm specifies the use of NARROW_COLUMNS, then fit to
      *      column by reflowing the text.
      *   B. If the page is not in overview mode then change to overview mode.
@@ -553,8 +554,15 @@
             return;
         }
 
-        if (settings.getLayoutAlgorithm() == WebSettings.LayoutAlgorithm.NARROW_COLUMNS
-                && willScaleTriggerZoom(mTextWrapScale)) {
+        final float newTextWrapScale;
+        if (settings.getUseFixedViewport()) {
+            newTextWrapScale = Math.max(mActualScale, getReadingLevelScale());
+        } else {
+            newTextWrapScale = mActualScale;
+        }
+        if (settings.isNarrowColumnLayout()
+                && exceedsMinScaleIncrement(mTextWrapScale, newTextWrapScale)) {
+            mTextWrapScale = newTextWrapScale;
             refreshZoomScale(true);
         } else if (!mInZoomOverview) {
             zoomToOverview();
@@ -584,7 +592,8 @@
         if (scrollY < mWebView.getTitleHeight()) {
             mWebView.updateScrollCoordinates(mWebView.getScrollX(), 0);
         }
-        startZoomAnimation(getZoomOverviewScale(), true);
+        startZoomAnimation(getZoomOverviewScale(), 
+            !mWebView.getSettings().getUseFixedViewport());
     }
 
     private void zoomToReadingLevel() {
@@ -603,7 +612,8 @@
                 mZoomCenterX = 0;
             }
         }
-        startZoomAnimation(readingScale, true);
+        startZoomAnimation(readingScale,
+            !mWebView.getSettings().getUseFixedViewport());
     }
 
     public void updateMultiTouchSupport(Context context) {
@@ -683,11 +693,12 @@
                 mAnchorX = mWebView.viewToContentX((int) mZoomCenterX + mWebView.getScrollX());
                 mAnchorY = mWebView.viewToContentY((int) mZoomCenterY + mWebView.getScrollY());
                 // don't reflow when zoom in; when zoom out, do reflow if the
-                // new scale is almost minimum scale;
+                // new scale is almost minimum scale.
                 boolean reflowNow = !canZoomOut() || (mActualScale <= 0.8 * mTextWrapScale);
                 // force zoom after mPreviewZoomOnly is set to false so that the
                 // new view size will be passed to the WebKit
-                refreshZoomScale(reflowNow);
+                refreshZoomScale(reflowNow &&
+                    !mWebView.getSettings().getUseFixedViewport());
                 // call invalidate() to draw without zoom filter
                 mWebView.invalidate();
             }
@@ -730,7 +741,8 @@
         // cause its child View to reposition itself through ViewManager's
         // scaleAll(), we need to post a Runnable to ensure requestLayout().
         // Additionally, only update the text wrap scale if the width changed.
-        mWebView.post(new PostScale(w != ow));
+        mWebView.post(new PostScale(w != ow &&
+            !mWebView.getSettings().getUseFixedViewport()));
     }
 
     private class PostScale implements Runnable {
@@ -808,7 +820,8 @@
         if (!mWebView.drawHistory() && (mInitialZoomOverview || (mInZoomOverview
                 && Math.abs((viewWidth * mInvActualScale) - mZoomOverviewWidth) > 1))) {
             mInitialZoomOverview = false;
-            setZoomScale(zoomOverviewScale, !willScaleTriggerZoom(mTextWrapScale));
+            setZoomScale(zoomOverviewScale, !willScaleTriggerZoom(mTextWrapScale) &&
+                !mWebView.getSettings().getUseFixedViewport());
         }
     }
 
@@ -855,6 +868,11 @@
                     scale = Math.max(viewState.mTextWrapScale, scale);
                     mInitialZoomOverview = !exceedsMinScaleIncrement(scale, getZoomOverviewScale());
                 }
+                if (settings.isNarrowColumnLayout() && settings.getUseFixedViewport()) {
+                    // When first layout, reflow using the reading level scale to avoid
+                    // reflow when double tapped.
+                    mTextWrapScale = getReadingLevelScale();
+                }
                 reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
             }
             setZoomScale(scale, reflowText);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 257dbf0..ef15f6f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -300,6 +300,8 @@
     int mTextSelectHandleLeftRes;
     int mTextSelectHandleRightRes;
     int mTextSelectHandleRes;
+    int mTextEditPasteWindowLayout;
+    int mTextEditNoPasteWindowLayout;
 
     Drawable mSelectHandleLeft;
     Drawable mSelectHandleRight;
@@ -737,7 +739,15 @@
             case com.android.internal.R.styleable.TextView_textSelectHandle:
                 mTextSelectHandleRes = a.getResourceId(attr, 0);
                 break;
-                
+
+            case com.android.internal.R.styleable.TextView_textEditPasteWindowLayout:
+                mTextEditPasteWindowLayout = a.getResourceId(attr, 0);
+                break;
+
+            case com.android.internal.R.styleable.TextView_textEditNoPasteWindowLayout:
+                mTextEditNoPasteWindowLayout = a.getResourceId(attr, 0);
+                break;
+
             case com.android.internal.R.styleable.TextView_textLineHeight:
                 int lineHeight = a.getDimensionPixelSize(attr, 0);
                 if (lineHeight != 0) {
@@ -7736,6 +7746,34 @@
         }
     }
 
+    /**
+     * Paste clipboard content between min and max positions.
+     *
+     * @param clipboard getSystemService(Context.CLIPBOARD_SERVICE)
+     */
+    private void paste(ClipboardManager clipboard, int min, int max) {
+        ClipData clip = clipboard.getPrimaryClip();
+        if (clip != null) {
+            boolean didfirst = false;
+            for (int i=0; i<clip.getItemCount(); i++) {
+                CharSequence paste = clip.getItem(i).coerceToText(getContext());
+                if (paste != null) {
+                    if (!didfirst) {
+                        long minMax = prepareSpacesAroundPaste(min, max, paste);
+                        min = extractRangeStartFromLong(minMax);
+                        max = extractRangeEndFromLong(minMax);
+                        Selection.setSelection((Spannable) mText, max);
+                        ((Editable) mText).replace(min, max, paste);
+                    } else {
+                        ((Editable) mText).insert(getSelectionEnd(), "\n");
+                        ((Editable) mText).insert(getSelectionEnd(), paste);
+                    }
+                }
+            }
+            stopSelectionActionMode();
+        }
+    }
+
     private class SelectionActionModeCallback implements ActionMode.Callback {
 
         @Override
@@ -7766,7 +7804,6 @@
                 }
 
                 menu.add(0, ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
-                    setIcon(com.android.internal.R.drawable.ic_menu_select_all).
                     setAlphabeticShortcut('a').
                     setShowAsAction(
                             MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
@@ -7844,26 +7881,7 @@
 
             switch (item.getItemId()) {
                 case ID_PASTE:
-                    ClipData clip = clipboard.getPrimaryClip();
-                    if (clip != null) {
-                        boolean didfirst = false;
-                        for (int i=0; i<clip.getItemCount(); i++) {
-                            CharSequence paste = clip.getItem(i).coerceToText(getContext());
-                            if (paste != null) {
-                                if (!didfirst) {
-                                    long minMax = prepareSpacesAroundPaste(min, max, paste);
-                                    min = extractRangeStartFromLong(minMax);
-                                    max = extractRangeEndFromLong(minMax);
-                                    Selection.setSelection((Spannable) mText, max);
-                                    ((Editable) mText).replace(min, max, paste);
-                                } else {
-                                    ((Editable) mText).insert(getSelectionEnd(), "\n");
-                                    ((Editable) mText).insert(getSelectionEnd(), paste);
-                                }
-                            }
-                        }
-                        stopSelectionActionMode();
-                    }
+                    paste(clipboard, min, max);
                     return true;
 
                 case ID_CUT:
@@ -7931,6 +7949,100 @@
         public boolean onTouchEvent(MotionEvent event);
     }
 
+    private class PastePopupMenu implements OnClickListener {
+        private PopupWindow mContainer;
+        private int mPositionX;
+        private int mPositionY;
+        private View mPasteView, mNoPasteView;
+
+        public PastePopupMenu() {
+            mContainer = new PopupWindow(TextView.this.mContext, null,
+                    com.android.internal.R.attr.textSelectHandleWindowStyle);
+            mContainer.setSplitTouchEnabled(true);
+            mContainer.setClippingEnabled(false);
+            mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+
+            mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
+            mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+
+        private void updateContent() {
+            View view = canPaste() ? mPasteView : mNoPasteView;
+
+            if (view == null) {
+                final int layout = canPaste() ? mTextEditPasteWindowLayout :
+                    mTextEditNoPasteWindowLayout;
+                LayoutInflater inflater = (LayoutInflater)TextView.this.mContext.
+                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+                if (inflater != null) {
+                    view = inflater.inflate(layout, null);
+                }
+
+                if (view == null) {
+                    throw new IllegalArgumentException("Unable to inflate TextEdit paste window");
+                }
+
+                final int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+                view.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT));
+                view.measure(size, size);
+
+                view.setOnClickListener(this);
+
+                if (canPaste()) mPasteView = view;
+                else mNoPasteView = view;
+            }
+
+            mContainer.setContentView(view);
+        }
+
+        public void show() {
+            updateContent();
+            final int[] coords = mTempCoords;
+            TextView.this.getLocationInWindow(coords);
+            positionAtCursor();
+            coords[0] += mPositionX;
+            coords[1] += mPositionY;
+            mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
+        }
+
+        public void hide() {
+            mContainer.dismiss();
+        }
+
+        public boolean isShowing() {
+            return mContainer.isShowing();
+        }
+
+        @Override
+        public void onClick(View v) {
+            ClipboardManager clipboard = 
+                (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+            paste(clipboard, getSelectionStart(), getSelectionEnd());
+        }
+
+        void positionAtCursor() {
+            final int offset = TextView.this.getSelectionStart();
+            View contentView = mContainer.getContentView();
+            final int width = contentView.getMeasuredWidth();
+            final int height = contentView.getMeasuredHeight();
+            final int line = mLayout.getLineForOffset(offset);
+            final int lineTop = mLayout.getLineTop(line);
+
+            final Rect bounds = sCursorControllerTempRect;
+            bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0f);
+            bounds.top = lineTop - height;
+
+            bounds.right = bounds.left + width;
+            bounds.bottom = bounds.top + height;
+
+            convertFromViewportToContentCoordinates(bounds);
+
+            mPositionX = bounds.left;
+            mPositionY = bounds.top;
+        }
+    }
+
     private class HandleView extends View {
         private boolean mPositionOnTop = false;
         private Drawable mDrawable;
@@ -7947,6 +8059,9 @@
         private float mTouchOffsetY;
         private int mLastParentX;
         private int mLastParentY;
+        private int mContainerPositionX, mContainerPositionY;
+        private long mTouchTimer;
+        private PastePopupMenu mPastePopupWindow;
 
         public static final int LEFT = 0;
         public static final int CENTER = 1;
@@ -7998,6 +8113,7 @@
                 mDrawable = mSelectHandleCenter;
                 handleWidth = mDrawable.getIntrinsicWidth();
                 mHotspotX = handleWidth / 2;
+                mPastePopupWindow = new PastePopupMenu();
                 break;
             }
             }
@@ -8011,7 +8127,7 @@
         }
 
         @Override
-        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
             setMeasuredDimension(mDrawable.getIntrinsicWidth(),
                     mDrawable.getIntrinsicHeight());
         }
@@ -8024,14 +8140,22 @@
             mContainer.setContentView(this);
             final int[] coords = mTempCoords;
             TextView.this.getLocationInWindow(coords);
-            coords[0] += mPositionX;
-            coords[1] += mPositionY;
-            mContainer.showAtLocation(TextView.this, 0, coords[0], coords[1]);
+            mContainerPositionX = coords[0] + mPositionX;
+            mContainerPositionY = coords[1] + mPositionY;
+            mContainer.showAtLocation(TextView.this, 0, mContainerPositionX, mContainerPositionY);
+
+            // Hide paste view when handle is moved.
+            if (mPastePopupWindow != null) {
+                mPastePopupWindow.hide();
+            }
         }
 
         public void hide() {
             mIsDragging = false;
             mContainer.dismiss();
+            if (mPastePopupWindow != null) {
+                mPastePopupWindow.hide();
+            }
         }
 
         public boolean isShowing() {
@@ -8086,8 +8210,22 @@
                 if (mContainer.isShowing()){
                     coords = mTempCoords;
                     TextView.this.getLocationInWindow(coords);
-                    mContainer.update(coords[0] + mPositionX, coords[1] + mPositionY,
-                            mRight - mLeft, mBottom - mTop);
+                    final int containerPositionX = coords[0] + mPositionX;
+                    final int containerPositionY = coords[1] + mPositionY;
+
+                    if (containerPositionX != mContainerPositionX || 
+                        containerPositionY != mContainerPositionY) {
+                        mContainerPositionX = containerPositionX;
+                        mContainerPositionY = containerPositionY;
+
+                        mContainer.update(mContainerPositionX, mContainerPositionY,
+                                mRight - mLeft, mBottom - mTop);
+
+                        // Hide paste popup window as soon as a scroll occurs.
+                        if (mPastePopupWindow != null) {
+                            mPastePopupWindow.hide();
+                        }
+                    }
                 } else {
                     show();
                 }
@@ -8103,6 +8241,10 @@
                         mLastParentX = coords[0];
                         mLastParentY = coords[1];
                     }
+                    // Hide paste popup window as soon as the handle is dragged.
+                    if (mPastePopupWindow != null) {
+                        mPastePopupWindow.hide();
+                    }
                 }
             } else {
                 hide();
@@ -8110,7 +8252,7 @@
         }
 
         @Override
-        public void onDraw(Canvas c) {
+        protected void onDraw(Canvas c) {
             mDrawable.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
             if (mPositionOnTop) {
                 c.save();
@@ -8135,6 +8277,15 @@
                 mLastParentX = coords[0];
                 mLastParentY = coords[1];
                 mIsDragging = true;
+                if (mPastePopupWindow != null) {
+                    mTouchTimer = SystemClock.uptimeMillis();
+                    if (mPastePopupWindow.isShowing()) {
+                        // Tapping on the handle again dismisses the displayed paste view,
+                        mPastePopupWindow.hide();
+                        // and makes sure the action up does not display the paste view.
+                        mTouchTimer = 0;
+                    }
+                }
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
@@ -8148,6 +8299,24 @@
                 break;
             }
             case MotionEvent.ACTION_UP:
+                if (mPastePopupWindow != null) {
+                    long delay = SystemClock.uptimeMillis() - mTouchTimer;
+                    if (delay < ViewConfiguration.getTapTimeout()) {
+                        final float touchOffsetX = ev.getRawX() - mPositionX;
+                        final float touchOffsetY = ev.getRawY() - mPositionY;
+                        final float dx = touchOffsetX - mTouchToWindowOffsetX;
+                        final float dy = touchOffsetY - mTouchToWindowOffsetY;
+                        final float distanceSquared = dx * dx + dy * dy;
+                        final ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
+                        final int doubleTapSlop = viewConfiguration.getScaledDoubleTapSlop();
+                        final int slopSquared = doubleTapSlop * doubleTapSlop;
+                        if (distanceSquared < slopSquared) {
+                            mPastePopupWindow.show();
+                        }
+                    }
+                }
+                mIsDragging = false;
+                break;
             case MotionEvent.ACTION_CANCEL:
                 mIsDragging = false;
             }
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 531d9fe..3d9cde4 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -62,9 +62,6 @@
     private static final int STATE_PLAYING            = 3;
     private static final int STATE_PAUSED             = 4;
     private static final int STATE_PLAYBACK_COMPLETED = 5;
-    private static final int STATE_SUSPEND            = 6;
-    private static final int STATE_RESUME             = 7;
-    private static final int STATE_SUSPEND_UNSUPPORTED = 8;
 
     // mCurrentState is a VideoView object's current state.
     // mTargetState is the state that a method caller intends to reach.
@@ -90,7 +87,6 @@
     private boolean     mCanPause;
     private boolean     mCanSeekBack;
     private boolean     mCanSeekForward;
-    private int         mStateWhenSuspended;  //state before calling suspend()
 
     public VideoView(Context context) {
         super(context);
@@ -470,14 +466,7 @@
         public void surfaceCreated(SurfaceHolder holder)
         {
             mSurfaceHolder = holder;
-            //resume() was called before surfaceCreated()
-            if (mMediaPlayer != null && mCurrentState == STATE_SUSPEND
-                   && mTargetState == STATE_RESUME) {
-                mMediaPlayer.setDisplay(mSurfaceHolder);
-                resume();
-            } else {
-                openVideo();
-            }
+            openVideo();
         }
 
         public void surfaceDestroyed(SurfaceHolder holder)
@@ -485,9 +474,7 @@
             // after we return from this we can't use the surface any more
             mSurfaceHolder = null;
             if (mMediaController != null) mMediaController.hide();
-            if (mCurrentState != STATE_SUSPEND) {
-                release(true);
-            }
+            release(true);
         }
     };
 
@@ -581,39 +568,14 @@
     }
 
     public void suspend() {
-        if (isInPlaybackState()) {
-            if (mMediaPlayer.suspend()) {
-                mStateWhenSuspended = mCurrentState;
-                mCurrentState = STATE_SUSPEND;
-                mTargetState = STATE_SUSPEND;
-            } else {
-                release(false);
-                mCurrentState = STATE_SUSPEND_UNSUPPORTED;
-                Log.w(TAG, "Unable to suspend video. Release MediaPlayer.");
-            }
-        }
+        release(false);
     }
 
     public void resume() {
-        if (mSurfaceHolder == null && mCurrentState == STATE_SUSPEND){
-            mTargetState = STATE_RESUME;
-            return;
-        }
-        if (mMediaPlayer != null && mCurrentState == STATE_SUSPEND) {
-            if (mMediaPlayer.resume()) {
-                mCurrentState = mStateWhenSuspended;
-                mTargetState = mStateWhenSuspended;
-            } else {
-                Log.w(TAG, "Unable to resume video");
-            }
-            return;
-        }
-        if (mCurrentState == STATE_SUSPEND_UNSUPPORTED) {
-            openVideo();
-        }
+        openVideo();
     }
 
-   // cache duration as mDuration for faster access
+    // cache duration as mDuration for faster access
     public int getDuration() {
         if (isInPlaybackState()) {
             if (mDuration > 0) {
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 3015363..f4a041c 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -52,9 +52,6 @@
 public class ActionBarImpl extends ActionBar {
     private static final int NORMAL_VIEW = 0;
     private static final int CONTEXT_VIEW = 1;
-    
-    private static final int TAB_SWITCH_SHOW_HIDE = 0;
-    private static final int TAB_SWITCH_ADD_REMOVE = 1;
 
     private Context mContext;
     private Activity mActivity;
@@ -67,9 +64,7 @@
 
     private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
 
-    private int mTabContainerViewId = android.R.id.content;
     private TabImpl mSelectedTab;
-    private int mTabSwitchMode = TAB_SWITCH_ADD_REMOVE;
     
     private ActionMode mActionMode;
     
@@ -133,7 +128,9 @@
 
     public void setCustomNavigationMode(View view) {
         cleanupTabs();
-        mActionView.setCustomNavigationView(view);
+        setCustomView(view);
+        setDisplayOptions(DISPLAY_SHOW_CUSTOM, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
+        mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
         mActionView.setCallback(null);
     }
 
@@ -144,16 +141,17 @@
     public void setDropdownNavigationMode(SpinnerAdapter adapter, NavigationCallback callback,
             int defaultSelectedPosition) {
         cleanupTabs();
-        mActionView.setNavigationMode(NAVIGATION_MODE_DROPDOWN_LIST);
-        mActionView.setDropdownAdapter(adapter);
+        setDisplayOptions(0, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
+        mActionView.setNavigationMode(NAVIGATION_MODE_LIST);
+        setListNavigationCallbacks(adapter, callback);
         if (defaultSelectedPosition >= 0) {
             mActionView.setDropdownSelectedPosition(defaultSelectedPosition);
         }
-        mActionView.setCallback(callback);
     }
 
     public void setStandardNavigationMode() {
         cleanupTabs();
+        setDisplayOptions(DISPLAY_SHOW_TITLE, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM);
         mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
         mActionView.setCallback(null);
     }
@@ -163,24 +161,21 @@
         case NAVIGATION_MODE_TABS:
             selectTab(mTabs.get(position));
             break;
-        case NAVIGATION_MODE_DROPDOWN_LIST:
+        case NAVIGATION_MODE_LIST:
             mActionView.setDropdownSelectedPosition(position);
             break;
         default:
             throw new IllegalStateException(
-                    "setSelectedNavigationItem not valid for current navigation mode");
+                    "setSelectedNavigationIndex not valid for current navigation mode");
         }
     }
 
     public int getSelectedNavigationItem() {
-        switch (mActionView.getNavigationMode()) {
-        case NAVIGATION_MODE_TABS:
-            return mSelectedTab.getPosition();
-        case NAVIGATION_MODE_DROPDOWN_LIST:
-            return mActionView.getDropdownSelectedPosition();
-        default:
-            return -1;
-        }
+        return getSelectedNavigationIndex();
+    }
+
+    public void removeAllTabs() {
+        cleanupTabs();
     }
 
     private void cleanupTabs() {
@@ -321,6 +316,7 @@
             throw new IllegalStateException(
                     "Tab navigation mode cannot be used outside of an Activity");
         }
+        setDisplayOptions(0, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM);
         mActionView.setNavigationMode(NAVIGATION_MODE_TABS);
     }
 
@@ -510,8 +506,9 @@
         }
 
         @Override
-        public void setTag(Object tag) {
+        public Tab setTag(Object tag) {
             mTag = tag;
+            return this;
         }
 
         public ActionBar.TabListener getCallback() {
@@ -519,8 +516,9 @@
         }
 
         @Override
-        public void setTabListener(ActionBar.TabListener callback) {
+        public Tab setTabListener(ActionBar.TabListener callback) {
             mCallback = callback;
+            return this;
         }
 
         @Override
@@ -529,8 +527,9 @@
         }
 
         @Override
-        public void setCustomView(View view) {
+        public Tab setCustomView(View view) {
             mCustomView = view;
+            return this;
         }
 
         @Override
@@ -553,13 +552,15 @@
         }
 
         @Override
-        public void setIcon(Drawable icon) {
+        public Tab setIcon(Drawable icon) {
             mIcon = icon;
+            return this;
         }
 
         @Override
-        public void setText(CharSequence text) {
+        public Tab setText(CharSequence text) {
             mText = text;
+            return this;
         }
 
         @Override
@@ -567,4 +568,56 @@
             selectTab(this);
         }
     }
+
+    @Override
+    public void setCustomView(View view) {
+        mActionView.setCustomNavigationView(view);
+    }
+
+    @Override
+    public void setCustomView(View view, LayoutParams layoutParams) {
+        view.setLayoutParams(layoutParams);
+        mActionView.setCustomNavigationView(view);
+    }
+
+    @Override
+    public void setListNavigationCallbacks(SpinnerAdapter adapter, NavigationCallback callback) {
+        mActionView.setDropdownAdapter(adapter);
+        mActionView.setCallback(callback);
+    }
+
+    @Override
+    public int getSelectedNavigationIndex() {
+        switch (mActionView.getNavigationMode()) {
+            case NAVIGATION_MODE_TABS:
+                return mSelectedTab.getPosition();
+            case NAVIGATION_MODE_LIST:
+                return mActionView.getDropdownSelectedPosition();
+            default:
+                return -1;
+        }
+    }
+
+    @Override
+    public int getNavigationItemCount() {
+        switch (mActionView.getNavigationMode()) {
+            case NAVIGATION_MODE_TABS:
+                return mTabs.size();
+            case NAVIGATION_MODE_LIST:
+                SpinnerAdapter adapter = mActionView.getDropdownAdapter();
+                return adapter != null ? adapter.getCount() : 0;
+            default:
+                return 0;
+        }
+    }
+
+    @Override
+    public void setNavigationMode(int mode) {
+        mActionView.setNavigationMode(mode);
+    }
+
+    @Override
+    public Tab getTabAt(int index) {
+        return mTabs.get(index);
+    }
 }
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index c8e3935..6f6b40b 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -18,11 +18,11 @@
 
 import com.android.internal.R;
 
-import android.app.Activity;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.ListFragment;
 import android.app.backup.BackupManager;
+import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Bundle;
@@ -45,61 +45,65 @@
         public void onLocaleSelected(Locale locale);
     }
 
-    Loc[] mLocales;
-    String[] mSpecialLocaleCodes;
-    String[] mSpecialLocaleNames;
-
-    private Locale mNewLocale;
-
     LocaleSelectionListener mListener;  // default to null
 
-    private static class Loc implements Comparable<Loc> {
-        static Collator sCollator = Collator.getInstance();
+    public static class LocaleInfo implements Comparable<LocaleInfo> {
+        static final Collator sCollator = Collator.getInstance();
 
         String label;
         Locale locale;
 
-        public Loc(String label, Locale locale) {
+        public LocaleInfo(String label, Locale locale) {
             this.label = label;
             this.locale = locale;
         }
 
+        public String getLabel() {
+            return label;
+        }
+
+        public Locale getLocale() {
+            return locale;
+        }
+
         @Override
         public String toString() {
             return this.label;
         }
 
         @Override
-        public int compareTo(Loc another) {
+        public int compareTo(LocaleInfo another) {
             return sCollator.compare(this.label, another.label);
         }
     }
 
-    private void setUpLocaleList() {
-        final Activity activity = getActivity();
-        final Resources resources = activity.getResources();
-        mSpecialLocaleCodes = resources.getStringArray(R.array.special_locale_codes);
-        mSpecialLocaleNames = resources.getStringArray(R.array.special_locale_names);
-
-        final String[] locales = activity.getAssets().getLocales();
+    /**
+     * Constructs an Adapter object containing Locale information. Content is sorted by
+     * {@link LocaleInfo#label}.
+     */
+    public static ArrayAdapter<LocaleInfo> constructAdapter(Context context) {
+        final Resources resources = context.getResources();
+        final String[] locales = context.getAssets().getLocales();
+        final String[] specialLocaleCodes = resources.getStringArray(R.array.special_locale_codes);
+        final String[] specialLocaleNames = resources.getStringArray(R.array.special_locale_names);
         Arrays.sort(locales);
         final int origSize = locales.length;
-        Loc[] preprocess = new Loc[origSize];
+        final LocaleInfo[] preprocess = new LocaleInfo[origSize];
         int finalSize = 0;
         for (int i = 0 ; i < origSize; i++ ) {
-            String s = locales[i];
-            int len = s.length();
+            final String s = locales[i];
+            final int len = s.length();
             if (len == 5) {
                 String language = s.substring(0, 2);
                 String country = s.substring(3, 5);
-                Locale l = new Locale(language, country);
+                final Locale l = new Locale(language, country);
 
                 if (finalSize == 0) {
                     if (DEBUG) {
                         Log.v(TAG, "adding initial "+ toTitleCase(l.getDisplayLanguage(l)));
                     }
                     preprocess[finalSize++] =
-                            new Loc(toTitleCase(l.getDisplayLanguage(l)), l);
+                            new LocaleInfo(toTitleCase(l.getDisplayLanguage(l)), l);
                 } else {
                     // check previous entry:
                     //  same lang and a country -> upgrade to full name and
@@ -110,15 +114,20 @@
                         if (DEBUG) {
                             Log.v(TAG, "backing up and fixing "+
                                     preprocess[finalSize-1].label+" to "+
-                                    getDisplayName(preprocess[finalSize-1].locale));
+                                    getDisplayName(preprocess[finalSize-1].locale,
+                                            specialLocaleCodes, specialLocaleNames));
                         }
                         preprocess[finalSize-1].label = toTitleCase(
-                                getDisplayName(preprocess[finalSize-1].locale));
+                                getDisplayName(preprocess[finalSize-1].locale,
+                                        specialLocaleCodes, specialLocaleNames));
                         if (DEBUG) {
-                            Log.v(TAG, "  and adding "+ toTitleCase(getDisplayName(l)));
+                            Log.v(TAG, "  and adding "+ toTitleCase(
+                                    getDisplayName(l, specialLocaleCodes, specialLocaleNames)));
                         }
                         preprocess[finalSize++] =
-                                new Loc(toTitleCase(getDisplayName(l)), l);
+                                new LocaleInfo(toTitleCase(
+                                        getDisplayName(
+                                                l, specialLocaleCodes, specialLocaleNames)), l);
                     } else {
                         String displayName;
                         if (s.equals("zz_ZZ")) {
@@ -129,31 +138,20 @@
                         if (DEBUG) {
                             Log.v(TAG, "adding "+displayName);
                         }
-                        preprocess[finalSize++] = new Loc(displayName, l);
+                        preprocess[finalSize++] = new LocaleInfo(displayName, l);
                     }
                 }
             }
         }
-        mLocales = new Loc[finalSize];
-        for (int i = 0; i < finalSize ; i++) {
-            mLocales[i] = preprocess[i];
+
+        final LocaleInfo[] localeInfos = new LocaleInfo[finalSize];
+        for (int i = 0; i < finalSize; i++) {
+            localeInfos[i] = preprocess[i];
         }
-        Arrays.sort(mLocales);
+        Arrays.sort(localeInfos);
         final int layoutId = R.layout.locale_picker_item;
         final int fieldId = R.id.locale;
-        final ArrayAdapter<Loc> adapter =
-                new ArrayAdapter<Loc>(activity, layoutId, fieldId, mLocales);
-        setListAdapter(adapter);
-    }
-
-    @Override
-    public void onActivityCreated(final Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-        setUpLocaleList();
-    }
-
-    public void setLocaleSelectionListener(LocaleSelectionListener listener) {
-        mListener = listener;
+        return new ArrayAdapter<LocaleInfo>(context, layoutId, fieldId, localeInfos);
     }
 
     private static String toTitleCase(String s) {
@@ -164,12 +162,13 @@
         return Character.toUpperCase(s.charAt(0)) + s.substring(1);
     }
 
-    private String getDisplayName(Locale l) {
+    private static String getDisplayName(
+            Locale l, String[] specialLocaleCodes, String[] specialLocaleNames) {
         String code = l.toString();
 
-        for (int i = 0; i < mSpecialLocaleCodes.length; i++) {
-            if (mSpecialLocaleCodes[i].equals(code)) {
-                return mSpecialLocaleNames[i];
+        for (int i = 0; i < specialLocaleCodes.length; i++) {
+            if (specialLocaleCodes[i].equals(code)) {
+                return specialLocaleNames[i];
             }
         }
 
@@ -177,6 +176,17 @@
     }
 
     @Override
+    public void onActivityCreated(final Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        final ArrayAdapter<LocaleInfo> adapter = constructAdapter(getActivity());
+        setListAdapter(adapter);
+    }
+
+    public void setLocaleSelectionListener(LocaleSelectionListener listener) {
+        mListener = listener;
+    }
+
+    @Override
     public void onResume() {
         super.onResume();
         getListView().requestFocus();
@@ -191,7 +201,8 @@
     @Override
     public void onListItemClick(ListView l, View v, int position, long id) {
         if (mListener != null) {
-            mListener.onLocaleSelected(mLocales[position].locale);
+            final Locale locale = ((LocaleInfo)getListAdapter().getItem(position)).locale;
+            mListener.onLocaleSelected(locale);
         }
     }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 34a5b11..f87ca3e 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -32,5 +32,6 @@
     void animateCollapse();
     void setLightsOn(boolean on);
     void setMenuKeyVisible(boolean visible);
+    void setIMEButtonVisible(boolean visible);
 }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 90f4d48..d5ae1f0 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -32,6 +32,7 @@
     void removeIcon(String slot);
     void setActiveWindowIsFullscreen(boolean fullscreen);
     void setMenuKeyVisible(boolean visible);
+    void setIMEButtonVisible(boolean visible);
 
     // ---- Methods below are for use by the status bar policy services ----
     // You need the STATUS_BAR_SERVICE permission
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 49ae2bc7..ca1cd59 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -55,6 +55,7 @@
     void hideMySoftInput(in IBinder token, int flags);
     void showMySoftInput(in IBinder token, int flags);
     void updateStatusIcon(in IBinder token, String packageName, int iconId);
+    void setIMEButtonVisible(in IBinder token, boolean visible);
     InputMethodSubtype getCurrentInputMethodSubtype();
     
     boolean setInputMethodEnabled(String id, boolean enabled);
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 2888074..621defe 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -24,10 +24,10 @@
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.LinearLayout.LayoutParams;
 
 import java.util.ArrayList;
 
@@ -169,6 +169,10 @@
             final MenuItemImpl itemData = itemsToShow.get(i);
             final View actionView = itemData.getActionView();
             if (actionView != null) {
+                final ViewParent parent = actionView.getParent();
+                if (parent instanceof ViewGroup) {
+                    ((ViewGroup) parent).removeView(actionView);
+                }
                 addView(actionView, makeActionViewLayoutParams());
             } else {
                 needsDivider = addItemView(i == 0 || !needsDivider,
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 38f76d3..e93c414 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -26,9 +26,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.ButtonGroup;
-import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 4c3bba1..be96e48 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -26,20 +26,21 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.TypedArray;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.ActionMode;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.widget.AdapterView;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
@@ -63,19 +64,27 @@
      * Display options that require re-layout as opposed to a simple invalidate
      */
     private static final int DISPLAY_RELAYOUT_MASK =
-            ActionBar.DISPLAY_HIDE_HOME |
-            ActionBar.DISPLAY_USE_LOGO;
+            ActionBar.DISPLAY_SHOW_HOME |
+            ActionBar.DISPLAY_USE_LOGO |
+            ActionBar.DISPLAY_HOME_AS_UP |
+            ActionBar.DISPLAY_SHOW_CUSTOM |
+            ActionBar.DISPLAY_SHOW_TITLE;
+
+    private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.LEFT | Gravity.CENTER_VERTICAL;
     
     private final int mContentHeight;
 
     private int mNavigationMode;
-    private int mDisplayOptions;
+    private int mDisplayOptions = ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP;
     private CharSequence mTitle;
     private CharSequence mSubtitle;
     private Drawable mIcon;
     private Drawable mLogo;
     private Drawable mDivider;
+    private Drawable mHomeAsUpIndicator;
 
+    private LinearLayout mHomeLayout;
+    private ImageView mHomeAsUpView;
     private ImageView mIconView;
     private ImageView mLogoView;
     private LinearLayout mTitleLayout;
@@ -98,7 +107,8 @@
     private ActionBarContextView mContextView;
 
     private ActionMenuItem mLogoNavItem;
-    
+
+    private SpinnerAdapter mSpinnerAdapter;
     private NavigationCallback mCallback;
 
     private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
@@ -122,30 +132,56 @@
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar);
 
-        final int colorFilter = a.getColor(R.styleable.ActionBar_colorFilter, 0);
-
-        if (colorFilter != 0) {
-            final Drawable d = getBackground();
-            d.setDither(true);
-            d.setColorFilter(new PorterDuffColorFilter(colorFilter, PorterDuff.Mode.OVERLAY));
-        }
-
-        ApplicationInfo info = context.getApplicationInfo();
+        ApplicationInfo appInfo = context.getApplicationInfo();
         PackageManager pm = context.getPackageManager();
         mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode,
                 ActionBar.NAVIGATION_MODE_STANDARD);
         mTitle = a.getText(R.styleable.ActionBar_title);
         mSubtitle = a.getText(R.styleable.ActionBar_subtitle);
-        mDisplayOptions = a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT);
         
         mLogo = a.getDrawable(R.styleable.ActionBar_logo);
         if (mLogo == null) {
-            mLogo = info.loadLogo(pm);
+            if (context instanceof Activity) {
+                try {
+                    mLogo = pm.getActivityLogo(((Activity) context).getComponentName());
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Activity component name not found!", e);
+                }
+            }
+            if (mLogo == null) {
+                mLogo = appInfo.loadLogo(pm);
+            }
         }
+
         mIcon = a.getDrawable(R.styleable.ActionBar_icon);
         if (mIcon == null) {
-            mIcon = info.loadIcon(pm);
+            if (context instanceof Activity) {
+                try {
+                    mIcon = pm.getActivityIcon(((Activity) context).getComponentName());
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Activity component name not found!", e);
+                }
+            }
+            if (mIcon == null) {
+                mIcon = appInfo.loadIcon(pm);
+            }
         }
+
+        mHomeLayout = new LinearLayout(context, null,
+                com.android.internal.R.attr.actionButtonStyle);
+        mHomeLayout.setClickable(true);
+        mHomeLayout.setFocusable(true);
+        mHomeLayout.setOnClickListener(mHomeClickListener);
+        mHomeLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT));
+
+        mHomeAsUpIndicator = a.getDrawable(R.styleable.ActionBar_homeAsUpIndicator);
+
+        mHomeAsUpView = new ImageView(context);
+        mHomeAsUpView.setImageDrawable(mHomeAsUpIndicator);
+        mHomeAsUpView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT));
+        mHomeLayout.addView(mHomeAsUpView);
         
         Drawable background = a.getDrawable(R.styleable.ActionBar_background);
         if (background != null) {
@@ -155,11 +191,14 @@
         mTitleStyleRes = a.getResourceId(R.styleable.ActionBar_titleTextStyle, 0);
         mSubtitleStyleRes = a.getResourceId(R.styleable.ActionBar_subtitleTextStyle, 0);
 
+        setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT));
+
         final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
         if (customNavId != 0) {
             LayoutInflater inflater = LayoutInflater.from(context);
             mCustomNavView = (View) inflater.inflate(customNavId, null);
-            mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM;
+            mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD;
+            setDisplayOptions(mDisplayOptions | ActionBar.DISPLAY_SHOW_CUSTOM);
         }
 
         mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
@@ -241,9 +280,13 @@
     }
 
     public void setCustomNavigationView(View view) {
+        final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
+        if (mCustomNavView != null && showCustom) {
+            removeView(mCustomNavView);
+        }
         mCustomNavView = view;
-        if (view != null) {
-            setNavigationMode(ActionBar.NAVIGATION_MODE_CUSTOM);
+        if (mCustomNavView != null && showCustom) {
+            addView(mCustomNavView);
         }
     }
 
@@ -296,15 +339,43 @@
     }
 
     public void setDisplayOptions(int options) {
+        // TODO Remove this once DISPLAY_HIDE_HOME is removed
+        if ((options & ActionBar.DISPLAY_HIDE_HOME) != 0) {
+            options &= ~(ActionBar.DISPLAY_HIDE_HOME | ActionBar.DISPLAY_SHOW_HOME);
+        }
+        // End TODO
+
         final int flagsChanged = options ^ mDisplayOptions;
         mDisplayOptions = options;
         if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
-            final int vis = (options & ActionBar.DISPLAY_HIDE_HOME) != 0 ? GONE : VISIBLE;
-            if (mLogoView != null) {
-                mLogoView.setVisibility(vis);
+            final int vis = (options & ActionBar.DISPLAY_SHOW_HOME) != 0 ? VISIBLE : GONE;
+            mHomeLayout.setVisibility(vis);
+
+            if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+                mHomeAsUpView.setVisibility((options & ActionBar.DISPLAY_HOME_AS_UP) != 0
+                        ? VISIBLE : GONE);
             }
-            if (mIconView != null) {
-                mIconView.setVisibility(vis);
+
+            if (mLogoView != null && (flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
+                final boolean logoVis = (options & ActionBar.DISPLAY_USE_LOGO) != 0;
+                mLogoView.setVisibility(logoVis ? VISIBLE : GONE);
+                mIconView.setVisibility(logoVis ? GONE : VISIBLE);
+            }
+
+            if ((flagsChanged & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                if ((options & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                    initTitle();
+                } else {
+                    removeView(mTitleLayout);
+                }
+            }
+
+            if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
+                if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+                    addView(mCustomNavView);
+                } else {
+                    removeView(mCustomNavView);
+                }
             }
             
             requestLayout();
@@ -317,52 +388,27 @@
         final int oldMode = mNavigationMode;
         if (mode != oldMode) {
             switch (oldMode) {
-            case ActionBar.NAVIGATION_MODE_STANDARD:
-                if (mTitleLayout != null) {
-                    removeView(mTitleLayout);
-                    mTitleLayout = null;
-                    mTitleView = null;
-                    mSubtitleView = null;
-                }
-                break;
-            case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+            case ActionBar.NAVIGATION_MODE_LIST:
                 if (mSpinner != null) {
                     removeView(mSpinner);
-                    mSpinner = null;
-                }
-                break;
-            case ActionBar.NAVIGATION_MODE_CUSTOM:
-                if (mCustomNavView != null) {
-                    removeView(mCustomNavView);
-                    mCustomNavView = null;
                 }
                 break;
             case ActionBar.NAVIGATION_MODE_TABS:
                 if (mTabLayout != null) {
                     removeView(mTabScrollView);
-                    mTabLayout = null;
-                    mTabScrollView = null;
                 }
             }
             
             switch (mode) {
-            case ActionBar.NAVIGATION_MODE_STANDARD:
-                initTitle();
-                break;
-            case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+            case ActionBar.NAVIGATION_MODE_LIST:
                 mSpinner = new Spinner(mContext, null,
                         com.android.internal.R.attr.actionDropDownStyle);
+                mSpinner.setAdapter(mSpinnerAdapter);
                 mSpinner.setOnItemSelectedListener(mNavItemSelectedListener);
                 addView(mSpinner);
                 break;
-            case ActionBar.NAVIGATION_MODE_CUSTOM:
-                addView(mCustomNavView);
-                break;
             case ActionBar.NAVIGATION_MODE_TABS:
-                mTabScrollView = new HorizontalScrollView(getContext());
-                mTabLayout = new LinearLayout(getContext(), null,
-                        com.android.internal.R.attr.actionBarTabBarStyle);
-                mTabScrollView.addView(mTabLayout);
+                ensureTabsExist();
                 addView(mTabScrollView);
                 break;
             }
@@ -371,8 +417,24 @@
         }
     }
     
+    private void ensureTabsExist() {
+        if (mTabScrollView == null) {
+            mTabScrollView = new HorizontalScrollView(getContext());
+            mTabLayout = new LinearLayout(getContext(), null,
+                    com.android.internal.R.attr.actionBarTabBarStyle);
+            mTabScrollView.addView(mTabLayout);
+        }
+    }
+
     public void setDropdownAdapter(SpinnerAdapter adapter) {
-        mSpinner.setAdapter(adapter);
+        mSpinnerAdapter = adapter;
+        if (mSpinner != null) {
+            mSpinner.setAdapter(adapter);
+        }
+    }
+
+    public SpinnerAdapter getDropdownAdapter() {
+        return mSpinnerAdapter;
     }
 
     public void setDropdownSelectedPosition(int position) {
@@ -407,6 +469,7 @@
     }
 
     public void addTab(ActionBar.Tab tab) {
+        ensureTabsExist();
         final boolean isFirst = mTabLayout.getChildCount() == 0;
         View tabView = createTabView(tab);
         mTabLayout.addView(tabView);
@@ -416,6 +479,7 @@
     }
 
     public void addTab(ActionBar.Tab tab, int position) {
+        ensureTabsExist();
         final boolean isFirst = mTabLayout.getChildCount() == 0;
         final TabView tabView = createTabView(tab);
         mTabLayout.addView(tabView, position);
@@ -425,46 +489,50 @@
     }
 
     public void removeTabAt(int position) {
-        mTabLayout.removeViewAt(position);
+        if (mTabLayout != null) {
+            mTabLayout.removeViewAt(position);
+        }
     }
 
     @Override
     protected LayoutParams generateDefaultLayoutParams() {
         // Used by custom nav views if they don't supply layout params. Everything else
         // added to an ActionBarView should have them already.
-        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+        return new ActionBar.LayoutParams(DEFAULT_CUSTOM_GRAVITY);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        if ((mDisplayOptions & ActionBar.DISPLAY_HIDE_HOME) == 0) {
-            if (mLogo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
-                mLogoView = new ImageView(getContext(), null,
-                        com.android.internal.R.attr.actionButtonStyle);
-                mLogoView.setAdjustViewBounds(true);
-                mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
-                        LayoutParams.MATCH_PARENT));
-                mLogoView.setImageDrawable(mLogo);
-                mLogoView.setClickable(true);
-                mLogoView.setFocusable(true);
-                mLogoView.setOnClickListener(mHomeClickListener);
-                addView(mLogoView);
-            } else if (mIcon != null) {
-                mIconView = new ImageView(getContext(), null,
-                        com.android.internal.R.attr.actionButtonStyle);
-                mIconView.setAdjustViewBounds(true);
-                mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
-                        LayoutParams.MATCH_PARENT));
-                mIconView.setImageDrawable(mIcon);
-                mIconView.setClickable(true);
-                mIconView.setFocusable(true);
-                mIconView.setOnClickListener(mHomeClickListener);
-                addView(mIconView);
-            }
+        final Context context = getContext();
+
+        if (mLogo != null) {
+            mLogoView = new ImageView(context);
+            mLogoView.setScaleType(ImageView.ScaleType.CENTER);
+            mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.MATCH_PARENT));
+            mLogoView.setImageDrawable(mLogo);
+            mLogoView.setVisibility((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0
+                    ? VISIBLE : GONE);
+            mHomeLayout.addView(mLogoView);
         }
 
+        if (mIcon != null) {
+            mIconView = new ImageView(context, null,
+                    com.android.internal.R.attr.actionButtonStyle);
+            mIconView.setScaleType(ImageView.ScaleType.CENTER);
+            mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.MATCH_PARENT));
+            mIconView.setImageDrawable(mIcon);
+            mIconView.setVisibility(
+                    (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null
+                    ? VISIBLE : GONE);
+            mHomeLayout.addView(mIconView);
+        }
+
+        addView(mHomeLayout);
+
         switch (mNavigationMode) {
         case ActionBar.NAVIGATION_MODE_STANDARD:
             if (mLogoView == null) {
@@ -472,19 +540,23 @@
             }
             break;
             
-        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+        case ActionBar.NAVIGATION_MODE_LIST:
             throw new UnsupportedOperationException(
-                    "Inflating dropdown list navigation isn't supported yet!");
+                    "Inflating list navigation isn't supported yet!");
             
         case ActionBar.NAVIGATION_MODE_TABS:
             throw new UnsupportedOperationException(
                     "Inflating tab navigation isn't supported yet!");
-            
-        case ActionBar.NAVIGATION_MODE_CUSTOM:
-            if (mCustomNavView != null) {
+        }
+
+        if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+            final ViewParent parent = mCustomNavView.getParent();
+            if (parent != this) {
+                if (parent instanceof ViewGroup) {
+                    ((ViewGroup) parent).removeView(mCustomNavView);
+                }
                 addView(mCustomNavView);
             }
-            break;
         }
     }
     
@@ -513,6 +585,7 @@
     }
 
     public void setTabSelected(int position) {
+        ensureTabsExist();
         final int tabCount = mTabLayout.getChildCount();
         for (int i = 0; i < tabCount; i++) {
             final View child = mTabLayout.getChildAt(i);
@@ -544,57 +617,40 @@
                 mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
         
         final int verticalPadding = getPaddingTop() + getPaddingBottom();
-        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
+        final int paddingLeft = getPaddingLeft();
+        final int paddingRight = getPaddingRight();
         final int height = maxHeight - verticalPadding;
         final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
 
-        if (mLogoView != null && mLogoView.getVisibility() != GONE) {
-            availableWidth = measureChildView(mLogoView, availableWidth, childSpecHeight, 0);
-        }
-        if (mIconView != null && mIconView.getVisibility() != GONE) {
-            availableWidth = measureChildView(mIconView, availableWidth, childSpecHeight, 0);
+        int availableWidth = contentWidth - paddingLeft - paddingRight;
+        int leftOfCenter = availableWidth / 2;
+        int rightOfCenter = leftOfCenter;
+
+        if (mHomeLayout.getVisibility() != GONE) {
+            availableWidth = measureChildView(mHomeLayout, availableWidth, childSpecHeight, 0);
+            leftOfCenter -= mHomeLayout.getMeasuredWidth();
         }
         
         if (mMenuView != null) {
             availableWidth = measureChildView(mMenuView, availableWidth,
                     childSpecHeight, 0);
+            rightOfCenter -= mMenuView.getMeasuredWidth();
         }
-        
+
+        if (mTitleLayout != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
+            leftOfCenter -= mTitleLayout.getMeasuredWidth();
+        }
+
         switch (mNavigationMode) {
-        case ActionBar.NAVIGATION_MODE_STANDARD:
-            if (mTitleLayout != null) {
-                measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
-            }
-            break;
-        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+        case ActionBar.NAVIGATION_MODE_LIST:
             if (mSpinner != null) {
                 mSpinner.measure(
                         MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
                         MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
-            }
-            break;
-        case ActionBar.NAVIGATION_MODE_CUSTOM:
-            if (mCustomNavView != null) {
-                LayoutParams lp = mCustomNavView.getLayoutParams();
-                final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
-                        MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
-                final int customNavWidth = lp.width >= 0 ?
-                        Math.min(lp.width, availableWidth) : availableWidth;
-
-                // If the action bar is wrapping to its content height, don't allow a custom
-                // view to MATCH_PARENT.
-                int customNavHeightMode;
-                if (mContentHeight <= 0) {
-                    customNavHeightMode = MeasureSpec.AT_MOST;
-                } else {
-                    customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
-                            MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
-                }
-                final int customNavHeight = lp.height >= 0 ?
-                        Math.min(lp.height, height) : height;
-                mCustomNavView.measure(
-                        MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode),
-                        MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
+                final int spinnerWidth = mSpinner.getMeasuredWidth();
+                availableWidth -= spinnerWidth;
+                leftOfCenter -= spinnerWidth;
             }
             break;
         case ActionBar.NAVIGATION_MODE_TABS:
@@ -602,10 +658,56 @@
                 mTabScrollView.measure(
                         MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
                         MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+                final int tabWidth = mTabScrollView.getMeasuredWidth();
+                availableWidth -= tabWidth;
+                leftOfCenter -= tabWidth;
             }
             break;
         }
 
+        if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
+            final LayoutParams lp = generateLayoutParams(mCustomNavView.getLayoutParams());
+            final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
+                    (ActionBar.LayoutParams) lp : null;
+
+            int horizontalMargin = 0;
+            int verticalMargin = 0;
+            if (ablp != null) {
+                horizontalMargin = ablp.leftMargin + ablp.rightMargin;
+                verticalMargin = ablp.topMargin + ablp.bottomMargin;
+            }
+
+            // If the action bar is wrapping to its content height, don't allow a custom
+            // view to MATCH_PARENT.
+            int customNavHeightMode;
+            if (mContentHeight <= 0) {
+                customNavHeightMode = MeasureSpec.AT_MOST;
+            } else {
+                customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
+                        MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            }
+            final int customNavHeight = Math.max(0,
+                    (lp.height >= 0 ? Math.min(lp.height, height) : height) - verticalMargin);
+
+            final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
+                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            int customNavWidth = Math.max(0,
+                    (lp.width >= 0 ? Math.min(lp.width, availableWidth) : availableWidth)
+                    - horizontalMargin);
+            final int hgrav = (ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY) &
+                    Gravity.HORIZONTAL_GRAVITY_MASK;
+
+            // Centering a custom view is treated specially; we try to center within the whole
+            // action bar rather than in the available space.
+            if (hgrav == Gravity.CENTER_HORIZONTAL && lp.width == LayoutParams.MATCH_PARENT) {
+                customNavWidth = Math.min(leftOfCenter, rightOfCenter) * 2;
+            }
+
+            mCustomNavView.measure(
+                    MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode),
+                    MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
+        }
+
         if (mContentHeight <= 0) {
             int measuredHeight = 0;
             final int count = getChildCount();
@@ -642,39 +744,89 @@
         final int y = getPaddingTop();
         final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
 
-        if (mLogoView != null && mLogoView.getVisibility() != GONE) {
-            x += positionChild(mLogoView, x, y, contentHeight);
-        }
-        if (mIconView != null && mIconView.getVisibility() != GONE) {
-            x += positionChild(mIconView, x, y, contentHeight);
+        if (mHomeLayout.getVisibility() != GONE) {
+            x += positionChild(mHomeLayout, x, y, contentHeight);
         }
         
+        if (mTitleLayout != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            x += positionChild(mTitleLayout, x, y, contentHeight);
+        }
+
         switch (mNavigationMode) {
         case ActionBar.NAVIGATION_MODE_STANDARD:
-            if (mTitleLayout != null) {
-                x += positionChild(mTitleLayout, x, y, contentHeight);
-            }
             break;
-        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+        case ActionBar.NAVIGATION_MODE_LIST:
             if (mSpinner != null) {
                 x += positionChild(mSpinner, x, y, contentHeight);
             }
             break;
-        case ActionBar.NAVIGATION_MODE_CUSTOM:
-            if (mCustomNavView != null) {
-                x += positionChild(mCustomNavView, x, y, contentHeight);
-            }
-            break;
         case ActionBar.NAVIGATION_MODE_TABS:
             if (mTabScrollView != null) {
                 x += positionChild(mTabScrollView, x, y, contentHeight);
             }
         }
 
-        x = r - l - getPaddingRight();
-
+        int menuLeft = r - l - getPaddingRight();
         if (mMenuView != null) {
-            x -= positionChildInverse(mMenuView, x, y, contentHeight);
+            positionChildInverse(mMenuView, menuLeft, y, contentHeight);
+            menuLeft -= mMenuView.getMeasuredWidth();
+        }
+
+        if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+            LayoutParams lp = mCustomNavView.getLayoutParams();
+            final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
+                    (ActionBar.LayoutParams) lp : null;
+
+            final int gravity = ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY;
+            final int navWidth = mCustomNavView.getMeasuredWidth();
+
+            int topMargin = 0;
+            int bottomMargin = 0;
+            if (ablp != null) {
+                x += ablp.leftMargin;
+                menuLeft -= ablp.rightMargin;
+                topMargin = ablp.topMargin;
+                bottomMargin = ablp.bottomMargin;
+            }
+
+            int hgravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+            // See if we actually have room to truly center; if not push against left or right.
+            if (hgravity == Gravity.CENTER_HORIZONTAL) {
+                final int centeredLeft = ((mRight - mLeft) - navWidth) / 2;
+                if (centeredLeft < x) {
+                    hgravity = Gravity.LEFT;
+                } else if (centeredLeft + navWidth > menuLeft) {
+                    hgravity = Gravity.RIGHT;
+                }
+            }
+
+            int xpos = 0;
+            switch (hgravity) {
+                case Gravity.CENTER_HORIZONTAL:
+                    xpos = ((mRight - mLeft) - navWidth) / 2;
+                    break;
+                case Gravity.LEFT:
+                    xpos = x;
+                    break;
+                case Gravity.RIGHT:
+                    xpos = menuLeft - navWidth;
+                    break;
+            }
+
+            int ypos = 0;
+            switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
+                case Gravity.CENTER_VERTICAL:
+                    ypos = ((mBottom - mTop) - mCustomNavView.getMeasuredHeight()) / 2;
+                    break;
+                case Gravity.TOP:
+                    ypos = getPaddingTop() + topMargin;
+                    break;
+                case Gravity.BOTTOM:
+                    ypos = getHeight() - getPaddingBottom() - mCustomNavView.getMeasuredHeight()
+                            - bottomMargin;
+                    break;
+            }
+            x += positionChild(mCustomNavView, xpos, ypos, contentHeight);
         }
     }
 
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index f3b9357..c4056a4 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -701,6 +701,7 @@
 
 static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
                                                            jint ident,
+                                                           jshort density,
                                                            jobject outValue,
                                                            jboolean resolve)
 {
@@ -713,7 +714,7 @@
     Res_value value;
     ResTable_config config;
     uint32_t typeSpecFlags;
-    ssize_t block = res.getResource(ident, &value, false, &typeSpecFlags, &config);
+    ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
 #if THROW_ON_BAD_ID
     if (block == BAD_INDEX) {
         jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
@@ -1703,7 +1704,7 @@
         (void*) android_content_AssetManager_getResourceTypeName },
     { "getResourceEntryName","(I)Ljava/lang/String;",
         (void*) android_content_AssetManager_getResourceEntryName },
-    { "loadResourceValue","(ILandroid/util/TypedValue;Z)I",
+    { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
         (void*) android_content_AssetManager_loadResourceValue },
     { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
         (void*) android_content_AssetManager_loadResourceBagValue },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2444fce..3635fab 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -532,6 +532,13 @@
         android:description="@string/permdesc_sdcardWrite"
         android:protectionLevel="dangerous" />
 
+    <!-- Allows an application to write to internal media storage -->
+    <permission android:name="android.permission.WRITE_MEDIA_STORAGE"
+        android:permissionGroup="android.permission-group.STORAGE"
+        android:label="@string/permlab_mediaStorageWrite"
+        android:description="@string/permdesc_mediaStorageWrite"
+        android:protectionLevel="signatureOrSystem" />
+
     <!-- ============================================ -->
     <!-- Permissions for low-level system interaction -->
     <!-- ============================================ -->
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png
new file mode 100644
index 0000000..a8da981
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png
new file mode 100644
index 0000000..af0f308
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_select_all.png b/core/res/res/drawable-hdpi/ic_menu_select_all.png
deleted file mode 100644
index dde6741..0000000
--- a/core/res/res/drawable-hdpi/ic_menu_select_all.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png
new file mode 100644
index 0000000..7aae741
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png
new file mode 100644
index 0000000..66ef51c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_select_all.png b/core/res/res/drawable-mdpi/ic_menu_select_all.png
deleted file mode 100644
index 37fd3cbd..0000000
--- a/core/res/res/drawable-mdpi/ic_menu_select_all.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
new file mode 100644
index 0000000..2738b62
--- /dev/null
+++ b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/layout/text_edit_no_paste_window.xml b/core/res/res/layout/text_edit_no_paste_window.xml
new file mode 100644
index 0000000..f288e6f6
--- /dev/null
+++ b/core/res/res/layout/text_edit_no_paste_window.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@android:drawable/text_edit_paste_window">
+
+    <ImageView android:id="@+id/paste_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:background="@android:drawable/ic_menu_paste_dark"
+    />
+
+    <TextView android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:text="@android:string/pasteDisabled"
+        android:layout_toRightOf="@id/paste_icon"
+    />
+
+</RelativeLayout>
diff --git a/core/res/res/layout/text_edit_paste_window.xml b/core/res/res/layout/text_edit_paste_window.xml
new file mode 100644
index 0000000..ee2c4d2
--- /dev/null
+++ b/core/res/res/layout/text_edit_paste_window.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@android:drawable/text_edit_paste_window">
+
+    <ImageView android:id="@+id/paste_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:background="@android:drawable/ic_menu_paste_light"
+    />
+
+    <TextView android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:textAppearance="?android:attr/textAppearanceMediumInverse"
+        android:text="@android:string/paste"
+        android:layout_toRightOf="@id/paste_icon"
+    />
+
+</RelativeLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dab627c..0cac7eb 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -556,6 +556,11 @@
         <!-- Reference to a drawable that will be used to display a text selection
              anchor for positioning the cursor within text. -->
         <attr name="textSelectHandle" format="reference" />
+        <!-- The layout of the view that is displayed on top of the cursor to paste inside a
+             TextEdit field. -->
+        <attr name="textEditPasteWindowLayout" format="reference" />
+        <!-- Variation of textEditPasteWindowLayout displayed when the clipboard is empty. -->
+        <attr name="textEditNoPasteWindowLayout" format="reference" />
 
         <!-- Theme to use for dialogs spawned from this theme. -->
         <attr name="dialogTheme" format="reference" />
@@ -2393,6 +2398,11 @@
         <!-- Reference to a drawable that will be used to display a text selection
              anchor for positioning the cursor within text. -->
         <attr name="textSelectHandle" />
+        <!-- The layout of the view that is displayed on top of the cursor to paste inside a
+             TextEdit field. -->
+        <attr name="textEditPasteWindowLayout" />
+        <!-- Variation of textEditPasteWindowLayout displayed when the clipboard is empty. -->
+        <attr name="textEditNoPasteWindowLayout" />
 
         <!-- Height of a line of text. -->
         <attr name="textLineHeight" />
@@ -4230,18 +4240,21 @@
         <attr name="navigationMode">
             <!-- Normal static title text -->
             <enum name="normal" value="0" />
-            <!-- The action bar will use a drop-down selection in place of title text. -->
-            <enum name="dropdownList" value="1" />
-            <!-- The action bar will use a series of horizontal tabs in place of title text. -->
-            <enum name="tabBar" value="2" />
+            <!-- The action bar will use a selection list for navigation. -->
+            <enum name="listMode" value="1" />
+            <!-- The action bar will use a series of horizontal tabs for navigation. -->
+            <enum name="tabMode" value="2" />
         </attr>
         <!-- Options affecting how the action bar is displayed. -->
         <attr name="displayOptions">
-            <flag name="useLogo" value="1" />
-            <flag name="hideHome" value="2" />
+            <flag name="useLogo" value="0x1" />
+            <flag name="showHome" value="0x2" />
+            <flag name="homeAsUp" value="0x4" />
+            <flag name="showTitle" value="0x8" />
+            <flag name="showCustom" value="0x10" />
+            <!-- DEPRECATED - Remove this later!! -->
+            <flag name="hideHome" value="0x1000" />
         </attr>
-        <!-- Specifies the color used to style the action bar. -->
-        <attr name="colorFilter" format="color" />
         <!-- Specifies title text used for navigationMode="normal" -->
         <attr name="title" />
         <!-- Specifies subtitle text used for navigationMode="normal" -->
@@ -4262,6 +4275,8 @@
         <attr name="customNavigationLayout" format="reference" />
         <!-- Specifies a fixed height. -->
         <attr name="height" />
+        <!-- Specifies a drawable to use for the 'home as up' indicator. -->
+        <attr name="homeAsUpIndicator" format="reference" />
     </declare-styleable>
 
     <declare-styleable name="ActionMode">
@@ -4295,4 +4310,8 @@
             <flag name="end" value="4" />
         </attr>
     </declare-styleable>
+
+    <declare-styleable name="ActionBar_LayoutParams">
+        <attr name="layout_gravity" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 47bb5f8..d704366 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1357,6 +1357,7 @@
   <public type="attr" name="dividerVertical" />
   <public type="attr" name="buttonGroupStyle" />
   <public type="attr" name="alertDialogButtonGroupStyle" />
+  <public type="attr" name="homeAsUpIndicator" />
 
   <public type="anim" name="animator_fade_in" />
   <public type="anim" name="animator_fade_out" />
@@ -1415,5 +1416,6 @@
   <public type="attr" name="actionModeCutDrawable" />
   <public type="attr" name="actionModeCopyDrawable" />
   <public type="attr" name="actionModePasteDrawable" />
-
+  <public type="attr" name="textEditPasteWindowLayout" />
+  <public type="attr" name="textEditNoPasteWindowLayout" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8b9bc43..b427a0e 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1231,6 +1231,11 @@
     <string name="permdesc_sdcardWrite" product="default">Allows an application to write to the SD card.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_mediaStorageWrite" product="default">modify/delete internal media storage contents</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_mediaStorageWrite" product="default">Allows an application to modify the contents of the internal media storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_cache_filesystem">access the cache filesystem</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_cache_filesystem">Allows an application to read and write the cache filesystem.</string>
@@ -1961,9 +1966,12 @@
     <!-- Item on EditText context menu. This action is used to cut selected the text into the clipboard. -->
     <string name="copy">Copy</string>
 
-    <!-- Item on EditText context menu. This action is used t o paste from the clipboard into the eidt field -->
+    <!-- Item on EditText context menu. This action is used to paste from the clipboard into the eidt field -->
     <string name="paste">Paste</string>
 
+    <!-- Text displayed in a popup dialog in TextEdit when the clipboard is empty. 'paste' is used otherwise. [CHAR LIMIT=20] -->
+    <string name="pasteDisabled">Nothing to paste</string>
+
     <!-- Item on EditText context menu. This action is used to copy a URL from the edit field into the clipboard. -->
     <string name="copyUrl">Copy URL</string>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 61167b5..adf1715 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -403,6 +403,8 @@
         <item name="android:textSelectHandleLeft">?android:attr/textSelectHandleLeft</item>
         <item name="android:textSelectHandleRight">?android:attr/textSelectHandleRight</item>
         <item name="android:textSelectHandle">?android:attr/textSelectHandle</item>
+        <item name="android:textEditPasteWindowLayout">?android:attr/textEditPasteWindowLayout</item>
+        <item name="android:textEditNoPasteWindowLayout">?android:attr/textEditNoPasteWindowLayout</item>
     </style>
     
     <style name="Widget.TextView.ListSeparator">
@@ -909,7 +911,7 @@
 
     <style name="Widget.ActionBar">
         <item name="android:background">@android:drawable/action_bar_background</item>
-        <item name="android:displayOptions">useLogo</item>
+        <item name="android:displayOptions">useLogo|showHome|showTitle</item>
         <item name="android:divider">@android:drawable/action_bar_divider</item>
         <item name="android:height">?android:attr/actionBarSize</item>
         <item name="android:paddingLeft">0dip</item>
@@ -1534,6 +1536,7 @@
         <item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item>
         <item name="android:background">@null</item>
         <item name="android:divider">?android:attr/dividerVertical</item>
+        <item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_dark</item>
     </style>
 
     <!-- Light widget styles -->
@@ -1786,6 +1789,7 @@
         <item name="android:titleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Title</item>
         <item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item>
         <item name="android:background">@null</item>
+        <item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_light</item>
     </style>
 
     <!-- Animation Styles -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 552e7e5..eeefa9e 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -166,6 +166,8 @@
         <item name="textSelectHandleRight">@android:drawable/text_select_handle_right</item>
         <item name="textSelectHandle">@android:drawable/text_select_handle_middle</item>
         <item name="textSelectHandleWindowStyle">@android:style/Widget.TextSelectHandle</item>
+        <item name="textEditPasteWindowLayout">@android:layout/text_edit_paste_window</item>
+        <item name="textEditNoPasteWindowLayout">@android:layout/text_edit_no_paste_window</item>
 
         <!-- Widget styles -->
         <item name="absListViewStyle">@android:style/Widget.AbsListView</item>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 439fc90..f458576 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -58,6 +58,10 @@
         <group gid="sdcard_rw" />
     </permission>
 
+    <permission name="android.permission.WRITE_MEDIA_STORAGE" >
+        <group gid="media_rw" />
+    </permission>
+
     <permission name="android.permission.ACCESS_USB" >
         <group gid="usb" />
     </permission>
diff --git a/docs/html/sdk/adding-components.jd b/docs/html/sdk/adding-components.jd
index 63c577e..755f200 100644
--- a/docs/html/sdk/adding-components.jd
+++ b/docs/html/sdk/adding-components.jd
@@ -6,7 +6,7 @@
 <div id="qv">
 <h2>Quickview</h2>
 <ul>
-  <li>Use the Android SDK and AVD Manager to 
+  <li>Use the Android SDK and AVD Manager to
    set up your SDK and keep it up-to-date.</li>
 </ul>
 
@@ -25,7 +25,7 @@
 <p>Adding and updating components in your Android SDK is fast and easy. To
 perform an update, use the <strong>Android SDK and AVD Manager</strong> to
 install or update the individual SDK components that you need. The Android SDK
-and AVD Manager tool is included in the <a href="index.html">Android SDK 
+and AVD Manager tool is included in the <a href="index.html">Android SDK
 download</a>.</p>
 
 <p>It only takes a couple of clicks to install individual versions of the
@@ -53,19 +53,19 @@
 href="{@docRoot}sdk/tools-notes.html">SDK Tools</a> document for ADT
 Plugin compatibility.</p>
 
-<div style="TEXT-ALIGN:left; width:600px;"> 
-<img src="{@docRoot}images/sdk_manager_packages.png" 
-style="padding-bottom:0;margin-bottom:0;" /> 
+<div style="TEXT-ALIGN:left; width:600px;">
+<img src="{@docRoot}images/sdk_manager_packages.png"
+style="padding-bottom:0;margin-bottom:0;" />
 <p class="caption" style="margin:0 0 1.5em 1em;padding:0 0 0
-1em;"><strong>Figure 1.</strong> The Android SDK and AVD Manager's 
+1em;"><strong>Figure 1.</strong> The Android SDK and AVD Manager's
 <strong>Available Packages</strong>
 panel, which shows the SDK components that are
 available for you to download into your environment. </p>
-</div> 
+</div>
 
 <h2 id="launching">Launching the Android SDK and AVD Manager</h2>
 
-<p>The Android SDK and AVD Manager is the tool that you use to install and 
+<p>The Android SDK and AVD Manager is the tool that you use to install and
 upgrade SDK components in your development environment. </p>
 
 <p>You can access the tool in any of three ways:</p>
@@ -83,15 +83,15 @@
 
 <ol>
 <li>Open Eclipse</li>
-<li>Select <strong>Window</strong> &gt; <strong>Android SDK and AVD 
+<li>Select <strong>Window</strong> &gt; <strong>Android SDK and AVD
 Manager</strong>.</li>
 </ol>
 
-<h4>Launching from the setup script (Windows only)</h4>
+<h4>Launching from the SDK Manager script (Windows only)</h4>
 
 <p>For Windows only, the SDK includes a script that invokes the Android SDK and
-AVD Manager. To launch the tool using the script, double-click "SDK
-Setup.exe" at the root of the the SDK directory.</p>
+AVD Manager. To launch the tool using the script, double-click {@code SDK
+Manager.exe} at the root of the the SDK directory.</p>
 
 <h4>Launching from a command line</h4>
 
@@ -100,37 +100,39 @@
 
 <ol>
 <li>Navigate to the <code>&lt;<em>sdk</em>&gt;/tools/</code> directory.</li>
-<li>Execute the {@code android} tool command with no options. 
+<li>Execute the {@code android} tool command with no options.
   <pre style="width:400px">$ android</pre></li>
 </ol>
 
 
 <h2 id="InstallingComponents">Installing SDK Components</h2>
 
-<p class="caution"><strong>Important:</strong> Before you install SDK components, 
-we recommend that you disable any antivirus programs that may be running on
-your computer.</p>
+<p class="caution"><strong>Caution:</strong> Before you install SDK components,
+we recommend that you disable any antivirus software that may be running on
+your computer. There are cases in which antivirus software on Windows is known to interfere with the
+installation process, so we suggest you disable your antivirus until installation is
+complete.</p>
 
 <p>Follow these steps to install new SDK components in your environment:</p>
 
 <ol>
   <li>Launch the Android SDK and AVD Manager as described in the section above.</li>
   <li>Select <strong>Available Packages</strong> in the left panel.
-  This will reveal all of the components that are currently available for download 
+  This will reveal all of the components that are currently available for download
   from the SDK repository.</li>
   <li>Select the component(s) you'd like to install and click <strong>Install
-  Selected</strong>. If you aren't sure which packages to select, read <a 
+  Selected</strong>. If you aren't sure which packages to select, read <a
   href="installing.html#which">Which components do I need?</a>.</li>
   <li>Verify and accept the components you want and click <strong>Install
   Accepted</strong>. The components will now be installed into your existing
   Android SDK directories.</li>
 </ol>
 
-<p>New platforms are automatically saved into the 
+<p>New platforms are automatically saved into the
 <code>&lt;<em>sdk</em>&gt;/platforms/</code> directory of your SDK;
 new add-ons are saved in the <code>&lt;<em>sdk</em>&gt;/add-ons/</code>
-directory; samples are saved in the 
-<code>&lt;<em>sdk</em>&gt;/samples/android-&lt;<em>level</em>&gt;/</code>; 
+directory; samples are saved in the
+<code>&lt;<em>sdk</em>&gt;/samples/android-&lt;<em>level</em>&gt;/</code>;
 and new documentation is saved in the existing
 <code>&lt;<em>sdk</em>&gt;/docs/</code> directory (old docs are replaced).</p>
 
@@ -184,10 +186,10 @@
 <h2 id="AddingSites">Adding New Sites</h2>
 
 <p>By default, <strong>Available Packages</strong> only shows the default
-repository site, which offers platforms, SDK tools, documentation, the 
-Google APIs Add-on, and other components. You can add other sites that host 
+repository site, which offers platforms, SDK tools, documentation, the
+Google APIs Add-on, and other components. You can add other sites that host
 their own Android SDK add-ons, then download the SDK add-ons
-from those sites.</p>	
+from those sites.</p>
 
 <p>For example, a mobile carrier or device manufacturer might offer additional
 API libraries that are supported by their own Android-powered devices. In order
@@ -199,7 +201,7 @@
 
 <ol>
   <li>Select <strong>Available Packages</strong> in the left panel.</li>
-  <li>Click <strong>Add Site</strong> and enter the URL of the 
+  <li>Click <strong>Add Site</strong> and enter the URL of the
 {@code repository.xml} file. Click <strong>OK</strong>.</li>
 </ol>
 <p>Any SDK components available from the site will now be listed under
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 7016eee..2e59801 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -1,27 +1,27 @@
 page.title=Android SDK
 sdk.redirect=0
 
-sdk.win_download=android-sdk_r07-windows.zip
-sdk.win_bytes=23669664
-sdk.win_checksum=69c40c2d2e408b623156934f9ae574f0
+sdk.win_installer=installer_r08-windows.exe
+sdk.win_installer_bytes=TODO
+sdk.win_installer_checksum=TODO
 
-sdk.mac_download=android-sdk_r07-mac_x86.zip
-sdk.mac_bytes=19229546
-sdk.mac_checksum=0f330ed3ebb36786faf6dc72b8acf819
+sdk.win_download=android-sdk_r08-windows.zip
+sdk.win_bytes=TODO
+sdk.win_checksum=TODO
 
-sdk.linux_download=android-sdk_r07-linux_x86.tgz
-sdk.linux_bytes=17114517
-sdk.linux_checksum=e10c75da3d1aa147ddd4a5c58bfc3646
+sdk.mac_download=android-sdk_r08-mac_x86.zip
+sdk.mac_bytes=TODO
+sdk.mac_checksum=TODO
+
+sdk.linux_download=android-sdk_r08-linux_x86.tgz
+sdk.linux_bytes=TODO
+sdk.linux_checksum=TODO
 
 @jd:body
 
 
 <h2 id="quickstart">Quick Start</h2>
 
-<p>The steps below provide an overview of how to get started with the Android
-SDK. For detailed instructions, start with the <a
-href="{@docRoot}sdk/installing.html">Installing the SDK</a> guide. </p>
-
 <p><strong>1. Prepare your development computer</strong></p>
 
 <p>Read the <a href="{@docRoot}sdk/requirements.html">System Requirements</a>
@@ -34,38 +34,37 @@
 
 <p><strong>2. Download and install the SDK starter package</strong></p>
 
-<p>Select a starter package from the table at the top of this page and download
-it to your development computer. To install the SDK, simply unpack the starter
-package to a safe location and then add the location to your PATH. </p>
+<p>Download a starter package from the table above onto your development computer.
+If you're using Windows, we recommend that you download the installer (the {@code .exe} file),
+which will launch a Wizard to guide you through the installation and check your computer for
+required software. Otherwise, download the SDK starter package ({@code .zip} or {@code .tgz})
+appropriate for your system, unpack it to a safe location, then add the location to your PATH
+environment variable. </p>
 
 <p><strong>3. Install the ADT Plugin for Eclipse</strong></p>
 
-<p>If you are developing in Eclipse, set up a remote update site at
-<code>https://dl-ssl.google.com/android/eclipse/</code>. Install the Android 
-Development Tools (ADT) Plugin, restart Eclipse, and set the "Android" 
-preferences in Eclipse to point to the SDK install location. For detailed
-instructions, see <a href="{@docRoot}sdk/eclipse-adt.html">ADT Plugin 
+<p>If you are developing in Eclipse, add a new remote update site with the URL
+<code>https://dl-ssl.google.com/android/eclipse/</code>. Install the Android
+Development Tools (ADT) Plugin from that site, restart Eclipse, and set the "Android"
+preferences in Eclipse to point to the Android SDK directory (installed in the previous step). For
+detailed instructions to setup Eclipse, see <a href="{@docRoot}sdk/eclipse-adt.html">ADT Plugin
 for Eclipse</a>.</p>
 
 <p><strong>4. Add Android platforms and other components to your SDK</strong></p>
 
-<p>Use the Android SDK and AVD Manager, included in the SDK starter package, to
-add one or more Android platforms (for example, Android 1.6 or Android 2.2) and
-other components to your SDK. If you aren't sure what to add, see <a
+<p>Launch the <em>Android SDK and AVD Manager</em> by executing {@code SDK Manager.exe} (Windows) or
+{@code android} (Mac/Linux) from the SDK's {@code tools/} directory (if you used the Windows
+installer, this is launched for you when the Wizard is complete). Add some Android platforms
+(such as Android 1.6 and Android 2.3) and other components (such as documentation) to your SDK. If
+you aren't sure what to add, see <a
 href="installing.html#which">Which components do I need?</a></p>
 
-<p>To launch the Android SDK and AVD Manager on Windows, execute <code>SDK
-Setup.exe</code>, at the root of the SDK directory. On Mac OS X or Linux,
-execute the <code>android</code> tool in the <code>&lt;sdk&gt;/tools/</code>
-folder. For detailed instructions, see <a
-href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a>.</p>
-
 <p><strong>Done!</strong></p>
 
-<p>If you are new to Android, you can use the <a
-href="{@docRoot}resources/tutorials/hello-world.html">Hello World</a> tutorial to
-get started quickly. <a href="{@docRoot}sdk/installing.html#NextSteps">Next
-Steps</a> offers other suggestions of how to begin.</p>
+<p>To write your first Android application, see the <a
+href="{@docRoot}resources/tutorials/hello-world.html">Hello World</a> tutorial. Also see <a
+href="{@docRoot}sdk/installing.html#NextSteps">Next
+Steps</a> for other suggestions about how to get started.</p>
 
-<p>For a more detailed guide to installing and setting up the SDK, read <a 
+<p>For a more detailed guide to installing and setting up the SDK, read <a
 href="installing.html">Installing the SDK</a>.</p>
diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd
index 73190a0..8484bea 100644
--- a/docs/html/sdk/installing.jd
+++ b/docs/html/sdk/installing.jd
@@ -29,20 +29,20 @@
 </div>
 </div>
 
-<p>This page describes how to install the Android SDK 
+<p>This page describes how to install the Android SDK
 and set up your development environment for the first time.</p>
 
-<p>If you encounter any problems during installation, see the 
+<p>If you encounter any problems during installation, see the
 <a href="#troubleshooting">Troubleshooting</a> section at the bottom of
 this page.</p>
 
 <h4>Updating?</h4>
 
-<p>If you are currently using the Android 1.6 SDK or later and want to update 
-to the latest tools or platforms, you do not need to install a new SDK. Instead, 
-you can simply update the individual components in your SDK using the 
-Android SDK and AVD Manager tool. For information about how to do that, see <a 
-href="{@docRoot}sdk/adding-components.html#UpdatingComponents">Updating SDK 
+<p>If you are currently using the Android 1.6 SDK or later and want to update
+to the latest tools or platforms, you do not need to install a new SDK. Instead,
+you can simply update the individual components in your SDK using the
+Android SDK and AVD Manager tool. For information about how to do that, see <a
+href="{@docRoot}sdk/adding-components.html#UpdatingComponents">Updating SDK
 Components</a></p>
 
 <p>If you are using Android 1.5 SDK or earlier, you should install a new SDK as
@@ -54,65 +54,71 @@
 
 <p>Before getting started with the Android SDK, take a moment to confirm that
 your development computer meets the <a href="requirements.html">System
-Requirements</a>. In particular, you may need to install the <a 
-href="http://java.sun.com/javase/downloads/index.jsp">JDK</a> before 
+Requirements</a>. In particular, you may need to install the <a
+href="http://java.sun.com/javase/downloads/index.jsp">JDK</a> before
 continuing, if it's not already installed on your computer. </p>
 
 <p>If you will be developing in Eclipse with the Android Development
 Tools (ADT) Plugin &mdash; the recommended path if you are new to
 Android &mdash; make sure that you have a suitable version of Eclipse
-installed on your computer (3.4 or newer is recommended). If you need 
-to install Eclipse, you can download it from this location: </p> 
- 
+installed on your computer (3.4 or newer is recommended). If you need
+to install Eclipse, you can download it from this location: </p>
+
 <p style="margin-left:2em;"><a href=
-"http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a></p> 
- 
-<p>A Java or RCP version of Eclipse is recommended. For Eclipse 3.5, the 
-"Eclipse Classic" version is recommended.</p> 
+"http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a></p>
+
+<p>A Java or RCP version of Eclipse is recommended. For Eclipse 3.5, the
+"Eclipse Classic" version is recommended.</p>
 
 
 <h2 id="Installing">Step 2. Downloading the SDK Starter Package</h2>
 
 <p>The first step in setting up your environment for developing Android applications
 is downloading the Android SDK starter package. The starter package is not a full
-development environment &mdash; it includes only the core SDK Tools, which you can 
-use to download the rest of the SDK components. </p>
+development environment &mdash; it includes only the core SDK Tools, which you can
+use to download the rest of the SDK components (such as the platform system images). </p>
 
 <p>You can get the latest version of the SDK starter package from the <a
 href="{@docRoot}sdk/index.html">SDK download page</a>. Make sure to download the
 package that is appropriate for your development computer.</p>
 
-<p>After downloading, unpack the Android SDK archive to a safe location on your
-machine. By default, the SDK files are unpacked into a directory named
-<code>android-sdk-&lt;machine-platform&gt;</code>. Make a note of the name and
-location of the unpacked SDK directory on your system &mdash; you will need to
-refer to the SDK directory later, when setting up the ADT plugin or when using
-the SDK tools.</p>
+<p class="note"><strong>Note:</strong> If you're using Windows, we recommend that you download
+the SDK installer (the {@code .exe} file from the download table). It will guide you through the
+installation process and check your computer for the required software.</p>
 
-<p>Optionally, you may want to add the location of the SDK's primary
-<code>tools</code> directory to your system <code>PATH</code>. The primary
-<code>tools/</code> directory is located at the root of the SDK folder. Adding
-<code>tools</code> to your path lets you run Android Debug Bridge (adb) and the
-other command line <a
+<p>If you downloaded a {@code .zip} of {@code .tgz} (instead of using the SDK installer), unpack the
+Android SDK archive to a safe location on your machine. By default, the SDK files are unpacked into
+a directory named <code>android-sdk-&lt;machine-platform&gt;</code>.</p>
+
+<p>Make a note of the name and
+location of the unpacked SDK directory on your system &mdash; you will need to
+refer to the SDK directory later, when setting up the ADT plugin and when using
+the SDK tools from command line.</p>
+
+<p>Optionally, you might want to add the location of the SDK's primary
+<code>tools</code> directory and the additional {@code platform-tools/} directory  to your system
+<code>PATH</code>. Both tool directories are located at the root of the SDK folder. Adding
+<code>tools/</code> and {@code platform-tools/} to your path lets you run Android Debug Bridge (adb)
+and the other command line <a
 href="{@docRoot}guide/developing/tools/index.html">tools</a> without needing to
-supply the full path to the tools directory. </p> 
+supply the full path to the tool directories. </p>
 
 <ul>
     <li>On Linux, edit your <code>~/.bash_profile</code> or <code>~/.bashrc</code> file. Look
     for a line that sets the PATH environment variable and add the
-    full path to the <code>tools/</code> directory to it. If you don't 
+    full path to the <code>tools/</code> and {@code platform-tools/} directories to it. If you don't
     see a line setting the path, you can add one:</li>
 
-    <ul><code>export PATH=${PATH}:<em>&lt;your_sdk_dir&gt;</em>/tools</code></ul>
+    <ul><code>export PATH=${PATH}:&lt;your_sdk_dir&gt;/tools:&lt;your_sdk_dir&gt;/platform-tools</code></ul>
 
     <li>On a Mac OS X, look in your home directory for <code>.bash_profile</code> and
-    proceed as for Linux. You can create the <code>.bash_profile</code> if 
+    proceed as for Linux. You can create the <code>.bash_profile</code> if
     you haven't already set one up on your machine. </li>
 
-    <li>On Windows, right-click on My Computer, and select Properties.  
+    <li>On Windows, right-click on My Computer, and select Properties.
   Under the Advanced tab, hit the Environment Variables button, and in the
-  dialog that comes up, double-click on Path (under System Variables). Add the full path to the 
-  <code>tools/</code> directory to the path. </li>
+  dialog that comes up, double-click on Path (under System Variables). Add the full path to the
+  <code>tools/</code> and {@code platform-tools/} directories to the path. </li>
   </ul>
 
 <p>If you will be using the Eclipse IDE as your development environment, the
@@ -203,11 +209,11 @@
 <code>com.google.android.maps</code> library. You can also add additional
 repositories, so that you can download other SDK add-ons, where available. </li>
 
-<li><strong>USB Driver for Windows</strong> &mdash; Contains driver files 
+<li><strong>USB Driver for Windows</strong> &mdash; Contains driver files
 that you can install on your Windows computer, so that you can run and debug
 your applications on an actual device. You <em>do not</em> need the USB driver unless
 you plan to debug your application on an actual Android-powered device. If you
-develop on Mac OS X or Linux, you do not need a special driver to debug 
+develop on Mac OS X or Linux, you do not need a special driver to debug
 your application on an Android-powered device.</li>
 
 <li><strong>Samples</strong> &mdash; Contains the sample code and apps available
@@ -226,15 +232,15 @@
 components for download, and then install the selected components in your SDK
 environment. </p>
 
-<div style="TEXT-ALIGN:left;width:600px;"> 
-<img src="/images/sdk_manager_packages.png" 
-style="padding-bottom:0;margin-bottom:0;" /> 
+<div style="TEXT-ALIGN:left;width:600px;">
+<img src="/images/sdk_manager_packages.png"
+style="padding-bottom:0;margin-bottom:0;" />
 <p class="caption" style="margin:0 0 1.5em 1em;padding:0 0 0
-1em;"><strong>Figure 1.</strong> The Android SDK and AVD Manager's 
+1em;"><strong>Figure 1.</strong> The Android SDK and AVD Manager's
 <strong>Available Packages</strong>
 panel, which shows the SDK components that are
 available for you to download into your environment. </p>
-</div> 
+</div>
 
 
 <h3 id="which">Which components do I need?</h3>
@@ -257,8 +263,8 @@
 <td style="font-size:.9em;background-color:#FFE;color:gray">SDK Tools</td>
 <td style="font-size:.9em;background-color:#FFE;color:gray">If you've installed
 the SDK starter package, then you already have this component preinstalled. The
-SDK Tools component is required &mdash; you can't develop or build an application 
-without it. </td>
+SDK Tools and the SDK Platform-tools components are required &mdash; you can't develop or build an
+application without these. Make sure you keep these up to date.</td>
 </tr>
 
 <tr>
@@ -324,8 +330,8 @@
 to add components, see the <a href="{@docRoot}sdk/adding-components.html">Adding
 SDK Components</a> document. </p>
 
-<p>For revision notes and other detailed information about individual SDK 
-components, see the documents listed under "Downloadable SDK Components" in 
+<p>For revision notes and other detailed information about individual SDK
+components, see the documents listed under "Downloadable SDK Components" in
 the navigation at left.</p>
 
 
@@ -335,7 +341,7 @@
 and add-ons that you need, open the SDK directory and take a look at what's
 inside.</p>
 
-<p>The table below describes the full SDK directory contents, with components 
+<p>The table below describes the full SDK directory contents, with components
 installed. </p>
 
 <table>
@@ -351,10 +357,19 @@
 <tr>
 <td colspan="3"><code>docs/</code></td>
 <td>A full set of documentation in HTML format, including the Developer's Guide,
-API Reference, and other information. To read the documentation, load the 
+API Reference, and other information. To read the documentation, load the
 file <code>offline.html</code> in a web browser.</td>
 </tr>
 <tr>
+<td colspan="3"><code>platform-tools/</code></td>
+<td>Contains development tools that may be updated with each platform release (from the <em>Android
+SDK Platform-tools</em> component). Tools in here include {@code adb}, {@code dexdump}, and others
+others that you don't typically use directly. These tools are separate from the generic development
+tools in the {@code tools/} directory, because these tools may be updated in order to support new
+features in the latest Android platform, whereas the other tools have no dependencies on the
+platform version.</td>
+</tr>
+<tr>
 <td colspan="3"><code>platforms/</code></td>
 <td>Contains a set of Android platform versions that you can develop
 applications against, each in a separate directory.  </td>
@@ -362,7 +377,7 @@
 <tr>
 <td style="width:2em;border-bottom-color:white;"></td>
 <td colspan="2"><code><em>&lt;platform&gt;</em>/</code></td>
-<td>Platform version directory, for example "android-1.6". All platform version 
+<td>Platform version directory, for example "android-1.6". All platform version
 directories contain a similar set of files and subdirectory structure.</td>
 </tr>
 
@@ -376,8 +391,8 @@
 <td style="width:2em;border-bottom-color:white;"></td>
 <td style="width:2em;border-bottom-color:white;"></td>
 <td><code>images/</code></td>
-<td>Storage area for default disk images, including the Android system image, 
-the default userdata image, the default ramdisk image, and more. The images 
+<td>Storage area for default disk images, including the Android system image,
+the default userdata image, the default ramdisk image, and more. The images
 are used in emulator sessions.</td>
 </tr>
 <tr>
@@ -397,7 +412,8 @@
 <td style="width:2em;border-bottom-color:white;"></td>
 <td style="width:2em;border-bottom-color:white;"></td>
 <td><code>tools/</code></td>
-<td>Any development tools that are specific to the platform version.</td>
+<td>This directory is used only by SDK Tools r7 and below for development tools that are specific to
+this platform version&mdash;it's not used by SDK Tools r8 and above.</td>
 </tr>
 <tr>
 <td style="width:2em;"></td>
@@ -411,18 +427,21 @@
 <td>Sample code and apps that are specific to platform version.</td>
 </tr>
 <td colspan="3"><code>tools/</code></td>
-<td>Contains the set of development and profiling tools available to you, such
-as the emulator, the <code>android</code> tool, adb, ddms, and more.</td>
+<td>Contains the set of development and profiling tools that are platform-independent, such
+as the emulator, the AVD and SDK Manager, adb, ddms, hierarchyviewer and more. The tools in
+this directory may be updated at any time (from the <em>Android SDK Tools</em> component),
+independent of platform releases, whereas the tools in {@code platform-tools/} may be updated based
+on the latest platform release.</td>
 </tr>
 <tr>
 <td colspan="3"><code>SDK Readme.txt</code></td>
-<td>A file that explains how to perform the initial setup of your SDK, 
-including how to launch the Android SDK and AVD Manager tool on all 
+<td>A file that explains how to perform the initial setup of your SDK,
+including how to launch the Android SDK and AVD Manager tool on all
 platforms</td>
 </tr>
 <tr>
-<td colspan="3"><code>SDK Setup.exe</code></td>
-<td>Windows SDK only. A shortcut that launches the Android SDK and AVD 
+<td colspan="3"><code>SDK Manager.exe</code></td>
+<td>Windows SDK only. A shortcut that launches the Android SDK and AVD
 Manager tool, which you use to add components to your SDK. </td>
 </tr>
 <!--<tr>
@@ -447,7 +466,7 @@
 </li>
 </ul>
 
-<p class="caution">Following the Hello World tutorial is an essential 
+<p class="caution">Following the Hello World tutorial is an essential
 first step in getting started with Android development. </p>
 
 <p><strong>Learn about Android</strong></p>
@@ -481,20 +500,20 @@
 
 <ul>
   <li>The <a href="{@docRoot}resources/tutorials/notepad/index.html">
-  Notepad Tutorial</a> shows you how to build a full Android application 
-  and provides  helpful commentary on the Android system and API. The 
+  Notepad Tutorial</a> shows you how to build a full Android application
+  and provides  helpful commentary on the Android system and API. The
   Notepad tutorial helps you bring together the important design
-  and architectural concepts in a moderately complex application. 
+  and architectural concepts in a moderately complex application.
   </li>
 </ul>
-<p class="caution">Following the Notepad tutorial is an excellent 
+<p class="caution">Following the Notepad tutorial is an excellent
 second step in getting started with Android development. </p>
 
 <p><strong>Explore some code</strong></p>
 
 <ul>
   <li>The Android SDK includes sample code and applications for each platform
-version. You can browse the samples in the <a 
+version. You can browse the samples in the <a
 href="{@docRoot}resources/index.html">Resources</a> tab or download them
 into your SDK using the Android SDK and AVD Manager. Once you've downloaded the
 samples, you'll find them in
@@ -517,7 +536,7 @@
 
 <ul>
   <li>If you need help installing and configuring Java on your
-    development machine, you might find these resources helpful: 
+    development machine, you might find these resources helpful:
     <ul>
       <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/Java </a></li>
       <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/JavaInstallation</a></li>
@@ -537,7 +556,7 @@
       eclipse.org (<a
       href="http://www.eclipse.org/downloads/">http://www.eclipse.org/
       downloads/</a>). A Java or RCP version of Eclipse is recommended.</li>
-      <li>Follow the steps given in previous sections to install the SDK 
+      <li>Follow the steps given in previous sections to install the SDK
       and the ADT plugin. </li>
     </ol>
   </li>
diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java
index 0477d75..5fe69cd 100644
--- a/graphics/java/android/renderscript/RenderScriptGL.java
+++ b/graphics/java/android/renderscript/RenderScriptGL.java
@@ -141,6 +141,13 @@
         nContextSetSurface(w, h, mSurface);
     }
 
+    public int getHeight() {
+        return mHeight;
+    }
+
+    public int getWidth() {
+        return mWidth;
+    }
 
     void pause() {
         validate();
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
index 5959be4..73f42de 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -76,78 +76,5 @@
         rs.nScriptCSetScript(pgm, 0, pgmLength);
         return rs.nScriptCCreate();
     }
-
-    public static class Builder extends Script.Builder {
-        byte[] mProgram;
-        int mProgramLength;
-
-        public Builder(RenderScript rs) {
-            super(rs);
-        }
-
-        public void setScript(String s) {
-            try {
-                mProgram = s.getBytes("UTF-8");
-                mProgramLength = mProgram.length;
-            } catch (java.io.UnsupportedEncodingException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        public void setScript(Resources resources, int id) {
-            InputStream is = resources.openRawResource(id);
-            try {
-                try {
-                    setScript(is);
-                } finally {
-                    is.close();
-                }
-            } catch(IOException e) {
-                throw new Resources.NotFoundException();
-            }
-        }
-
-        public void setScript(InputStream is) throws IOException {
-            byte[] buf = new byte[1024];
-            int currentPos = 0;
-            while(true) {
-                int bytesLeft = buf.length - currentPos;
-                if (bytesLeft == 0) {
-                    byte[] buf2 = new byte[buf.length * 2];
-                    System.arraycopy(buf, 0, buf2, 0, buf.length);
-                    buf = buf2;
-                    bytesLeft = buf.length - currentPos;
-                }
-                int bytesRead = is.read(buf, currentPos, bytesLeft);
-                if (bytesRead <= 0) {
-                    break;
-                }
-                currentPos += bytesRead;
-            }
-            mProgram = buf;
-            mProgramLength = currentPos;
-        }
-
-        static synchronized ScriptC internalCreate(Builder b) {
-            b.mRS.nScriptCBegin();
-
-            android.util.Log.e("rs", "len = " + b.mProgramLength);
-            b.mRS.nScriptCSetScript(b.mProgram, 0, b.mProgramLength);
-
-            int id = b.mRS.nScriptCCreate();
-            ScriptC obj = new ScriptC(id, b.mRS);
-            return obj;
-        }
-
-        public void addDefine(String name, int value) {}
-        public void addDefine(String name, float value) {}
-        public void addDefines(Class cl) {}
-        public void addDefines(Object o) {}
-        void addDefines(Field[] fields, int mask, Object o) {}
-
-        public ScriptC create() {
-            return internalCreate(this);
-        }
-    }
 }
 
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index a1ce113..3d77278 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -48,8 +48,6 @@
     virtual status_t        setAudioStreamType(int type) = 0;
     virtual status_t        setLooping(int loop) = 0;
     virtual status_t        setVolume(float leftVolume, float rightVolume) = 0;
-    virtual status_t        suspend() = 0;
-    virtual status_t        resume() = 0;
     virtual status_t        setAuxEffectSendLevel(float level) = 0;
     virtual status_t        attachAuxEffect(int effectId) = 0;
 
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index eae0d7b..2d55a55 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -120,8 +120,6 @@
     virtual status_t    reset() = 0;
     virtual status_t    setLooping(int loop) = 0;
     virtual player_type playerType() = 0;
-    virtual status_t    suspend() { return INVALID_OPERATION; }
-    virtual status_t    resume() { return INVALID_OPERATION; }
 
     virtual void        setNotifyCallback(void* cookie, notify_callback_f notifyFunc) {
                             mCookie = cookie; mNotify = notifyFunc; }
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 207191d..88b0c3e 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -169,8 +169,6 @@
             status_t        invoke(const Parcel& request, Parcel *reply);
             status_t        setMetadataFilter(const Parcel& filter);
             status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
-            status_t        suspend();
-            status_t        resume();
             status_t        setAudioSessionId(int sessionId);
             int             getAudioSessionId();
             status_t        setAuxEffectSendLevel(float level);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index da86da4..ed7f53d1 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1771,12 +1771,14 @@
      *
      * @return ssize_t Either a >= 0 table index or a negative error code.
      */
-    ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag=false,
-            uint32_t* outSpecFlags=NULL, ResTable_config* outConfig=NULL) const;
+    ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag = false,
+                    uint16_t density = 0,
+                    uint32_t* outSpecFlags = NULL,
+                    ResTable_config* outConfig = NULL) const;
 
     inline ssize_t getResource(const ResTable_ref& res, Res_value* outValue,
             uint32_t* outSpecFlags=NULL) const {
-        return getResource(res.ident, outValue, false, outSpecFlags, NULL);
+        return getResource(res.ident, outValue, false, 0, outSpecFlags, NULL);
     }
 
     ssize_t resolveReference(Res_value* inOutValue,
diff --git a/libs/rs/java/Balls/Android.mk b/libs/rs/java/Balls/Android.mk
new file mode 100644
index 0000000..5b65628
--- /dev/null
+++ b/libs/rs/java/Balls/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2008 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.
+#
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Balls
+
+include $(BUILD_PACKAGE)
+
+endif
diff --git a/libs/rs/java/Balls/AndroidManifest.xml b/libs/rs/java/Balls/AndroidManifest.xml
new file mode 100644
index 0000000..2fffc5f
--- /dev/null
+++ b/libs/rs/java/Balls/AndroidManifest.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.balls">
+    <application 
+        android:label="Balls"
+        android:icon="@drawable/test_pattern">
+        <activity android:name="Balls"
+                  android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/libs/rs/java/Balls/res/drawable/flares.png b/libs/rs/java/Balls/res/drawable/flares.png
new file mode 100644
index 0000000..3a5c970
--- /dev/null
+++ b/libs/rs/java/Balls/res/drawable/flares.png
Binary files differ
diff --git a/libs/rs/java/Balls/res/drawable/test_pattern.png b/libs/rs/java/Balls/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/libs/rs/java/Balls/res/drawable/test_pattern.png
Binary files differ
diff --git a/libs/rs/java/Balls/src/com/android/balls/Balls.java b/libs/rs/java/Balls/src/com/android/balls/Balls.java
new file mode 100644
index 0000000..5957c94
--- /dev/null
+++ b/libs/rs/java/Balls/src/com/android/balls/Balls.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 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.balls;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+public class Balls extends Activity implements SensorEventListener {
+    //EventListener mListener = new EventListener();
+
+    private static final String LOG_TAG = "libRS_jni";
+    private static final boolean DEBUG  = false;
+    private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+    private BallsView mView;
+    private SensorManager mSensorManager;
+
+    // get the current looper (from your Activity UI thread for instance
+
+
+    public void onSensorChanged(SensorEvent event) {
+        //android.util.Log.d("rs", "sensor: " + event.sensor + ", x: " + event.values[0] + ", y: " + event.values[1] + ", z: " + event.values[2]);
+        synchronized (this) {
+            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+                if(mView != null) {
+                    mView.setAccel(event.values[0], event.values[1], event.values[2]);
+                }
+            }
+        }
+    }
+
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new BallsView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        mSensorManager.registerListener(this,
+                                        mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+                                        SensorManager.SENSOR_DELAY_FASTEST);
+
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onResume();
+        mView.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        Log.e("rs", "onPause");
+
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onPause();
+        mView.onPause();
+
+
+
+        //Runtime.getRuntime().exit(0);
+    }
+
+    @Override
+    protected void onStop() {
+        mSensorManager.unregisterListener(this);
+        super.onStop();
+    }
+
+    static void log(String message) {
+        if (LOG_ENABLED) {
+            Log.v(LOG_TAG, message);
+        }
+    }
+
+
+}
+
diff --git a/libs/rs/java/Balls/src/com/android/balls/BallsRS.java b/libs/rs/java/Balls/src/com/android/balls/BallsRS.java
new file mode 100644
index 0000000..f76a011
--- /dev/null
+++ b/libs/rs/java/Balls/src/com/android/balls/BallsRS.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2008 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.balls;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+public class BallsRS {
+    public static final int PART_COUNT = 800;
+
+    public BallsRS() {
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private ScriptC_balls mScript;
+    private ScriptC_ball_physics mPhysicsScript;
+    private ProgramFragment mPF;
+    private ProgramVertex mPV;
+    private ProgramRaster mPR;
+    private ProgramStore mPS;
+    private ScriptField_Point mPoints;
+    private ScriptField_Point mArcs;
+    private ScriptField_VpConsts mVpConsts;
+
+    void updateProjectionMatrices() {
+        mVpConsts = new ScriptField_VpConsts(mRS, 1);
+        ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
+        Matrix4f mvp = new Matrix4f();
+        mvp.loadOrtho(0, mRS.getWidth(), mRS.getHeight(), 0, -1, 1);
+        i.MVP = mvp;
+        mVpConsts.set(i, 0, true);
+    }
+
+    private void createProgramRaster() {
+        ProgramRaster.Builder b = new ProgramRaster.Builder(mRS);
+        mPR = b.create();
+        mScript.set_gPR(mPR);
+    }
+
+    private void createProgramVertex() {
+        updateProjectionMatrices();
+
+        ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(mRS);
+        String t =  "varying vec4 varColor;\n" +
+                    "void main() {\n" +
+                    "  vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n" +
+                    "  pos.xy = ATTRIB_position;\n" +
+                    "  gl_Position = UNI_MVP * pos;\n" +
+                    "  varColor = ATTRIB_color;\n" +
+                    "  gl_PointSize = ATTRIB_size;\n" +
+                    "}\n";
+        sb.setShader(t);
+        sb.addConstant(mVpConsts.getType());
+        sb.addInput(mPoints.getElement());
+        ProgramVertex pvs = sb.create();
+        pvs.bindConstants(mVpConsts.getAllocation(), 0);
+        mScript.set_gPV(pvs);
+    }
+
+    private Allocation loadTexture(int id) {
+        final Allocation allocation = Allocation.createFromBitmapResource(mRS, mRes,
+                id, Element.RGB_565(mRS), false);
+        allocation.uploadToTexture(0);
+        return allocation;
+    }
+
+    public void init(RenderScriptGL rs, Resources res, int width, int height) {
+        mRS = rs;
+        mRes = res;
+
+        ProgramFragment.Builder pfb = new ProgramFragment.Builder(rs);
+        pfb.setPointSpriteTexCoordinateReplacement(true);
+        pfb.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
+                           ProgramFragment.Builder.Format.RGBA, 0);
+        pfb.setVaryingColor(true);
+        mPF = pfb.create();
+        rs.contextBindProgramFragment(mPF);
+
+        mPF.bindTexture(loadTexture(R.drawable.flares), 0);
+
+        mPoints = new ScriptField_Point(mRS, PART_COUNT);
+        mArcs = new ScriptField_Point(mRS, PART_COUNT * 2);
+
+        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+        smb.addVertexAllocation(mPoints.getAllocation());
+        smb.addIndexType(Primitive.POINT);
+        Mesh smP = smb.create();
+
+        smb = new Mesh.AllocationBuilder(mRS);
+        smb.addVertexAllocation(mArcs.getAllocation());
+        smb.addIndexType(Primitive.LINE);
+        Mesh smA = smb.create();
+
+        mPhysicsScript = new ScriptC_ball_physics(mRS, mRes, R.raw.ball_physics, true);
+
+        mScript = new ScriptC_balls(mRS, mRes, R.raw.balls, true);
+        mScript.set_partMesh(smP);
+        mScript.set_arcMesh(smA);
+        mScript.set_physics_script(mPhysicsScript);
+        mScript.bind_point(mPoints);
+        mScript.bind_arc(mArcs);
+        mScript.bind_balls1(new ScriptField_Ball(mRS, PART_COUNT));
+        mScript.bind_balls2(new ScriptField_Ball(mRS, PART_COUNT));
+
+        mScript.set_gPF(mPF);
+        createProgramVertex();
+        createProgramRaster();
+
+        mPS = ProgramStore.BLEND_ADD_DEPTH_NO_DEPTH(mRS);
+        mScript.set_gPS(mPS);
+
+        mPhysicsScript.set_gMinPos(new Float2(5, 5));
+        mPhysicsScript.set_gMaxPos(new Float2(width - 5, height - 5));
+
+        mScript.invoke_initParts(width, height);
+
+        mRS.contextBindRootScript(mScript);
+    }
+
+    public void newTouchPosition(float x, float y, float pressure, int id) {
+        mPhysicsScript.set_touchX(x);
+        mPhysicsScript.set_touchY(y);
+        mPhysicsScript.set_touchPressure(pressure);
+    }
+
+    public void setAccel(float x, float y) {
+        mPhysicsScript.set_gGravityVector(new Float2(x, y));
+    }
+
+}
diff --git a/libs/rs/java/Balls/src/com/android/balls/BallsView.java b/libs/rs/java/Balls/src/com/android/balls/BallsView.java
new file mode 100644
index 0000000..635dac9
--- /dev/null
+++ b/libs/rs/java/Balls/src/com/android/balls/BallsView.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008 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.balls;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class BallsView extends RSSurfaceView {
+
+    public BallsView(Context context) {
+        super(context);
+        //setFocusable(true);
+    }
+
+    private RenderScriptGL mRS;
+    private BallsRS mRender;
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            mRS = createRenderScript(sc);
+            mRS.contextSetSurface(w, h, holder.getSurface());
+            mRender = new BallsRS();
+            mRender.init(mRS, getResources(), w, h);
+        }
+        mRender.updateProjectionMatrices();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if(mRS != null) {
+            mRS = null;
+            destroyRenderScript();
+        }
+    }
+
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev)
+    {
+        int act = ev.getActionMasked();
+        if (act == ev.ACTION_UP) {
+            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+            return false;
+        } else if (act == MotionEvent.ACTION_POINTER_UP) {
+            // only one pointer going up, we can get the index like this
+            int pointerIndex = ev.getActionIndex();
+            int pointerId = ev.getPointerId(pointerIndex);
+            mRender.newTouchPosition(0, 0, 0, pointerId);
+        }
+        int count = ev.getHistorySize();
+        int pcount = ev.getPointerCount();
+
+        for (int p=0; p < pcount; p++) {
+            int id = ev.getPointerId(p);
+            mRender.newTouchPosition(ev.getX(p),
+                                     ev.getY(p),
+                                     ev.getPressure(p),
+                                     id);
+
+            for (int i=0; i < count; i++) {
+                mRender.newTouchPosition(ev.getHistoricalX(p, i),
+                                         ev.getHistoricalY(p, i),
+                                         ev.getHistoricalPressure(p, i),
+                                         id);
+            }
+        }
+        return true;
+    }
+
+    void setAccel(float x, float y, float z) {
+        if (mRender == null) {
+            return;
+        }
+        mRender.setAccel(x, -y);
+    }
+
+}
+
+
diff --git a/libs/rs/java/Balls/src/com/android/balls/ball_physics.rs b/libs/rs/java/Balls/src/com/android/balls/ball_physics.rs
new file mode 100644
index 0000000..b5f149c
--- /dev/null
+++ b/libs/rs/java/Balls/src/com/android/balls/ball_physics.rs
@@ -0,0 +1,116 @@
+#pragma version(1)
+#pragma rs java_package_name(com.android.balls)
+
+#include "balls.rsh"
+
+float2 gGravityVector = {0.f, 9.8f};
+
+#pragma rs export_func(setGamma);
+
+float2 gMinPos = {0.f, 0.f};
+float2 gMaxPos = {1280.f, 700.f};
+
+float touchX;
+float touchY;
+float touchPressure = 0.f;
+
+void setGamma(float g) {
+}
+
+
+void root(const Ball_t *ballIn, Ball_t *ballOut, const BallControl_t *ctl, uint32_t x) {
+    float2 fv = {0, 0};
+    float2 pos = ballIn->position;
+    //rsDebug("physics pos in", pos);
+
+    int arcID = -1;
+    float arcInvStr = 100000;
+
+    const Ball_t * bPtr = rsGetElementAt(ctl->ain, 0);
+    for (uint32_t xin = 0; xin < ctl->dimX; xin++) {
+        float2 vec = bPtr[xin].position - pos;
+        float2 vec2 = vec * vec;
+        float len2 = vec2.x + vec2.y;
+
+        if (len2 < 1000) {
+            if (len2 > (4*4)) {
+                // Repulsion
+                float len = sqrt(len2);
+                if (len < arcInvStr) {
+                    arcInvStr = len;
+                    arcID = xin;
+                }
+                fv -= (vec / (len * len * len)) * 20000.f;
+            } else {
+                if (len2 < 0.1) {
+                    continue;
+                }
+                // Collision
+                float2 axis = normalize(vec);
+                float e1 = dot(axis, ballIn->delta);
+                float e2 = dot(axis, bPtr[xin].delta);
+                float e = (e1 - e2) * 0.45f;
+                if (e1 > 0) {
+                    fv -= axis * e;
+                } else {
+                    fv += axis * e;
+                }
+            }
+        }
+    }
+
+    fv -= gGravityVector;
+    fv *= ctl->dt;
+
+    {
+        float2 tp = {touchX, touchY};
+        float2 vec = tp - ballIn->position;
+        float2 vec2 = vec * vec;
+        float len2 = vec2.x + vec2.y;
+
+        if (len2 > 0.2) {
+            float len = sqrt(len2);
+            fv -= (vec / (len * len)) * touchPressure * 1000.f;
+        }
+    }
+
+    ballOut->delta = ballIn->delta * 0.998f;
+    ballOut->position = ballIn->position;
+
+    ballOut->delta += fv;
+    ballOut->position += ballOut->delta * ctl->dt;
+
+    if (ballOut->position.x > gMaxPos.x) {
+        if (ballOut->delta.x > 0) {
+            ballOut->delta.x *= -0.7;
+        }
+        ballOut->position.x = gMaxPos.x;
+    }
+    if (ballOut->position.y > gMaxPos.y) {
+        if (ballOut->delta.y > 0) {
+            ballOut->delta.y *= -0.7;
+        }
+        ballOut->position.y = gMaxPos.y - 1.f;
+    }
+    if (ballOut->position.x < gMinPos.x) {
+        if (ballOut->delta.x < 0) {
+            ballOut->delta.x *= -0.7;
+        }
+        ballOut->position.x = gMinPos.x + 1.f;
+    }
+    if (ballOut->position.y < gMinPos.y) {
+        if (ballOut->delta.y < 0) {
+            ballOut->delta.y *= -0.7;
+        }
+        ballOut->position.y = gMinPos.y + 1.f;
+    }
+
+    ballOut->color.b = 1.f;
+    ballOut->color.r = min(sqrt(length(ballOut->delta)) * 0.1f, 1.f);
+    ballOut->color.g = min(sqrt(length(fv) * 0.1f), 1.f);
+    ballOut->arcID = arcID;
+    ballOut->arcStr = 8 / arcInvStr;
+
+    //rsDebug("physics pos out", ballOut->position);
+}
+
diff --git a/libs/rs/java/Balls/src/com/android/balls/balls.rs b/libs/rs/java/Balls/src/com/android/balls/balls.rs
new file mode 100644
index 0000000..9d3f30b
--- /dev/null
+++ b/libs/rs/java/Balls/src/com/android/balls/balls.rs
@@ -0,0 +1,104 @@
+#pragma version(1)
+#pragma rs java_package_name(com.android.balls)
+#include "rs_graphics.rsh"
+
+#include "balls.rsh"
+
+#pragma stateFragment(parent)
+
+rs_program_fragment gPF;
+rs_program_vertex gPV;
+rs_program_raster gPR;
+rs_program_store gPS;
+rs_mesh partMesh;
+rs_mesh arcMesh;
+
+typedef struct __attribute__((packed, aligned(4))) Point {
+    float2 position;
+    uchar4 color;
+    float size;
+} Point_t;
+Point_t *point;
+Point_t *arc;
+
+typedef struct VpConsts {
+    //rs_matrix4x4 Proj;
+    rs_matrix4x4 MVP;
+} VpConsts_t;
+VpConsts_t *vpConstants;
+
+
+#pragma rs export_func(initParts)
+
+rs_script physics_script;
+
+Ball_t *balls1;
+Ball_t *balls2;
+
+static int frame = 0;
+
+void initParts(int w, int h)
+{
+    uint32_t dimX = rsAllocationGetDimX(rsGetAllocation(balls1));
+
+    for (uint32_t ct=0; ct < dimX; ct++) {
+        balls1[ct].position.x = rsRand(0.f, (float)w);
+        balls1[ct].position.y = rsRand(0.f, (float)h);
+        balls1[ct].delta.x = 0.f;
+        balls1[ct].delta.y = 0.f;
+        balls1[ct].arcID = -1;
+        balls1[ct].color = 0.f;
+    }
+}
+
+
+
+int root() {
+    rsgClearColor(0.f, 0.f, 0.f, 1.f);
+
+    BallControl_t bc;
+    Ball_t *bout;
+
+    if (frame & 1) {
+        bc.ain = rsGetAllocation(balls2);
+        bc.aout = rsGetAllocation(balls1);
+        bout = balls2;
+    } else {
+        bc.ain = rsGetAllocation(balls1);
+        bc.aout = rsGetAllocation(balls2);
+        bout = balls1;
+    }
+
+    bc.dimX = rsAllocationGetDimX(bc.ain);
+    bc.dt = 1.f / 30.f;
+
+    rsForEach(physics_script, bc.ain, bc.aout, &bc);
+
+    uint32_t arcIdx = 0;
+    for (uint32_t ct=0; ct < bc.dimX; ct++) {
+        point[ct].position = bout[ct].position;
+        point[ct].color = rsPackColorTo8888(bout[ct].color);
+        point[ct].size = 6.f + bout[ct].color.g * 6.f;
+
+        if (bout[ct].arcID >= 0) {
+            arc[arcIdx].position = bout[ct].position;
+            arc[arcIdx].color.r = min(bout[ct].arcStr, 1.f) * 0xff;
+            arc[arcIdx].color.g = 0;
+            arc[arcIdx].color.b = 0;
+            arc[arcIdx].color.a = 0xff;
+            arc[arcIdx+1].position = bout[bout[ct].arcID].position;
+            arc[arcIdx+1].color = arc[arcIdx].color;
+            arcIdx += 2;
+        }
+    }
+
+    frame++;
+    rsgBindProgramFragment(gPF);
+    rsgBindProgramVertex(gPV);
+    rsgBindProgramRaster(gPR);
+    rsgBindProgramStore(gPS);
+    rsgDrawMesh(arcMesh, 0, 0, arcIdx);
+    rsgDrawMesh(partMesh);
+    return 1;
+}
+
diff --git a/libs/rs/java/Balls/src/com/android/balls/balls.rsh b/libs/rs/java/Balls/src/com/android/balls/balls.rsh
new file mode 100644
index 0000000..ed3c31a
--- /dev/null
+++ b/libs/rs/java/Balls/src/com/android/balls/balls.rsh
@@ -0,0 +1,17 @@
+
+typedef struct __attribute__((packed, aligned(4))) Ball {
+    float2 delta;
+    float2 position;
+    float3 color;
+    int arcID;
+    float arcStr;
+} Ball_t;
+Ball_t *balls;
+
+
+typedef struct BallControl {
+    uint32_t dimX;
+    rs_allocation ain;
+    rs_allocation aout;
+    float dt;
+} BallControl_t;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 3f04585..0241455 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -470,7 +470,7 @@
              rsc->timerPrint();
              rsc->timerReset();
          }
-         if (rsc->mThreadPriority > 0 && targetTime) {
+         if (targetTime > 1) {
              int32_t t = (targetTime - (int32_t)(rsc->mTimeMSLastScript + rsc->mTimeMSLastSwap)) * 1000;
              if (t > 0) {
                  usleep(t);
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 9dce158..1f5ed7c 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -217,6 +217,32 @@
 
 }
 
+static void wc_x(void *usr, uint32_t idx)
+{
+    MTLaunchStruct *mtls = (MTLaunchStruct *)usr;
+
+    while (1) {
+        uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
+        uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
+        uint32_t xEnd = xStart + mtls->mSliceSize;
+        xEnd = rsMin(xEnd, mtls->xEnd);
+        if (xEnd <= xStart) {
+            return;
+        }
+
+        //LOGE("usr idx %i, x %i,%i  y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
+        //LOGE("usr ptr in %p,  out %p", mtls->ptrIn, mtls->ptrOut);
+        uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart);
+        const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart);
+        for (uint32_t x = xStart; x < xEnd; x++) {
+            ((rs_t)mtls->script->mProgram.mRoot) (xPtrIn, xPtrOut, mtls->usr, x, 0, 0, 0);
+            xPtrIn += mtls->eStrideIn;
+            xPtrOut += mtls->eStrideOut;
+        }
+    }
+
+}
+
 void ScriptC::runForEach(Context *rsc,
                          const Allocation * ain,
                          Allocation * aout,
@@ -296,10 +322,14 @@
         mtls.eStrideOut = aout->getType()->getElementSizeBytes();
     }
 
-    if ((rsc->getWorkerPoolSize() > 1) && mEnviroment.mIsThreadable && (mtls.dimY > 1)) {
+    if ((rsc->getWorkerPoolSize() > 1) && mEnviroment.mIsThreadable) {
+        if (mtls.dimY > 1) {
+            rsc->launchThreads(wc_xy, &mtls);
+        } else {
+            rsc->launchThreads(wc_x, &mtls);
+        }
 
         //LOGE("launch 1");
-        rsc->launchThreads(wc_xy, &mtls);
     } else {
         //LOGE("launch 3");
         for (uint32_t ar = mtls.arrayStart; ar < mtls.arrayEnd; ar++) {
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 91e7df3..03d2e21 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1896,7 +1896,7 @@
     return false;
 }
 
-ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
+ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density,
         uint32_t* outSpecFlags, ResTable_config* outConfig) const
 {
     if (mError != NO_ERROR) {
@@ -1926,7 +1926,7 @@
     memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up
 
     if (outSpecFlags != NULL) *outSpecFlags = 0;
-    
+
     // Look through all resource packages, starting with the most
     // recently added.
     const PackageGroup* const grp = mPackageGroups[p];
@@ -1934,6 +1934,22 @@
         LOGW("Bad identifier when getting value for resource number 0x%08x", resID);
         return BAD_INDEX;
     }
+
+    // Allow overriding density
+    const ResTable_config* desiredConfig = &mParams;
+    ResTable_config* overrideConfig = NULL;
+    if (density > 0) {
+        overrideConfig = (ResTable_config*) malloc(sizeof(ResTable_config));
+        if (overrideConfig == NULL) {
+            LOGE("Couldn't malloc ResTable_config for overrides: %s", strerror(errno));
+            return BAD_INDEX;
+        }
+        memcpy(overrideConfig, &mParams, sizeof(ResTable_config));
+        overrideConfig->density = density;
+        desiredConfig = overrideConfig;
+    }
+
+    ssize_t rc = BAD_INDEX;
     size_t ip = grp->packages.size();
     while (ip > 0) {
         ip--;
@@ -1943,12 +1959,13 @@
         const ResTable_type* type;
         const ResTable_entry* entry;
         const Type* typeClass;
-        ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+        ssize_t offset = getEntry(package, t, e, desiredConfig, &type, &entry, &typeClass);
         if (offset <= 0) {
             if (offset < 0) {
                 LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n",
                         resID, t, e, ip, (int)offset);
-                return offset;
+                rc = offset;
+                goto out;
             }
             continue;
         }
@@ -1963,13 +1980,14 @@
 
         TABLE_NOISY(aout << "Resource type data: "
               << HexDump(type, dtohl(type->header.size)) << endl);
-        
+
         if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
             LOGW("ResTable_item at %d is beyond type chunk data %d",
                  (int)offset, dtohl(type->header.size));
-            return BAD_TYPE;
+            rc = BAD_TYPE;
+            goto out;
         }
-        
+
         const Res_value* item =
             (const Res_value*)(((const uint8_t*)type) + offset);
         ResTable_config thisConfig;
@@ -2011,10 +2029,16 @@
                          outValue->data, &len)).string()
                      : "",
                      outValue->data));
-        return bestPackage->header->index;
+        rc = bestPackage->header->index;
+        goto out;
     }
 
-    return BAD_VALUE;
+out:
+    if (overrideConfig != NULL) {
+        free(overrideConfig);
+    }
+
+    return rc;
 }
 
 ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
@@ -2027,7 +2051,7 @@
         if (outLastRef) *outLastRef = value->data;
         uint32_t lastRef = value->data;
         uint32_t newFlags = 0;
-        const ssize_t newIndex = getResource(value->data, value, true, &newFlags,
+        const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags,
                 outConfig);
         if (newIndex == BAD_INDEX) {
             return BAD_INDEX;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index cb46a29..01134f2 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1087,53 +1087,6 @@
     private native void _reset();
 
     /**
-     * Suspends the MediaPlayer. The only methods that may be called while
-     * suspended are {@link #reset()}, {@link #release()} and {@link #resume()}.
-     * MediaPlayer will release its hardware resources as far as
-     * possible and reasonable. A successfully suspended MediaPlayer will
-     * cease sending events.
-     * If suspension is successful, this method returns true, otherwise
-     * false is returned and the player's state is not affected.
-     * @hide
-     */
-    public boolean suspend() {
-        if (native_suspend_resume(true) < 0) {
-            return false;
-        }
-
-        stayAwake(false);
-
-        // make sure none of the listeners get called anymore
-        mEventHandler.removeCallbacksAndMessages(null);
-
-        return true;
-    }
-
-    /**
-     * Resumes the MediaPlayer. Only to be called after a previous (successful)
-     * call to {@link #suspend()}.
-     * MediaPlayer will return to a state close to what it was in before
-     * suspension.
-     * @hide
-     */
-    public boolean resume() {
-        if (native_suspend_resume(false) < 0) {
-            return false;
-        }
-
-        if (isPlaying()) {
-            stayAwake(true);
-        }
-
-        return true;
-    }
-
-    /**
-     * @hide
-     */
-    private native int native_suspend_resume(boolean isSuspend);
-
-    /**
      * Sets the audio stream type for this MediaPlayer. See {@link AudioManager}
      * for a list of stream types. Must call this method before prepare() or
      * prepareAsync() in order for the target stream type to become effective
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index eb3d27b..997d017 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -680,19 +680,6 @@
     android_media_MediaPlayer_release(env, thiz);
 }
 
-static jint
-android_media_MediaPlayer_native_suspend_resume(
-        JNIEnv *env, jobject thiz, jboolean isSuspend) {
-    LOGV("suspend_resume(%d)", isSuspend);
-    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return UNKNOWN_ERROR;
-    }
-
-    return isSuspend ? mp->suspend() : mp->resume();
-}
-
 static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env,  jobject thiz, jint sessionId) {
     LOGV("set_session_id(): %d", sessionId);
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
@@ -767,7 +754,6 @@
     {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
     {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
     {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
-    {"native_suspend_resume", "(Z)I",                           (void *)android_media_MediaPlayer_native_suspend_resume},
     {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},
     {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer_set_audio_session_id},
     {"setAuxEffectSendLevel", "(F)V",                           (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 9dfdcb0..1a46715 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -45,8 +45,6 @@
     INVOKE,
     SET_METADATA_FILTER,
     GET_METADATA,
-    SUSPEND,
-    RESUME,
     SET_AUX_EFFECT_SEND_LEVEL,
     ATTACH_AUX_EFFECT
 };
@@ -215,26 +213,6 @@
         return reply->readInt32();
     }
 
-    status_t suspend() {
-        Parcel request;
-        request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-
-        Parcel reply;
-        remote()->transact(SUSPEND, request, &reply);
-
-        return reply.readInt32();
-    }
-
-    status_t resume() {
-        Parcel request;
-        request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-
-        Parcel reply;
-        remote()->transact(RESUME, request, &reply);
-
-        return reply.readInt32();
-    }
-
     status_t setAuxEffectSendLevel(float level)
     {
         Parcel data, reply;
@@ -358,16 +336,6 @@
             reply->writeInt32(setMetadataFilter(data));
             return NO_ERROR;
         } break;
-        case SUSPEND: {
-            CHECK_INTERFACE(IMediaPlayer, data, reply);
-            reply->writeInt32(suspend());
-            return NO_ERROR;
-        } break;
-        case RESUME: {
-            CHECK_INTERFACE(IMediaPlayer, data, reply);
-            reply->writeInt32(resume());
-            return NO_ERROR;
-        } break;
         case GET_METADATA: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             const status_t retcode = getMetadata(data.readInt32(), data.readInt32(), reply);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index ee3f660..34e41a1 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -172,16 +172,6 @@
     return INVALID_OPERATION;
 }
 
-status_t MediaPlayer::suspend() {
-    Mutex::Autolock _l(mLock);
-    return mPlayer->suspend();
-}
-
-status_t MediaPlayer::resume() {
-    Mutex::Autolock _l(mLock);
-    return mPlayer->resume();
-}
-
 status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
 {
     LOGD("setMetadataFilter");
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 80922d6..bb86e05 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -974,20 +974,6 @@
     return OK;
 }
 
-status_t MediaPlayerService::Client::suspend() {
-    sp<MediaPlayerBase> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-
-    return p->suspend();
-}
-
-status_t MediaPlayerService::Client::resume() {
-    sp<MediaPlayerBase> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-
-    return p->resume();
-}
-
 status_t MediaPlayerService::Client::prepareAsync()
 {
     LOGV("[%d] prepareAsync", mConnId);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index c4e78f7..e197cde 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -225,8 +225,6 @@
         virtual status_t        getMetadata(bool update_only,
                                             bool apply_filter,
                                             Parcel *reply);
-        virtual status_t        suspend();
-        virtual status_t        resume();
         virtual status_t        setAuxEffectSendLevel(float level);
         virtual status_t        attachAuxEffect(int effectId);
 
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index b3e2da0..e0957f6 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -147,16 +147,6 @@
     return STAGEFRIGHT_PLAYER;
 }
 
-status_t StagefrightPlayer::suspend() {
-    LOGV("suspend");
-    return mPlayer->suspend();
-}
-
-status_t StagefrightPlayer::resume() {
-    LOGV("resume");
-    return mPlayer->resume();
-}
-
 status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) {
     return INVALID_OPERATION;
 }
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index dd37102..3899447 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -51,8 +51,6 @@
     virtual player_type playerType();
     virtual status_t invoke(const Parcel &request, Parcel *reply);
     virtual void setAudioSink(const sp<AudioSink> &audioSink);
-    virtual status_t suspend();
-    virtual status_t resume();
 
     virtual status_t getMetadata(
             const media::Metadata::Filter& ids, Parcel *records);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index cf04e92..60a41bf 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1192,6 +1192,13 @@
     mFlags |= FIRST_FRAME;
     mSeeking = false;
     mSeekNotificationSent = false;
+
+    if (mDecryptHandle != NULL) {
+        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
+                Playback::PAUSE, 0);
+        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
+                Playback::START, videoTimeUs / 1000);
+    }
 }
 
 void AwesomePlayer::onVideoEvent() {
@@ -1295,13 +1302,6 @@
 
     TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
 
-    if (mDecryptHandle != NULL) {
-        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
-                Playback::PAUSE, 0);
-        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
-                Playback::START, timeUs / 1000);
-    }
-
     if (mFlags & FIRST_FRAME) {
         mFlags &= ~FIRST_FRAME;
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index ea5577d..0b8997c 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -32,6 +32,8 @@
 #include <media/stagefright/MediaErrors.h>
 #include <utils/String8.h>
 
+#include <cutils/properties.h>
+
 namespace android {
 
 bool DataSource::getUInt16(off_t offset, uint16_t *x) {
@@ -105,7 +107,12 @@
     RegisterSniffer(SniffAMR);
     RegisterSniffer(SniffMPEG2TS);
     RegisterSniffer(SniffMP3);
-    //RegisterSniffer(SniffDRM);
+
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("drm.service.enabled", value, NULL)
+            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        RegisterSniffer(SniffDRM);
+    }
 }
 
 // static
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 9e79aa9..b3ed845 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -506,7 +506,7 @@
 }
 
 void MPEG4Writer::stopWriterThread() {
-    LOGV("stopWriterThread");
+    LOGD("Stopping writer thread");
 
     {
         Mutex::Autolock autolock(mLock);
@@ -517,6 +517,7 @@
 
     void *dummy;
     pthread_join(mThread, &dummy);
+    LOGD("Writer thread stopped");
 }
 
 status_t MPEG4Writer::stop() {
@@ -1228,6 +1229,7 @@
 }
 
 status_t MPEG4Writer::Track::stop() {
+    LOGD("Stopping %s track", mIsAudio? "Audio": "Video");
     if (mDone) {
         return OK;
     }
@@ -1239,6 +1241,7 @@
 
     status_t err = (status_t) dummy;
 
+    LOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
     {
         status_t status = mSource->stop();
         if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
@@ -1246,6 +1249,7 @@
         }
     }
 
+    LOGD("%s track stopped", mIsAudio? "Audio": "Video");
     return err;
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index c164eb4..ed2ed1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -55,6 +55,7 @@
     private static final int MSG_SET_LIGHTS_ON = 0x00070000;
 
     private static final int MSG_SHOW_MENU = 0x00080000;
+    private static final int MSG_SHOW_IME_BUTTON = 0x00090000;
 
     private StatusBarIconList mList;
     private Callbacks mCallbacks;
@@ -81,6 +82,7 @@
         public void animateCollapse();
         public void setLightsOn(boolean on);
         public void setMenuKeyVisible(boolean visible);
+        public void setIMEButtonVisible(boolean visible);
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -163,6 +165,13 @@
         }
     }
 
+    public void setIMEButtonVisible(boolean visible) {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
+            mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, visible ? 1 : 0, 0, null).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
@@ -223,6 +232,9 @@
                 case MSG_SHOW_MENU:
                     mCallbacks.setMenuKeyVisible(msg.arg1 != 0);
                     break;
+                case MSG_SHOW_IME_BUTTON:
+                    mCallbacks.setIMEButtonVisible(msg.arg1 != 0);
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
index bf58b37..b174973 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -1014,6 +1014,7 @@
 
     // Not supported
     public void setMenuKeyVisible(boolean visible) { }
+    public void setIMEButtonVisible(boolean visible) { }
 
     private class Launcher implements View.OnClickListener {
         private PendingIntent mIntent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index ae1fdbd..256386b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -65,7 +65,7 @@
         mCommandQueue = new CommandQueue(this, iconList);
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        boolean[] switches = new boolean[2];
+        boolean[] switches = new boolean[3];
         try {
             mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
                     switches);
@@ -75,6 +75,7 @@
 
         setLightsOn(switches[0]);
         setMenuKeyVisible(switches[1]);
+        setIMEButtonVisible(switches[2]);
 
         // Set up the initial icon state
         int N = iconList.size();
@@ -119,6 +120,7 @@
                    + " icons=" + iconList.size()
                    + " lights=" + (switches[0]?"on":"off")
                    + " menu=" + (switches[1]?"visible":"invisible")
+                   + " imeButton=" + (switches[2]?"visible":"invisible")
                    );
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
index 56b4f24..c416ff4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
@@ -16,9 +16,13 @@
 
 package com.android.systemui.statusbar.tablet;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
@@ -32,7 +36,9 @@
 import com.android.server.InputMethodManagerService;
 import com.android.systemui.R;
 
+import java.util.Calendar;
 import java.util.List;
+import java.util.TimeZone;
 
 public class InputMethodButton extends ImageView {
 
@@ -61,8 +67,10 @@
         });
     }
 
+    @Override
     protected void onAttachedToWindow() {
         mIcon = (ImageView) findViewById(R.id.imeButton);
+
         refreshStatusIcon(mKeyboardShown);
     }
 
@@ -119,21 +127,8 @@
         }
     }
 
-    private void postRefreshStatusIcon() {
-        getHandler().post(new Runnable() {
-            public void run() {
-                refreshStatusIcon(mKeyboardShown);
-            }
-        });
-    }
-
-    public void showSoftInput() {
-        mKeyboardShown = true;
-        postRefreshStatusIcon();
-    }
-
-    public void hideSoftInput() {
-        mKeyboardShown = false;
-        postRefreshStatusIcon();
+    public void setIMEButtonVisible(boolean visible) {
+        mKeyboardShown = visible;
+        refreshStatusIcon(mKeyboardShown);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
index 6e9b456..abcfec8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
@@ -95,6 +95,8 @@
     View mMenuButton;
     View mRecentButton;
 
+    InputMethodButton mInputMethodButton;
+
     NotificationPanel mNotificationPanel;
     SystemPanel mSystemPanel;
     NotificationPanel mNotificationPeekWindow;
@@ -305,6 +307,9 @@
         mNavigationArea = sb.findViewById(R.id.navigationArea);
         mMenuButton = mNavigationArea.findViewById(R.id.menu);
 
+        // The bar contents buttons
+        mInputMethodButton = (InputMethodButton) mBarContents.findViewById(R.id.imeButton);
+
         // set the initial view visibility
         setAreThereNotifications();
         refreshNotificationTrigger();
@@ -690,6 +695,13 @@
                 visible ? R.anim.navigation_in : R.anim.navigation_out);
     }
 
+    public void setIMEButtonVisible(boolean visible) {
+        if (DEBUG) {
+            Slog.d(TAG, (visible?"showing":"hiding") + " the IME button");
+        }
+        mInputMethodButton.setIMEButtonVisible(visible);
+    }
+
     private void setAreThereNotifications() {
         final boolean hasClearable = mNotns.hasClearableItems();
 
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 3f378e1..07da0fa 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -940,6 +940,23 @@
         }
     }
 
+    public void setIMEButtonVisible(IBinder token, boolean visible) {
+        int uid = Binder.getCallingUid();
+        long ident = Binder.clearCallingIdentity();
+        try {
+            if (token == null || mCurToken != token) {
+                Slog.w(TAG, "Ignoring setIMEButtonVisible of uid " + uid + " token: " + token);
+                return;
+            }
+
+            synchronized (mMethodMap) {
+                mStatusBar.setIMEButtonVisible(visible);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     void updateFromSettingsLocked() {
         // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
         // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 400b31f..95d2b65 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -74,6 +74,8 @@
 
     boolean mMenuVisible = false;
 
+    boolean mIMEButtonVisible = false;
+
     private class DisableRecord implements IBinder.DeathRecipient {
         String pkg;
         int what;
@@ -257,6 +259,28 @@
         }
     }
 
+    public void setIMEButtonVisible(final boolean visible) {
+        enforceStatusBar();
+
+        if (SPEW) Slog.d(TAG, (visible?"showing":"hiding") + " IME Button");
+
+        synchronized(mLock) {
+            if (mIMEButtonVisible != visible) {
+                mIMEButtonVisible = visible;
+                mHandler.post(new Runnable() {
+                    public void run() {
+                        if (mBar != null) {
+                            try {
+                                mBar.setIMEButtonVisible(visible);
+                            } catch (RemoteException ex) {
+                            }
+                        }
+                    }
+                });
+            }
+        }
+    }
+
     /**
      * This is used for the automatic version of lights-out mode.  Only call this from
      * the window manager.
@@ -345,6 +369,7 @@
         synchronized (mLock) {
             switches[0] = mLightsOn;
             switches[1] = mMenuVisible;
+            switches[2] = mIMEButtonVisible;
         }
     }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8d36e4f..60b2b67 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6679,6 +6679,9 @@
             if (info.numAnimationsRunning != 0) {
                 sb.append("Animations-Running: ").append(info.numAnimationsRunning).append("\n");
             }
+            if (info.broadcastIntentAction != null) {
+                sb.append("Broadcast-Intent-Action: ").append(info.broadcastIntentAction).append("\n");
+            }
             if (info != null && info.durationMillis != -1) {
                 sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
             }