Merge "Add better index checks for AndroidCharacter.mirror"
diff --git a/api/current.xml b/api/current.xml
index 00f7505..eb1c6d6 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4611,7 +4611,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843448"
+ value="16843447"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -5773,17 +5773,6 @@
  visibility="public"
 >
 </field>
-<field name="neverEncrypt"
- type="int"
- transient="false"
- volatile="false"
- value="16843447"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="nextFocusDown"
  type="int"
  transient="false"
@@ -5971,6 +5960,17 @@
  visibility="public"
 >
 </field>
+<field name="overscrollMode"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843450"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="padding"
  type="int"
  transient="false"
@@ -6855,7 +6855,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843449"
+ value="16843448"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9073,6 +9073,17 @@
  visibility="public"
 >
 </field>
+<field name="webTextViewStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843449"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="webViewStyle"
  type="int"
  transient="false"
@@ -20056,242 +20067,6 @@
 </parameter>
 </method>
 </interface>
-<class name="DeviceAdmin"
- extends="android.content.BroadcastReceiver"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="DeviceAdmin"
- type="android.app.DeviceAdmin"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getManager"
- return="android.app.DevicePolicyManager"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-</method>
-<method name="getWho"
- return="android.content.ComponentName"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-</method>
-<method name="onDisableRequested"
- return="java.lang.CharSequence"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-</method>
-<method name="onDisabled"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-</method>
-<method name="onEnabled"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-</method>
-<method name="onPasswordChanged"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-</method>
-<method name="onPasswordFailed"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-</method>
-<method name="onPasswordSucceeded"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-</method>
-<method name="onReceive"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-</method>
-<field name="ACTION_DEVICE_ADMIN_DISABLED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.app.action.DEVICE_ADMIN_DISABLED&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ACTION_DEVICE_ADMIN_DISABLE_REQUESTED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ACTION_DEVICE_ADMIN_ENABLED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.app.action.DEVICE_ADMIN_ENABLED&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ACTION_PASSWORD_CHANGED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.app.action.ACTION_PASSWORD_CHANGED&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ACTION_PASSWORD_FAILED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.app.action.ACTION_PASSWORD_FAILED&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ACTION_PASSWORD_SUCCEEDED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.app.action.ACTION_PASSWORD_SUCCEEDED&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="DEVICE_ADMIN_META_DATA"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.app.device_admin&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="EXTRA_DISABLE_WARNING"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.app.extra.DISABLE_WARNING&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
 <class name="DeviceAdminInfo"
  extends="java.lang.Object"
  abstract="false"
@@ -20536,6 +20311,242 @@
 >
 </field>
 </class>
+<class name="DeviceAdminReceiver"
+ extends="android.content.BroadcastReceiver"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DeviceAdminReceiver"
+ type="android.app.DeviceAdminReceiver"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getManager"
+ return="android.app.DevicePolicyManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="getWho"
+ return="android.content.ComponentName"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="onDisableRequested"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onDisabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onPasswordChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onPasswordFailed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onPasswordSucceeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onReceive"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<field name="ACTION_DEVICE_ADMIN_DISABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.DEVICE_ADMIN_DISABLED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DEVICE_ADMIN_DISABLE_REQUESTED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DEVICE_ADMIN_ENABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.DEVICE_ADMIN_ENABLED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_PASSWORD_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.ACTION_PASSWORD_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_PASSWORD_FAILED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.ACTION_PASSWORD_FAILED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_PASSWORD_SUCCEEDED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.ACTION_PASSWORD_SUCCEEDED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DEVICE_ADMIN_META_DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.device_admin&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DISABLE_WARNING"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.extra.DISABLE_WARNING&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="DevicePolicyManager"
  extends="java.lang.Object"
  abstract="false"
@@ -150327,9 +150338,9 @@
 </parameter>
 <parameter name="align" type="android.text.Layout.Alignment">
 </parameter>
-<parameter name="spacingmult" type="float">
+<parameter name="spacingMult" type="float">
 </parameter>
-<parameter name="spacingadd" type="float">
+<parameter name="spacingAdd" type="float">
 </parameter>
 </constructor>
 <method name="draw"
@@ -150359,7 +150370,7 @@
 </parameter>
 <parameter name="highlight" type="android.graphics.Path">
 </parameter>
-<parameter name="highlightpaint" type="android.graphics.Paint">
+<parameter name="highlightPaint" type="android.graphics.Paint">
 </parameter>
 <parameter name="cursorOffsetVertical" type="int">
 </parameter>
diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java
index 159fa75..bedf4b4 100644
--- a/core/java/android/app/DeviceAdminInfo.java
+++ b/core/java/android/app/DeviceAdminInfo.java
@@ -60,8 +60,8 @@
     
     /**
      * A type of policy that this device admin can use: able to watch login
-     * attempts from the user, via {@link DeviceAdmin#ACTION_PASSWORD_FAILED},
-     * {@link DeviceAdmin#ACTION_PASSWORD_SUCCEEDED}, and
+     * attempts from the user, via {@link DeviceAdminReceiver#ACTION_PASSWORD_FAILED},
+     * {@link DeviceAdminReceiver#ACTION_PASSWORD_SUCCEEDED}, and
      * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts}.
      * 
      * <p>To control this policy, the device admin must have a "watch-login"
@@ -169,10 +169,10 @@
         
         XmlResourceParser parser = null;
         try {
-            parser = ai.loadXmlMetaData(pm, DeviceAdmin.DEVICE_ADMIN_META_DATA);
+            parser = ai.loadXmlMetaData(pm, DeviceAdminReceiver.DEVICE_ADMIN_META_DATA);
             if (parser == null) {
                 throw new XmlPullParserException("No "
-                        + DeviceAdmin.DEVICE_ADMIN_META_DATA + " meta-data");
+                        + DeviceAdminReceiver.DEVICE_ADMIN_META_DATA + " meta-data");
             }
         
             AttributeSet attrs = Xml.asAttributeSet(parser);
diff --git a/core/java/android/app/DeviceAdmin.java b/core/java/android/app/DeviceAdminReceiver.java
similarity index 93%
rename from core/java/android/app/DeviceAdmin.java
rename to core/java/android/app/DeviceAdminReceiver.java
index af9c379..453e0bf 100644
--- a/core/java/android/app/DeviceAdmin.java
+++ b/core/java/android/app/DeviceAdminReceiver.java
@@ -29,6 +29,13 @@
  * class provides a convenience for interpreting the raw intent actions
  * that are sent by the system.
  * 
+ * <p>The callback methods, like the base
+ * {@link BroadcastReceiver#onReceive(Context, Intent) BroadcastReceiver.onReceive()}
+ * method, happen on the main thread of the process.  Thus long running
+ * operations must be done on another thread.  Note that because a receiver
+ * is done once returning from its receive function, such long-running operations
+ * should probably be done in a {@link Service}.
+ * 
  * <p>When publishing your DeviceAdmin subclass as a receiver, it must
  * handle {@link #ACTION_DEVICE_ADMIN_ENABLED} and require the
  * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission.  A typical
@@ -42,7 +49,7 @@
  * 
  * {@sample development/samples/ApiDemos/res/xml/device_admin_sample.xml meta_data}
  */
-public class DeviceAdmin extends BroadcastReceiver {
+public class DeviceAdminReceiver extends BroadcastReceiver {
     private static String TAG = "DevicePolicy";
     private static boolean DEBUG = false;
     private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
@@ -51,7 +58,7 @@
      * This is the primary action that a device administrator must implement to be
      * allowed to manage a device.  This will be set to the receiver
      * when the user enables it for administration.  You will generally
-     * handle this in {@link DeviceAdmin#onEnabled(Context, Intent)}.  To be
+     * handle this in {@link DeviceAdminReceiver#onEnabled(Context, Intent)}.  To be
      * supported, the receiver must also require the
      * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission so
      * that other applications can not abuse it.
@@ -85,7 +92,7 @@
      * Action sent to a device administrator when the user has disabled
      * it.  Upon return, the application no longer has access to the
      * protected device policy manager APIs.  You will generally
-     * handle this in {@link DeviceAdmin#onDisabled(Context, Intent)}.  Note
+     * handle this in {@link DeviceAdminReceiver#onDisabled(Context, Intent)}.  Note
      * that this action will be
      * sent the receiver regardless of whether it is explicitly listed in
      * its intent filter.
@@ -100,7 +107,7 @@
      * of the new password with {@link DevicePolicyManager#isActivePasswordSufficient()
      * DevicePolicyManager.isActivePasswordSufficient()}.
      * You will generally
-     * handle this in {@link DeviceAdmin#onPasswordChanged}.
+     * handle this in {@link DeviceAdminReceiver#onPasswordChanged}.
      * 
      * <p>The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to receive
@@ -116,7 +123,7 @@
      * number of failed password attempts there have been with
      * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts
      * DevicePolicyManager.getCurrentFailedPasswordAttempts()}.  You will generally
-     * handle this in {@link DeviceAdmin#onPasswordFailed}.
+     * handle this in {@link DeviceAdminReceiver#onPasswordFailed}.
      * 
      * <p>The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
index 82c43dc..d611807 100644
--- a/core/java/android/app/DevicePolicyManager.java
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -36,7 +36,7 @@
 
 /**
  * Public interface for managing policies enforced on a device.  Most clients
- * of this class must have published a {@link DeviceAdmin} that the user
+ * of this class must have published a {@link DeviceAdminReceiver} that the user
  * has currently enabled.
  */
 public class DevicePolicyManager {
@@ -195,7 +195,7 @@
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
      * this method; if it has not, a security exception will be thrown.
      * 
-     * @param admin Which {@link DeviceAdmin} this request is associated with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param quality The new desired quality.  One of
      * {@link #PASSWORD_QUALITY_UNSPECIFIED}, {@link #PASSWORD_QUALITY_SOMETHING},
      * {@link #PASSWORD_QUALITY_NUMERIC}, or {@link #PASSWORD_QUALITY_ALPHANUMERIC}.
@@ -243,7 +243,7 @@
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
      * this method; if it has not, a security exception will be thrown.
      * 
-     * @param admin Which {@link DeviceAdmin} this request is associated with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param length The new desired minimum password length.  A value of 0
      * means there is no restriction.
      */
@@ -338,11 +338,11 @@
      * <p>To implement any other policy (e.g. wiping data for a particular
      * application only, erasing or revoking credentials, or reporting the
      * failure to a server), you should implement
-     * {@link DeviceAdmin#onPasswordFailed(Context, android.content.Intent)}
+     * {@link DeviceAdminReceiver#onPasswordFailed(Context, android.content.Intent)}
      * instead.  Do not use this API, because if the maximum count is reached,
      * the device will be wiped immediately, and your callback will not be invoked.
      * 
-     * @param admin Which {@link DeviceAdmin} this request is associated with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param num The number of failed password attempts at which point the
      * device will wipe its data.
      */
@@ -375,7 +375,9 @@
     }
     
     /**
-     * Force a new password on the user.  This takes effect immediately.
+     * Force a new device unlock password (the password needed to access the
+     * entire device, not for individual accounts) on the user.  This takes
+     * effect immediately.
      * The given password must be sufficient for the
      * current password quality and length constraints as returned by
      * {@link #getPasswordQuality(ComponentName)} and
@@ -413,7 +415,7 @@
      * {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
      * this method; if it has not, a security exception will be thrown.
      * 
-     * @param admin Which {@link DeviceAdmin} this request is associated with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param timeMs The new desired maximum time to lock in milliseconds.
      * A value of 0 means there is no restriction.
      */
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index ed38240..4598bb5 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -822,11 +822,6 @@
         final SearchManager searchManager = (SearchManager) mContext
                 .getSystemService(Context.SEARCH_SERVICE);
 
-        // can't start search without an associated activity (e.g a system dialog)
-        if (!searchManager.hasIdent()) {
-            return false;
-        }
-
         // associate search with owner activity if possible (otherwise it will default to
         // global search).
         final ComponentName appName = getAssociatedActivity();
diff --git a/core/java/android/app/FullBackupAgent.java b/core/java/android/app/FullBackupAgent.java
index d89db96..db198ad 100644
--- a/core/java/android/app/FullBackupAgent.java
+++ b/core/java/android/app/FullBackupAgent.java
@@ -48,7 +48,8 @@
         }
 
         // That's the file set; now back it all up
-        FileBackupHelper helper = new FileBackupHelper(this, (String[])allFiles.toArray());
+        FileBackupHelper helper = new FileBackupHelper(this,
+                allFiles.toArray(new String[allFiles.size()]));
         helper.performBackup(oldState, data, newState);
     }
 
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index e4c1ba6..581b436 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -16,6 +16,9 @@
 
 package android.app;
 
+import com.android.common.Patterns;
+import com.android.common.speech.Recognition;
+
 import static android.app.SuggestionsAdapter.getColumnString;
 
 import android.content.ActivityNotFoundException;
@@ -67,9 +70,6 @@
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
 
-import com.android.common.Patterns;
-import com.android.common.speech.Recognition;
-
 import java.util.ArrayList;
 import java.util.WeakHashMap;
 import java.util.concurrent.atomic.AtomicLong;
@@ -89,10 +89,7 @@
 
     private static final String INSTANCE_KEY_COMPONENT = "comp";
     private static final String INSTANCE_KEY_APPDATA = "data";
-    private static final String INSTANCE_KEY_GLOBALSEARCH = "glob";
-    private static final String INSTANCE_KEY_STORED_COMPONENT = "sComp";
     private static final String INSTANCE_KEY_STORED_APPDATA = "sData";
-    private static final String INSTANCE_KEY_PREVIOUS_COMPONENTS = "sPrev";
     private static final String INSTANCE_KEY_USER_QUERY = "uQry";
     
     // The string used for privateImeOptions to identify to the IME that it should not show
@@ -115,19 +112,8 @@
     private SearchableInfo mSearchable;
     private ComponentName mLaunchComponent;
     private Bundle mAppSearchData;
-    private boolean mGlobalSearchMode;
     private Context mActivityContext;
     private SearchManager mSearchManager;
-    
-    // Values we store to allow user to toggle between in-app search and global search.
-    private ComponentName mStoredComponentName;
-    private Bundle mStoredAppSearchData;
-    
-    // stack of previous searchables, to support the BACK key after
-    // SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.
-    // The top of the stack (= previous searchable) is the last element of the list,
-    // since adding and removing is efficient at the end of an ArrayList.
-    private ArrayList<ComponentName> mPreviousComponents;
 
     // For voice searching
     private final Intent mVoiceWebSearchIntent;
@@ -158,7 +144,7 @@
      * @param context Application Context we can use for system acess
      */
     public SearchDialog(Context context, SearchManager searchManager) {
-        super(context, com.android.internal.R.style.Theme_GlobalSearchBar);
+        super(context, com.android.internal.R.style.Theme_SearchBar);
 
         // Save voice intent for later queries/launching
         mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
@@ -241,14 +227,8 @@
      * @return true if search dialog launched, false if not
      */
     public boolean show(String initialQuery, boolean selectInitialQuery,
-            ComponentName componentName, Bundle appSearchData, boolean globalSearch) {
-
-        // Reset any stored values from last time dialog was shown.
-        mStoredComponentName = null;
-        mStoredAppSearchData = null;
-
-        boolean success = doShow(initialQuery, selectInitialQuery, componentName, appSearchData,
-                globalSearch);
+            ComponentName componentName, Bundle appSearchData) {
+        boolean success = doShow(initialQuery, selectInitialQuery, componentName, appSearchData);
         if (success) {
             // Display the drop down as soon as possible instead of waiting for the rest of the
             // pending UI stuff to get done, so that things appear faster to the user.
@@ -257,67 +237,16 @@
         return success;
     }
 
-    private boolean isInRealAppSearch() {
-        return !mGlobalSearchMode
-                && (mPreviousComponents == null || mPreviousComponents.isEmpty());
-    }
-
     /**
-     * Called in response to a press of the hard search button in
-     * {@link #onKeyDown(int, KeyEvent)}, this method toggles between in-app
-     * search and global search when relevant.
-     * 
-     * If pressed within an in-app search context, this switches the search dialog out to
-     * global search. If pressed within a global search context that was originally an in-app
-     * search context, this switches back to the in-app search context. If pressed within a
-     * global search context that has no original in-app search context (e.g., global search
-     * from Home), this does nothing.
-     * 
-     * @return false if we wanted to toggle context but could not do so successfully, true
-     * in all other cases
-     */
-    private boolean toggleGlobalSearch() {
-        String currentSearchText = mSearchAutoComplete.getText().toString();
-        if (!mGlobalSearchMode) {
-            mStoredComponentName = mLaunchComponent;
-            mStoredAppSearchData = mAppSearchData;
-            
-            // If this is the browser, we have a special case to not show the icon to the left
-            // of the text field, for extra space for url entry (this should be reconciled in
-            // Eclair). So special case a second tap of the search button to remove any
-            // already-entered text so that we can be sure to show the "Quick Search Box" hint
-            // text to still make it clear to the user that we've jumped out to global search.
-            //
-            // TODO: When the browser icon issue is reconciled in Eclair, remove this special case.
-            if (isBrowserSearch()) currentSearchText = "";
-
-            cancel();
-            mSearchManager.startGlobalSearch(currentSearchText, false, mStoredAppSearchData);
-            return true;
-        } else {
-            if (mStoredComponentName != null) {
-                // This means we should toggle *back* to an in-app search context from
-                // global search.
-                return doShow(currentSearchText, false, mStoredComponentName,
-                        mStoredAppSearchData, false);
-            } else {
-                return true;
-            }
-        }
-    }
-    
-    /**
-     * Does the rest of the work required to show the search dialog. Called by both
-     * {@link #show(String, boolean, ComponentName, Bundle, boolean)} and
-     * {@link #toggleGlobalSearch()}.
-     * 
+     * Does the rest of the work required to show the search dialog. Called by
+     * {@link #show(String, boolean, ComponentName, Bundle)} and
+     *
      * @return true if search dialog showed, false if not
      */
     private boolean doShow(String initialQuery, boolean selectInitialQuery,
-            ComponentName componentName, Bundle appSearchData,
-            boolean globalSearch) {
+            ComponentName componentName, Bundle appSearchData) {
         // set up the searchable and show the dialog
-        if (!show(componentName, appSearchData, globalSearch)) {
+        if (!show(componentName, appSearchData)) {
             return false;
         }
 
@@ -335,38 +264,24 @@
      * 
      * @return <code>true</code> if search dialog launched
      */
-    private boolean show(ComponentName componentName, Bundle appSearchData, 
-            boolean globalSearch) {
+    private boolean show(ComponentName componentName, Bundle appSearchData) {
         
         if (DBG) { 
             Log.d(LOG_TAG, "show(" + componentName + ", " 
-                    + appSearchData + ", " + globalSearch + ")");
+                    + appSearchData + ")");
         }
         
         SearchManager searchManager = (SearchManager)
                 mContext.getSystemService(Context.SEARCH_SERVICE);
-        // Try to get the searchable info for the provided component (or for global search,
-        // if globalSearch == true).
-        mSearchable = searchManager.getSearchableInfo(componentName, globalSearch);
-        
-        // If we got back nothing, and it wasn't a request for global search, then try again
-        // for global search, as we'll try to launch that in lieu of any component-specific search.
-        if (!globalSearch && mSearchable == null) {
-            globalSearch = true;
-            mSearchable = searchManager.getSearchableInfo(componentName, globalSearch);
-        }
+        // Try to get the searchable info for the provided component.
+        mSearchable = searchManager.getSearchableInfo(componentName, false);
 
-        // If there's not even a searchable info available for global search, then really give up.
         if (mSearchable == null) {
-            Log.w(LOG_TAG, "No global search provider.");
             return false;
         }
 
         mLaunchComponent = componentName;
         mAppSearchData = appSearchData;
-        // Using globalSearch here is just an optimization, just calling
-        // isDefaultSearchable() should always give the same result.
-        mGlobalSearchMode = globalSearch || searchManager.isDefaultSearchable(mSearchable);
         mActivityContext = mSearchable.getActivityContext(getContext());
 
         // show the dialog. this will call onStart().
@@ -375,20 +290,6 @@
             // of any bad state in the AutoCompleteTextView etc
             createContentView();
 
-            // The Dialog uses a ContextThemeWrapper for the context; use this to change the
-            // theme out from underneath us, between the global search theme and the in-app
-            // search theme. They are identical except that the global search theme does not
-            // dim the background of the window (because global search is full screen so it's
-            // not needed and this should save a little bit of time on global search invocation).
-            Object context = getContext();
-            if (context instanceof ContextThemeWrapper) {
-                ContextThemeWrapper wrapper = (ContextThemeWrapper) context;
-                if (globalSearch) {
-                    wrapper.setTheme(com.android.internal.R.style.Theme_GlobalSearchBar);
-                } else {
-                    wrapper.setTheme(com.android.internal.R.style.Theme_SearchBar);
-                }
-            }
             show();
         }
         updateUI();
@@ -414,7 +315,6 @@
         mSearchable = null;
         mActivityContext = null;
         mUserQuery = null;
-        mPreviousComponents = null;
     }
 
     /**
@@ -428,7 +328,7 @@
         mWorkingSpinner.setVisible(working, false);
         mWorkingSpinner.invalidateSelf();
     }
-    
+
     /**
      * Closes and gets rid of the suggestions adapter.
      */
@@ -442,7 +342,7 @@
         }
         mSuggestionsAdapter = null;
     }
-    
+
     /**
      * Save the minimal set of data necessary to recreate the search
      * 
@@ -458,10 +358,6 @@
         // setup info so I can recreate this particular search       
         bundle.putParcelable(INSTANCE_KEY_COMPONENT, mLaunchComponent);
         bundle.putBundle(INSTANCE_KEY_APPDATA, mAppSearchData);
-        bundle.putBoolean(INSTANCE_KEY_GLOBALSEARCH, mGlobalSearchMode);
-        bundle.putParcelable(INSTANCE_KEY_STORED_COMPONENT, mStoredComponentName);
-        bundle.putBundle(INSTANCE_KEY_STORED_APPDATA, mStoredAppSearchData);
-        bundle.putParcelableArrayList(INSTANCE_KEY_PREVIOUS_COMPONENTS, mPreviousComponents);
         bundle.putString(INSTANCE_KEY_USER_QUERY, mUserQuery);
 
         return bundle;
@@ -481,22 +377,10 @@
 
         ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT);
         Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA);
-        boolean globalSearch = savedInstanceState.getBoolean(INSTANCE_KEY_GLOBALSEARCH);
-        ComponentName storedComponentName =
-                savedInstanceState.getParcelable(INSTANCE_KEY_STORED_COMPONENT);
-        Bundle storedAppSearchData =
-                savedInstanceState.getBundle(INSTANCE_KEY_STORED_APPDATA);
-        ArrayList<ComponentName> previousComponents =
-                savedInstanceState.getParcelableArrayList(INSTANCE_KEY_PREVIOUS_COMPONENTS);
         String userQuery = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY);
 
-        // Set stored state
-        mStoredComponentName = storedComponentName;
-        mStoredAppSearchData = storedAppSearchData;
-        mPreviousComponents = previousComponents;
-
         // show the dialog.
-        if (!doShow(userQuery, false, launchComponent, appSearchData, globalSearch)) {
+        if (!doShow(userQuery, false, launchComponent, appSearchData)) {
             // for some reason, we couldn't re-instantiate
             return;
         }
@@ -506,7 +390,7 @@
      * Called after resources have changed, e.g. after screen rotation or locale change.
      */
     public void onConfigurationChanged() {
-        if (isShowing()) {
+        if (mSearchable != null && isShowing()) {
             // Redraw (resources may have changed)
             updateSearchButton();
             updateSearchAppIcon();
@@ -571,19 +455,13 @@
         // we dismiss the entire dialog instead
         mSearchAutoComplete.setDropDownDismissedOnCompletion(false);
 
-        if (!isInRealAppSearch()) {
-            mSearchAutoComplete.setDropDownAlwaysVisible(true);  // fill space until results come in
-        } else {
-            mSearchAutoComplete.setDropDownAlwaysVisible(false);
-        }
-
         mSearchAutoComplete.setForceIgnoreOutsideTouch(true);
 
         // attach the suggestions adapter, if suggestions are available
         // The existence of a suggestions authority is the proxy for "suggestions available here"
         if (mSearchable.getSuggestAuthority() != null) {
             mSuggestionsAdapter = new SuggestionsAdapter(getContext(), this, mSearchable, 
-                    mOutsideDrawablesCache, mGlobalSearchMode);
+                    mOutsideDrawablesCache);
             mSearchAutoComplete.setAdapter(mSuggestionsAdapter);
         }
     }
@@ -611,7 +489,7 @@
         // global search, for extra space for url entry.
         //
         // TODO: Remove this special case once the issue has been reconciled in Eclair. 
-        if (mGlobalSearchMode || isBrowserSearch()) {
+        if (isBrowserSearch()) {
             mAppIcon.setImageResource(0);
             mAppIcon.setVisibility(View.GONE);
             mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_GLOBAL,
@@ -705,15 +583,13 @@
     
     /**
      * Hack to determine whether this is the browser, so we can remove the browser icon
-     * to the left of the search field, as a special requirement for Donut.
-     * 
-     * TODO: For Eclair, reconcile this with the rest of the global search UI.
+     * to the left of the search field.
      */
     private boolean isBrowserSearch() {
         return mLaunchComponent.flattenToShortString().startsWith("com.android.browser/");
     }
 
-    /**
+    /*
      * Listeners of various types
      */
 
@@ -769,7 +645,7 @@
 
         return super.onKeyDown(keyCode, event);
     }
-    
+
     /**
      * Callback to watch the textedit field for empty/non-empty
      */
@@ -799,12 +675,8 @@
             if (mSearchable.autoUrlDetect() && !mSearchAutoComplete.isPerformingCompletion()) {
                 // The user changed the query, check if it is a URL and if so change the search
                 // button in the soft keyboard to the 'Go' button.
-                int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION));
-                if (Patterns.WEB_URL.matcher(mUserQuery).matches()) {
-                    options = options | EditorInfo.IME_ACTION_GO;
-                } else {
-                    options = options | EditorInfo.IME_ACTION_SEARCH;
-                }
+                int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION))
+                        | EditorInfo.IME_ACTION_GO;
                 if (options != mSearchAutoCompleteImeOptions) {
                     mSearchAutoCompleteImeOptions = options;
                     mSearchAutoComplete.setImeOptions(options);
@@ -881,7 +753,8 @@
                 if (searchable.getVoiceSearchLaunchWebSearch()) {
                     getContext().startActivity(mVoiceWebSearchIntent);
                 } else if (searchable.getVoiceSearchLaunchRecognizer()) {
-                    Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent);                    
+                    Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent,
+                            searchable);
                     getContext().startActivity(appSearchIntent);
                 }
             } catch (ActivityNotFoundException e) {
@@ -899,8 +772,8 @@
      * @param baseIntent The voice app search intent to start from
      * @return A completely-configured intent ready to send to the voice search activity
      */
-    private Intent createVoiceAppSearchIntent(Intent baseIntent) {
-        ComponentName searchActivity = mSearchable.getSearchActivity();
+    private Intent createVoiceAppSearchIntent(Intent baseIntent, SearchableInfo searchable) {
+        ComponentName searchActivity = searchable.getSearchActivity();
         
         // create the necessary intent to set up a search-and-forward operation
         // in the voice search system.   We have to keep the bundle separate,
@@ -930,17 +803,17 @@
         String language = null;
         int maxResults = 1;
         Resources resources = mActivityContext.getResources();
-        if (mSearchable.getVoiceLanguageModeId() != 0) {
-            languageModel = resources.getString(mSearchable.getVoiceLanguageModeId());
+        if (searchable.getVoiceLanguageModeId() != 0) {
+            languageModel = resources.getString(searchable.getVoiceLanguageModeId());
         }
-        if (mSearchable.getVoicePromptTextId() != 0) {
-            prompt = resources.getString(mSearchable.getVoicePromptTextId());
+        if (searchable.getVoicePromptTextId() != 0) {
+            prompt = resources.getString(searchable.getVoicePromptTextId());
         }
-        if (mSearchable.getVoiceLanguageId() != 0) {
-            language = resources.getString(mSearchable.getVoiceLanguageId());
+        if (searchable.getVoiceLanguageId() != 0) {
+            language = resources.getString(searchable.getVoiceLanguageId());
         }
-        if (mSearchable.getVoiceMaxResults() != 0) {
-            maxResults = mSearchable.getVoiceMaxResults();
+        if (searchable.getVoiceMaxResults() != 0) {
+            maxResults = searchable.getVoiceMaxResults();
         }
         voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel);
         voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt);
@@ -1140,14 +1013,9 @@
      */
     protected void launchQuerySearch(int actionKey, String actionMsg)  {
         String query = mSearchAutoComplete.getText().toString();
-        String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH;
+        String action = Intent.ACTION_SEARCH;
         Intent intent = createIntent(action, null, null, query, null,
-                actionKey, actionMsg, null);
-        // Allow GlobalSearch to log and create shortcut for searches launched by
-        // the search button, enter key or an action key.
-        if (mGlobalSearchMode) {
-            mSuggestionsAdapter.reportSearch(query);
-        }
+                actionKey, actionMsg);
         launchIntent(intent);
     }
     
@@ -1160,7 +1028,7 @@
     protected boolean launchSuggestion(int position) {
         return launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null);
     }
-    
+
     /**
      * Launches an intent based on a suggestion.
      * 
@@ -1177,20 +1045,7 @@
 
             Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg);
 
-            // report back about the click
-            if (mGlobalSearchMode) {
-                // in global search mode, do it via cursor
-                mSuggestionsAdapter.callCursorOnClick(c, position, actionKey, actionMsg);
-            } else if (intent != null
-                    && mPreviousComponents != null
-                    && !mPreviousComponents.isEmpty()) {
-                // in-app search (and we have pivoted in as told by mPreviousComponents,
-                // which is used for keeping track of what we pop back to when we are pivoting into
-                // in app search.)
-                reportInAppClickToGlobalSearch(c, intent);
-            }
-
-            // launch the intent
+           // launch the intent
             launchIntent(intent);
 
             return true;
@@ -1199,163 +1054,28 @@
     }
 
     /**
-     * Report a click from an in app search result back to global search for shortcutting porpoises.
-     *
-     * @param c The cursor that is pointing to the clicked position.
-     * @param intent The intent that will be launched for the click.
-     */
-    private void reportInAppClickToGlobalSearch(Cursor c, Intent intent) {
-        // for in app search, still tell global search via content provider
-        Uri uri = getClickReportingUri();
-        final ContentValues cv = new ContentValues();
-        cv.put(SearchManager.SEARCH_CLICK_REPORT_COLUMN_QUERY, mUserQuery);
-        final ComponentName source = mSearchable.getSearchActivity();
-        cv.put(SearchManager.SEARCH_CLICK_REPORT_COLUMN_COMPONENT, source.flattenToShortString());
-
-        // grab the intent columns from the intent we created since it has additional
-        // logic for falling back on the searchable default
-        cv.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, intent.getAction());
-        cv.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, intent.getDataString());
-        cv.put(SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME,
-                intent.getComponent().flattenToShortString());
-
-        // ensure the icons will work for global search
-        cv.put(SearchManager.SUGGEST_COLUMN_ICON_1,
-                        wrapIconForPackage(
-                                mSearchable.getSuggestPackage(),
-                                getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_1)));
-        cv.put(SearchManager.SUGGEST_COLUMN_ICON_2,
-                        wrapIconForPackage(
-                                mSearchable.getSuggestPackage(),
-                                getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_2)));
-
-        // the rest can be passed through directly
-        cv.put(SearchManager.SUGGEST_COLUMN_FORMAT,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_FORMAT));
-        cv.put(SearchManager.SUGGEST_COLUMN_TEXT_1,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_TEXT_1));
-        cv.put(SearchManager.SUGGEST_COLUMN_TEXT_2,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_TEXT_2));
-        cv.put(SearchManager.SUGGEST_COLUMN_QUERY,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY));
-        cv.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_SHORTCUT_ID));
-        // note: deliberately omitting background color since it is only for global search
-        // "more results" entries
-        mContext.getContentResolver().insert(uri, cv);
-    }
-
-    /**
-     * @return A URI appropriate for reporting a click.
-     */
-    private Uri getClickReportingUri() {
-        Uri.Builder uriBuilder = new Uri.Builder()
-                .scheme(ContentResolver.SCHEME_CONTENT)
-                .authority(SearchManager.SEARCH_CLICK_REPORT_AUTHORITY);
-
-        uriBuilder.appendPath(SearchManager.SEARCH_CLICK_REPORT_URI_PATH);
-
-        return uriBuilder
-                .query("")     // TODO: Remove, workaround for a bug in Uri.writeToParcel()
-                .fragment("")  // TODO: Remove, workaround for a bug in Uri.writeToParcel()
-                .build();
-    }
-
-    /**
-     * Wraps an icon for a particular package.  If the icon is a resource id, it is converted into
-     * an android.resource:// URI.
-     *
-     * @param packageName The source of the icon
-     * @param icon The icon retrieved from a suggestion column
-     * @return An icon string appropriate for the package.
-     */
-    private String wrapIconForPackage(String packageName, String icon) {
-        if (icon == null || icon.length() == 0 || "0".equals(icon)) {
-            // SearchManager specifies that null or zero can be returned to indicate
-            // no icon. We also allow empty string.
-            return null;
-        } else if (!Character.isDigit(icon.charAt(0))){
-            return icon;
-        } else {
-            return new Uri.Builder()
-                    .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
-                    .authority(packageName)
-                    .encodedPath(icon)
-                    .toString();
-        }
-    }
-
-    /**
      * Launches an intent, including any special intent handling.
      */
     private void launchIntent(Intent intent) {
         if (intent == null) {
             return;
         }
-        if (handleSpecialIntent(intent)){
-            return;
-        }
         Log.d(LOG_TAG, "launching " + intent);
         try {
-            // in global search mode, we send the activity straight to the original suggestion
-            // source. this is because GlobalSearch may not have permission to launch the
-            // intent, and to avoid the extra step of going through GlobalSearch.
-            if (mGlobalSearchMode) {
-                launchGlobalSearchIntent(intent);
-                if (mStoredComponentName != null) {
-                    // If we're embedded in an application, dismiss the dialog.
-                    // This ensures that if the intent is handled by the current
-                    // activity, it's not obscured by the dialog.
-                    dismiss();
-                }
-            } else {
-                // If the intent was created from a suggestion, it will always have an explicit
-                // component here.
-                Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI());
-                getContext().startActivity(intent);
-                // If the search switches to a different activity,
-                // SearchDialogWrapper#performActivityResuming
-                // will handle hiding the dialog when the next activity starts, but for
-                // real in-app search, we still need to dismiss the dialog.
-                if (isInRealAppSearch()) {
-                    dismiss();
-                }
-            }
+            // If the intent was created from a suggestion, it will always have an explicit
+            // component here.
+            Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI());
+            getContext().startActivity(intent);
+            // If the search switches to a different activity,
+            // SearchDialogWrapper#performActivityResuming
+            // will handle hiding the dialog when the next activity starts, but for
+            // real in-app search, we still need to dismiss the dialog.
+            dismiss();
         } catch (RuntimeException ex) {
             Log.e(LOG_TAG, "Failed launch activity: " + intent, ex);
         }
     }
 
-    private void launchGlobalSearchIntent(Intent intent) {
-        final String packageName;
-        // GlobalSearch puts the original source of the suggestion in the
-        // 'component name' column. If set, we send the intent to that activity.
-        // We trust GlobalSearch to always set this to the suggestion source.
-        String intentComponent = intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY);
-        if (intentComponent != null) {
-            ComponentName componentName = ComponentName.unflattenFromString(intentComponent);
-            intent.setComponent(componentName);
-            intent.removeExtra(SearchManager.COMPONENT_NAME_KEY);
-            // Launch the intent as the suggestion source.
-            // This prevents sources from using the search dialog to launch
-            // intents that they don't have permission for themselves.
-            packageName = componentName.getPackageName();
-        } else {
-            // If there is no component in the suggestion, it must be a built-in suggestion
-            // from GlobalSearch (e.g. "Search the web for") or the intent
-            // launched when pressing the search/go button in the search dialog.
-            // Launch the intent with the permissions of GlobalSearch.
-            packageName = mSearchable.getSearchActivity().getPackageName();
-        }
-
-        // Launch all global search suggestions as new tasks, since they don't relate
-        // to the current task.
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        setBrowserApplicationId(intent);
-
-        startActivityInPackage(intent, packageName);
-    }
-
     /**
      * If the intent is to open an HTTP or HTTPS URL, we set
      * {@link Browser#EXTRA_APPLICATION_ID} so that any existing browser window that
@@ -1372,106 +1092,6 @@
     }
 
     /**
-     * Starts an activity as if it had been started by the given package.
-     *
-     * @param intent The description of the activity to start.
-     * @param packageName
-     * @throws ActivityNotFoundException If the intent could not be resolved to
-     *         and existing activity.
-     * @throws SecurityException If the package does not have permission to start
-     *         start the activity.
-     * @throws AndroidRuntimeException If some other error occurs.
-     */
-    private void startActivityInPackage(Intent intent, String packageName) {
-        try {
-            int uid = ActivityThread.getPackageManager().getPackageUid(packageName);
-            if (uid < 0) {
-                throw new AndroidRuntimeException("Package UID not found " + packageName);
-            }
-            String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver());
-            IBinder resultTo = null;
-            String resultWho = null;
-            int requestCode = -1;
-            boolean onlyIfNeeded = false;
-            Log.i(LOG_TAG, "Starting (uid " + uid + ", " + packageName + ") " + intent.toURI());
-            int result = ActivityManagerNative.getDefault().startActivityInPackage(
-                    uid, intent, resolvedType, resultTo, resultWho, requestCode, onlyIfNeeded);
-            checkStartActivityResult(result, intent);
-        } catch (RemoteException ex) {
-            throw new AndroidRuntimeException(ex);
-        }
-    }
-
-    // Stolen from Instrumentation.checkStartActivityResult()
-    private static void checkStartActivityResult(int res, Intent intent) {
-        if (res >= IActivityManager.START_SUCCESS) {
-            return;
-        }
-        switch (res) {
-            case IActivityManager.START_INTENT_NOT_RESOLVED:
-            case IActivityManager.START_CLASS_NOT_FOUND:
-                if (intent.getComponent() != null)
-                    throw new ActivityNotFoundException(
-                            "Unable to find explicit activity class "
-                            + intent.getComponent().toShortString()
-                            + "; have you declared this activity in your AndroidManifest.xml?");
-                throw new ActivityNotFoundException(
-                        "No Activity found to handle " + intent);
-            case IActivityManager.START_PERMISSION_DENIED:
-                throw new SecurityException("Not allowed to start activity "
-                        + intent);
-            case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
-                throw new AndroidRuntimeException(
-                        "FORWARD_RESULT_FLAG used while also requesting a result");
-            default:
-                throw new AndroidRuntimeException("Unknown error code "
-                        + res + " when starting " + intent);
-        }
-    }
-
-    /**
-     * Handles the special intent actions declared in {@link SearchManager}.
-     * 
-     * @return <code>true</code> if the intent was handled.
-     */
-    private boolean handleSpecialIntent(Intent intent) {
-        String action = intent.getAction();
-        if (SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.equals(action)) {
-            handleChangeSourceIntent(intent);
-            return true;
-        }
-        return false;
-    }
-    
-    /**
-     * Handles {@link SearchManager#INTENT_ACTION_CHANGE_SEARCH_SOURCE}.
-     */
-    private void handleChangeSourceIntent(Intent intent) {
-        Uri dataUri = intent.getData();
-        if (dataUri == null) {
-            Log.w(LOG_TAG, "SearchManager.INTENT_ACTION_CHANGE_SOURCE without intent data.");
-            return;
-        }
-        ComponentName componentName = ComponentName.unflattenFromString(dataUri.toString());
-        if (componentName == null) {
-            Log.w(LOG_TAG, "Invalid ComponentName: " + dataUri);
-            return;
-        }
-        if (DBG) Log.d(LOG_TAG, "Switching to " + componentName);
-
-        pushPreviousComponent(mLaunchComponent);
-        if (!show(componentName, mAppSearchData, false)) {
-            Log.w(LOG_TAG, "Failed to switch to source " + componentName);
-            popPreviousComponent();
-            return;
-        }
-
-        String query = intent.getStringExtra(SearchManager.QUERY);
-        setUserQuery(query);
-        mSearchAutoComplete.showDropDown();
-    }
-
-    /**
      * Sets the list item selection in the AutoCompleteTextView's ListView.
      */
     public void setListSelection(int index) {
@@ -1479,61 +1099,6 @@
     }
 
     /**
-     * Checks if there are any previous searchable components in the history stack.
-     */
-    private boolean hasPreviousComponent() {
-        return mPreviousComponents != null && !mPreviousComponents.isEmpty();
-    }
-
-    /**
-     * Saves the previous component that was searched, so that we can go
-     * back to it.
-     */
-    private void pushPreviousComponent(ComponentName componentName) {
-        if (mPreviousComponents == null) {
-            mPreviousComponents = new ArrayList<ComponentName>();
-        }
-        mPreviousComponents.add(componentName);
-    }
-    
-    /**
-     * Pops the previous component off the stack and returns it.
-     * 
-     * @return The component name, or <code>null</code> if there was
-     *         no previous component.
-     */
-    private ComponentName popPreviousComponent() {
-        if (!hasPreviousComponent()) {
-            return null;
-        }
-        return mPreviousComponents.remove(mPreviousComponents.size() - 1);
-    }
-    
-    /**
-     * Goes back to the previous component that was searched, if any.
-     * 
-     * @return <code>true</code> if there was a previous component that we could go back to.
-     */
-    private boolean backToPreviousComponent() {
-        ComponentName previous = popPreviousComponent();
-        if (previous == null) {
-            return false;
-        }
-
-        if (!show(previous, mAppSearchData, false)) {
-            Log.w(LOG_TAG, "Failed to switch to source " + previous);
-            return false;
-        }
-
-        // must touch text to trigger suggestions
-        // TODO: should this be the text as it was when the user left
-        // the source that we are now going back to?
-        String query = mSearchAutoComplete.getText().toString();
-        setUserQuery(query);
-        return true;
-    }
-    
-    /**
      * When a particular suggestion has been selected, perform the various lookups required
      * to use the suggestion.  This includes checking the cursor for suggestion-specific data,
      * and/or falling back to the XML for defaults;  It also creates REST style Uri data when
@@ -1582,10 +1147,9 @@
 
             String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
             String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
-            String mode = mGlobalSearchMode ? SearchManager.MODE_GLOBAL_SEARCH_SUGGESTION : null;
 
             return createIntent(action, dataUri, extraData, query, componentName, actionKey,
-                    actionMsg, mode);
+                    actionMsg);
         } catch (RuntimeException e ) {
             int rowNum;
             try {                       // be really paranoid now
@@ -1616,16 +1180,13 @@
      * @return The intent.
      */
     private Intent createIntent(String action, Uri data, String extraData, String query,
-            String componentName, int actionKey, String actionMsg, String mode) {
+            String componentName, int actionKey, String actionMsg) {
         // Now build the Intent
         Intent intent = new Intent(action);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         // We need CLEAR_TOP to avoid reusing an old task that has other activities
         // on top of the one we want. We don't want to do this in in-app search though,
         // as it can be destructive to the activity stack.
-        if (mGlobalSearchMode) {
-            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        }
         if (data != null) {
             intent.setData(data);
         }
@@ -1636,9 +1197,6 @@
         if (extraData != null) {
             intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
         }
-        if (componentName != null) {
-            intent.putExtra(SearchManager.COMPONENT_NAME_KEY, componentName);
-        }
         if (mAppSearchData != null) {
             intent.putExtra(SearchManager.APP_DATA, mAppSearchData);
         }
@@ -1646,16 +1204,10 @@
             intent.putExtra(SearchManager.ACTION_KEY, actionKey);
             intent.putExtra(SearchManager.ACTION_MSG, actionMsg);
         }
-        if (mode != null) {
-            intent.putExtra(SearchManager.SEARCH_MODE, mode);
-        }
-        // Only allow 3rd-party intents from GlobalSearch
-        if (!mGlobalSearchMode) {
-            intent.setComponent(mSearchable.getSearchActivity());
-        }
+        intent.setComponent(mSearchable.getSearchActivity());
         return intent;
     }
-    
+
     /**
      * For a given suggestion and a given cursor row, get the action message.  If not provided
      * by the specific row/column, also check for a single definition (for the action key).
@@ -1812,12 +1364,8 @@
                 imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0)) {
             return;
         }
-        // Otherwise, go back to any previous source (e.g. back to QSB when
-        // pivoted into a source.
-        if (!backToPreviousComponent()) {
-            // If no previous source, close search dialog
-            cancel();
-        }
+        // Close search dialog
+        cancel();
     }
 
     /**
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 5a9a675..52cdc74 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -350,7 +350,7 @@
  * <p><b>Configuring your Content Provider to Receive Suggestion Queries.</b>  The basic job of
  * a search suggestions {@link android.content.ContentProvider Content Provider} is to provide
  * "live" (while-you-type) conversion of the user's query text into a set of zero or more 
- * suggestions.  Each application is free to define the conversion, and as described above there are
+ * suggestions. Each application is free to define the conversion, and as described above there are
  * many possible solutions.  This section simply defines how to communicate with the suggestion
  * provider.  
  * 
@@ -360,7 +360,8 @@
  * 
  * <p>Every query includes a Uri, and the Search Manager will format the Uri as shown:
  * <p><pre class="prettyprint">
- * content:// your.suggest.authority / your.suggest.path / SearchManager.SUGGEST_URI_PATH_QUERY</pre>
+ * content:// your.suggest.authority / your.suggest.path / SearchManager.SUGGEST_URI_PATH_QUERY
+ *    </pre>
  * 
  * <p>Your Content Provider can receive the query text in one of two ways.
  * <ul>
@@ -379,7 +380,7 @@
  * <p><b>Providing access to Content Providers that require permissions.</b>  If your content
  * provider declares an android:readPermission in your application's manifest, you must provide
  * access to the search infrastructure to the search suggestion path by including a path-permission
- * that grants android:readPermission access to "android.permission.GLOBAL_SEARCH".  Granting access
+ * that grants android:readPermission access to "android.permission.GLOBAL_SEARCH". Granting access
  * explicitly to the search infrastructure ensures it will be able to access the search suggestions
  * without needing to know ahead of time any other details of the permissions protecting your
  * provider.  Content providers that require no permissions are already available to the search
@@ -546,7 +547,8 @@
  * taken directly to a specific result.
  *   <ul>
  *   <li><b>Action:</b> {@link android.content.Intent#ACTION_VIEW ACTION_VIEW}</li>
- *   <li><b>Data:</b> a complete Uri, supplied by the cursor, that identifies the desired data.</li>
+ *   <li><b>Data:</b> a complete Uri, supplied by the cursor, that identifies the desired data.
+ *   </li>
  *   <li><b>Query:</b> query text supplied with the suggestion (probably ignored)</li>
  *   </ul>
  * </li>
@@ -570,7 +572,7 @@
  * 
  * <p><b>Suggestion Rewriting.</b>  If the user navigates through the suggestions list, the UI
  * may temporarily rewrite the user's query with a query that matches the currently selected 
- * suggestion.  This enables the user to see what query is being suggested, and also allows the user
+ * suggestion. This enables the user to see what query is being suggested, and also allows the user
  * to click or touch in the entry EditText element and make further edits to the query before
  * dispatching it.  In order to perform this correctly, the Search UI needs to know exactly what
  * text to rewrite the query with.
@@ -1289,15 +1291,6 @@
     public final static String SEARCH_MODE = "search_mode";
 
     /**
-     * Value for the {@link #SEARCH_MODE} key.
-     * This is used if the intent was launched by clicking a suggestion in global search
-     * mode (Quick Search Box).
-     *
-     * @hide
-     */
-    public static final String MODE_GLOBAL_SEARCH_SUGGESTION = "global_search_suggestion";
-
-    /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getIntExtra content.Intent.getIntExtra()}
      * to obtain the keycode that the user used to trigger this query.  It will be zero if the
@@ -1308,14 +1301,6 @@
     public final static String ACTION_KEY = "action_key";
     
     /**
-     * Intent component name key: This key will be used for the extra populated by the
-     * {@link #SUGGEST_COLUMN_INTENT_COMPONENT_NAME} column.
-     *
-     * {@hide}
-     */
-    public final static String COMPONENT_NAME_KEY = "intent_component_name_key";
-
-    /**
      * Intent extra data key: This key will be used for the extra populated by the
      * {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
      */
@@ -1329,58 +1314,6 @@
     public final static String EXTRA_SELECT_QUERY = "select_query";
 
     /**
-     * Defines the constants used in the communication between {@link android.app.SearchDialog} and
-     * the global search provider via {@link Cursor#respond(android.os.Bundle)}.
-     *
-     * @hide
-     */
-    public static class DialogCursorProtocol {
-
-        /**
-         * The sent bundle will contain this integer key, with a value set to one of the events
-         * below.
-         */
-        public final static String METHOD = "DialogCursorProtocol.method";
-
-        /**
-         * After data has been refreshed.
-         */
-        public final static int POST_REFRESH = 0;
-        public final static String POST_REFRESH_RECEIVE_ISPENDING
-                = "DialogCursorProtocol.POST_REFRESH.isPending";
-        public final static String POST_REFRESH_RECEIVE_DISPLAY_NOTIFY
-                = "DialogCursorProtocol.POST_REFRESH.displayNotify";
-
-        /**
-         * When a position has been clicked.
-         */
-        public final static int CLICK = 2;
-        public final static String CLICK_SEND_POSITION
-                = "DialogCursorProtocol.CLICK.sendPosition";
-        public final static String CLICK_SEND_MAX_DISPLAY_POS
-                = "DialogCursorProtocol.CLICK.sendDisplayPosition";
-        public final static String CLICK_SEND_ACTION_KEY
-                = "DialogCursorProtocol.CLICK.sendActionKey";
-        public final static String CLICK_SEND_ACTION_MSG
-                = "DialogCursorProtocol.CLICK.sendActionMsg";
-        public final static String CLICK_RECEIVE_SELECTED_POS
-                = "DialogCursorProtocol.CLICK.receiveSelectedPosition";
-
-        /**
-         * When the threshold received in {@link #POST_REFRESH_RECEIVE_DISPLAY_NOTIFY} is displayed.
-         */
-        public final static int THRESH_HIT = 3;
-
-        /**
-         * When a search is started without using a suggestion.
-         */
-        public final static int SEARCH = 4;
-        public final static String SEARCH_SEND_MAX_DISPLAY_POS
-                = "DialogCursorProtocol.SEARCH.sendDisplayPosition";
-        public final static String SEARCH_SEND_QUERY = "DialogCursorProtocol.SEARCH.query";
-    }
-
-    /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
      * to obtain the action message that was defined for a particular search action key and/or
@@ -1421,40 +1354,6 @@
     public final static String SHORTCUT_MIME_TYPE = 
             "vnd.android.cursor.item/vnd.android.search.suggest";
 
-
-    /**
-     * The authority of the provider to report clicks to when a click is detected after pivoting
-     * into a specific app's search from global search.
-     *
-     * In addition to the columns below, the suggestion columns are used to pass along the full
-     * suggestion so it can be shortcutted.
-     *
-     * @hide
-     */
-    public final static String SEARCH_CLICK_REPORT_AUTHORITY =
-            "com.android.globalsearch.stats";
-
-    /**
-     * The path the write goes to.
-     *
-     * @hide
-     */
-    public final static String SEARCH_CLICK_REPORT_URI_PATH = "click";
-
-    /**
-     * The column storing the query for the click.
-     *
-     * @hide
-     */
-    public final static String SEARCH_CLICK_REPORT_COLUMN_QUERY = "query";
-
-    /**
-     * The column storing the component name of the application that was pivoted into.
-     *
-     * @hide
-     */
-    public final static String SEARCH_CLICK_REPORT_COLUMN_COMPONENT = "component";
-
     /**
      * Column name for suggestions cursor.  <i>Unused - can be null or column can be omitted.</i>
      */
@@ -1531,10 +1430,7 @@
      */
     public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
     /**
-     * Column name for suggestions cursor.  <i>Optional.</i>  This column allows suggestions
-     *  to provide additional arbitrary data which will be included as an extra under the key
-     *  {@link #COMPONENT_NAME_KEY}. For use by the global search system only - if other providers
-     *  attempt to use this column, the value will be overwritten by global search.
+     * TODO: Remove
      *
      * @hide
      */
@@ -1594,27 +1490,6 @@
     public final static String SUGGEST_PARAMETER_LIMIT = "limit";
 
     /**
-     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
-     * the search dialog will switch to a different suggestion source when the
-     * suggestion is clicked. 
-     * 
-     * {@link #SUGGEST_COLUMN_INTENT_DATA} must contain
-     * the flattened {@link ComponentName} of the activity which is to be searched.
-     * 
-     * TODO: Should {@link #SUGGEST_COLUMN_INTENT_DATA} instead contain a URI in the format
-     * used by {@link android.provider.Applications}?
-     * 
-     * TODO: This intent should be protected by the same permission that we use
-     * for replacing the global search provider.
-     * 
-     * The query text field will be set to the value of {@link #SUGGEST_COLUMN_QUERY}.
-     * 
-     * @hide Pending API council approval.
-     */
-    public final static String INTENT_ACTION_CHANGE_SEARCH_SOURCE 
-            = "android.search.action.CHANGE_SEARCH_SOURCE";
-
-    /**
      * Intent action for starting the global search activity.
      * The global search provider should handle this intent.
      *
@@ -1663,7 +1538,7 @@
      * @hide
      */
     public final static String INTENT_ACTION_NONE = "android.search.action.ZILCH";
-    
+
     /**
      * Reference to the shared system search service.
      */
@@ -1672,13 +1547,6 @@
     private final Context mContext;
 
     /**
-     * compact representation of the activity associated with this search manager so
-     * we can say who we are when starting search.  the search managerservice, in turn,
-     * uses this to properly handle the back stack.
-     */
-    private int mIdent;
-
-    /**
      * The package associated with this seach manager.
      */
     private String mAssociatedPackage;
@@ -1696,21 +1564,6 @@
         mService = ISearchManager.Stub.asInterface(
                 ServiceManager.getService(Context.SEARCH_SERVICE));
     }
-
-    /*package*/ boolean hasIdent() {
-        return mIdent != 0;
-    }
-    
-    /*package*/ void setIdent(int ident, ComponentName component) {
-        if (mIdent != 0) {
-            throw new IllegalStateException("mIdent already set");
-        }
-        if (component == null) {
-            throw new IllegalArgumentException("component must be non-null");
-        }
-        mIdent = ident;
-        mAssociatedPackage = component.getPackageName();
-    }
     
     /**
      * Launch search UI.
@@ -1757,15 +1610,14 @@
                             ComponentName launchActivity,
                             Bundle appSearchData,
                             boolean globalSearch) {
-        ensureSearchDialog();
-
         if (globalSearch) {
             startGlobalSearch(initialQuery, selectInitialQuery, appSearchData);
             return;
         }
 
-        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
-                globalSearch);
+        ensureSearchDialog();
+
+        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData);
     }
 
     private void ensureSearchDialog() {
@@ -1994,17 +1846,6 @@
             return null;
         }
     }
-    
-    /**
-     * Checks whether the given searchable is the default searchable.
-     * 
-     * @hide because SearchableInfo is not part of the API.
-     */
-    public boolean isDefaultSearchable(SearchableInfo searchable) {
-        SearchableInfo defaultSearchable = getSearchableInfo(null, true);
-        return defaultSearchable != null 
-                && defaultSearchable.getSearchActivity().equals(searchable.getSearchActivity());
-    }
 
     /**
      * Gets a cursor with search suggestions.
@@ -2091,56 +1932,4 @@
         }
     }
 
-    /**
-     * Returns a list of the searchable activities that handle web searches.
-     *
-     * @return a list of all searchable activities that handle
-     *         {@link android.content.Intent#ACTION_WEB_SEARCH}.
-     *
-     * @hide because SearchableInfo is not part of the API.
-     */
-    public List<SearchableInfo> getSearchablesForWebSearch() {
-        try {
-            return mService.getSearchablesForWebSearch();
-        } catch (RemoteException e) {
-            Log.e(TAG, "getSearchablesForWebSearch() failed: " + e);
-            return null;
-        }
-    }
-
-    /**
-     * Returns the default searchable activity for web searches.
-     *
-     * @return searchable information for the activity handling web searches by default.
-     *
-     * @hide because SearchableInfo is not part of the API.
-     */
-    public SearchableInfo getDefaultSearchableForWebSearch() {
-        try {
-            return mService.getDefaultSearchableForWebSearch();
-        } catch (RemoteException e) {
-            Log.e(TAG, "getDefaultSearchableForWebSearch() failed: " + e);
-            return null;
-        }
-    }
-
-    /**
-     * Sets the default searchable activity for web searches.
-     *
-     * @param component Name of the component to set as default activity for web searches.
-     *
-     * @hide
-     */
-    public void setDefaultWebSearch(ComponentName component) {
-        try {
-            mService.setDefaultWebSearch(component);
-        } catch (RemoteException e) {
-            Log.e(TAG, "setDefaultWebSearch() failed: " + e);
-        }
-    }
-
-    private static void debug(String msg) {
-        Thread thread = Thread.currentThread();
-        Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
-    }
 }
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 173c3e1..57795d1 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -16,7 +16,6 @@
 
 package android.app;
 
-import android.app.SearchManager.DialogCursorProtocol;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -30,12 +29,10 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
 import android.net.Uri;
-import android.os.Bundle;
 import android.text.Html;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Filter;
@@ -65,7 +62,6 @@
     private Context mProviderContext;
     private WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache;
     private SparseArray<Drawable.ConstantState> mBackgroundsCache;
-    private boolean mGlobalSearchMode;
     private boolean mClosed = false;
 
     // Cached column indexes, updated when the cursor changes.
@@ -76,29 +72,8 @@
     private int mIconName2Col;
     private int mBackgroundColorCol;
     
-    // The extra used to tell a cursor to close itself. This is a hack, see the description by
-    // its use later in this file.
-    private static final String EXTRA_CURSOR_RESPOND_CLOSE_CURSOR = "cursor_respond_close_cursor";
-
-    // The bundle which contains {EXTRA_CURSOR_RESPOND_CLOSE_CURSOR=true}, just cached once
-    // so we don't bother recreating it a bunch.
-    private final Bundle mCursorRespondCloseCursorBundle;
-
-    // This value is stored in SuggestionsAdapter by the SearchDialog to indicate whether
-    // a particular list item should be selected upon the next call to notifyDataSetChanged.
-    // This is used to indicate the index of the "More results..." list item so that when
-    // the data set changes after a click of "More results...", we can correctly tell the
-    // ListView to scroll to the right line item. It gets reset to NONE every time it
-    // is consumed.
-    private int mListItemToSelect = NONE;
     static final int NONE = -1;
 
-    // holds the maximum position that has been displayed to the user
-    int mMaxDisplayed = NONE;
-
-    // holds the position that, when displayed, should result in notifying the cursor
-    int mDisplayNotifyPos = NONE;
-
     private final Runnable mStartSpinnerRunnable;
     private final Runnable mStopSpinnerRunnable;
 
@@ -110,8 +85,7 @@
 
     public SuggestionsAdapter(Context context, SearchDialog searchDialog,
             SearchableInfo searchable,
-            WeakHashMap<String, Drawable.ConstantState> outsideDrawablesCache,
-            boolean globalSearchMode) {
+            WeakHashMap<String, Drawable.ConstantState> outsideDrawablesCache) {
         super(context,
                 com.android.internal.R.layout.search_dropdown_item_icons_2line,
                 null,   // no initial cursor
@@ -126,7 +100,6 @@
 
         mOutsideDrawablesCache = outsideDrawablesCache;
         mBackgroundsCache = new SparseArray<Drawable.ConstantState>();
-        mGlobalSearchMode = globalSearchMode;
 
         mStartSpinnerRunnable = new Runnable() {
                 public void run() {
@@ -140,10 +113,6 @@
             }
         };
         
-        // Create this once because we'll reuse it a bunch.
-        mCursorRespondCloseCursorBundle = new Bundle();
-        mCursorRespondCloseCursorBundle.putBoolean(EXTRA_CURSOR_RESPOND_CLOSE_CURSOR, true);
-
         // delay 500ms when deleting
         getFilter().setDelayer(new Filter.Delayer() {
 
@@ -177,27 +146,22 @@
     public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
         if (DBG) Log.d(LOG_TAG, "runQueryOnBackgroundThread(" + constraint + ")");
         String query = (constraint == null) ? "" : constraint.toString();
-        if (!mGlobalSearchMode) {
-            /**
-             * for in app search we show the progress spinner until the cursor is returned with
-             * the results.  for global search we manage the progress bar using
-             * {@link DialogCursorProtocol#POST_REFRESH_RECEIVE_ISPENDING}.
-             */
-            mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
-        }
+        /**
+         * for in app search we show the progress spinner until the cursor is returned with
+         * the results.
+         */
+        mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
         try {
             final Cursor cursor = mSearchManager.getSuggestions(mSearchable, query, QUERY_LIMIT);
             // trigger fill window so the spinner stays up until the results are copied over and
             // closer to being ready
-            if (!mGlobalSearchMode && cursor != null) cursor.getCount();
+            if (cursor != null) cursor.getCount();
             return cursor;
         } catch (RuntimeException e) {
             Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
             return null;
         } finally {
-            if (!mGlobalSearchMode) {
-                mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
-            }
+            mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
         }
     }
 
@@ -221,21 +185,8 @@
         }
 
         try {
-            Cursor oldCursor = getCursor();
             super.changeCursor(c);
-            
-            // We send a special respond to the cursor to tell it to close itself directly because
-            // it may not happen correctly for some cursors currently. This was originally
-            // included as a fix to http://b/2036290, in which the search dialog was holding
-            // on to references to the web search provider unnecessarily. This is being caused by
-            // the fact that the cursor is not being correctly closed in
-            // BulkCursorToCursorAdapter#close, which remains unfixed (see http://b/2015069).
-            //
-            // TODO: Remove this hack once http://b/2015069 is fixed.
-            if (oldCursor != null && oldCursor != c) {
-                oldCursor.respond(mCursorRespondCloseCursorBundle);
-            }
-            
+
             if (c != null) {
                 mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
                 mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
@@ -249,79 +200,6 @@
         }
     }
 
-    @Override
-    public void notifyDataSetChanged() {
-        if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
-        super.notifyDataSetChanged();
-
-        callCursorPostRefresh(mCursor);
-
-        // look out for the pending item we are supposed to scroll to
-        if (mListItemToSelect != NONE) {
-            mSearchDialog.setListSelection(mListItemToSelect);
-            mListItemToSelect = NONE;
-        }
-    }
-
-    /**
-     * Handle sending and receiving information associated with
-     * {@link DialogCursorProtocol#POST_REFRESH}.
-     *
-     * @param cursor The cursor to call.
-     */
-    private void callCursorPostRefresh(Cursor cursor) {
-        if (!mGlobalSearchMode) return;
-        final Bundle request = new Bundle();
-        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.POST_REFRESH);
-        final Bundle response = cursor.respond(request);
-
-        mSearchDialog.setWorking(
-                response.getBoolean(DialogCursorProtocol.POST_REFRESH_RECEIVE_ISPENDING, false));
-
-        mDisplayNotifyPos =
-                response.getInt(DialogCursorProtocol.POST_REFRESH_RECEIVE_DISPLAY_NOTIFY, -1);
-    }
-
-    /**
-     * Tell the cursor which position was clicked, handling sending and receiving information
-     * associated with {@link DialogCursorProtocol#CLICK}.
-     *
-     * @param cursor The cursor
-     * @param position The position that was clicked.
-     */
-    void callCursorOnClick(Cursor cursor, int position, int actionKey, String actionMsg) {
-        if (!mGlobalSearchMode) return;
-        final Bundle request = new Bundle(5);
-        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
-        request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
-        request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
-        if (actionKey != KeyEvent.KEYCODE_UNKNOWN) {
-            request.putInt(DialogCursorProtocol.CLICK_SEND_ACTION_KEY, actionKey);
-            request.putString(DialogCursorProtocol.CLICK_SEND_ACTION_MSG, actionMsg);
-        }
-        final Bundle response = cursor.respond(request);
-        mMaxDisplayed = -1;
-        mListItemToSelect = response.getInt(
-                DialogCursorProtocol.CLICK_RECEIVE_SELECTED_POS, SuggestionsAdapter.NONE);
-    }
-
-    /**
-     * Tell the cursor that a search was started without using a suggestion.
-     *
-     * @param query The search query.
-     */
-    void reportSearch(String query) {
-        if (!mGlobalSearchMode) return;
-        Cursor cursor = getCursor();
-        if (cursor == null) return;
-        final Bundle request = new Bundle(3);
-        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.SEARCH);
-        request.putString(DialogCursorProtocol.SEARCH_SEND_QUERY, query);
-        request.putInt(DialogCursorProtocol.SEARCH_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
-        // the response is always empty
-        cursor.respond(request);
-    }
-
     /**
      * Tags the view with cached child view look-ups.
      */
@@ -353,20 +231,6 @@
     @Override
     public void bindView(View view, Context context, Cursor cursor) {
         ChildViewCache views = (ChildViewCache) view.getTag();
-        final int pos = cursor.getPosition();
-
-        // update the maximum position displayed since last refresh
-        if (pos > mMaxDisplayed) {
-            mMaxDisplayed = pos;
-        }
-
-        // if the cursor wishes to be notified about this position, send it
-        if (mGlobalSearchMode && mDisplayNotifyPos != NONE && pos == mDisplayNotifyPos) {
-            final Bundle request = new Bundle();
-            request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.THRESH_HIT);
-            mCursor.respond(request);
-            mDisplayNotifyPos = NONE;  // only notify the first time
-        }
 
         int backgroundColor = 0;
         if (mBackgroundColorCol != -1) {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 544e399..acb8473 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -608,6 +608,45 @@
     }
 
     /**
+     * URI parameter and cursor extras that return counts of rows grouped by the
+     * address book index, which is usually the first letter of the sort key.
+     * When this parameter is supplied, the row counts are returned in the
+     * cursor extras bundle.
+     *
+     * @hide
+     */
+    public final static class ContactCounts {
+
+        /**
+         * Add this query parameter to a URI to get back row counts grouped by
+         * the address book index as cursor extras. For most languages it is the
+         * first letter of the sort key. This parameter does not affect the main
+         * content of the cursor.
+         *
+         * @hide
+         */
+        public static final String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
+
+        /**
+         * The array of address book index titles, which are returned in the
+         * same order as the data in the cursor.
+         * <p>TYPE: String[]</p>
+         *
+         * @hide
+         */
+        public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+
+        /**
+         * The array of group counts for the corresponding group.  Contains the same number
+         * of elements as the EXTRA_ADDRESS_BOOK_INDEX_TITLES array.
+         * <p>TYPE: int[]</p>
+         *
+         * @hide
+         */
+        public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
+    }
+
+    /**
      * Constants for the contacts table, which contains a record per aggregate
      * of raw contacts representing the same person.
      * <h3>Operations</h3>
@@ -5695,5 +5734,4 @@
             public static final String IM_ISPRIMARY = "im_isprimary";
         }
     }
-
 }
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 22bb43c..096ad39 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -121,10 +121,44 @@
                         handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED);
                     }
                 }
+            } else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
+                int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+                if (streamType == AudioManager.STREAM_MUSIC) {
+                    BluetoothDevice sinks[] = getConnectedSinks();
+                    if (sinks.length != 0 && isPhoneDocked(sinks[0])) {
+                        String address = sinks[0].getAddress();
+                        int newVolLevel =
+                          intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0);
+                        int oldVolLevel =
+                          intent.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0);
+                        String path = mBluetoothService.getObjectPathFromAddress(address);
+                        if (newVolLevel > oldVolLevel) {
+                            avrcpVolumeUpNative(path);
+                        } else if (newVolLevel < oldVolLevel) {
+                            avrcpVolumeDownNative(path);
+                        }
+                    }
+                }
             }
         }
     };
 
+
+    private boolean isPhoneDocked(BluetoothDevice device) {
+        // This works only because these broadcast intents are "sticky"
+        Intent i = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+        if (i != null) {
+            int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
+            if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                BluetoothDevice dockDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                if (dockDevice != null && device.equals(dockDevice)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     public BluetoothA2dpService(Context context, BluetoothService bluetoothService) {
         mContext = context;
 
@@ -145,6 +179,7 @@
         mIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
         mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+        mIntentFilter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
         mContext.registerReceiver(mReceiver, mIntentFilter);
 
         mAudioDevices = new HashMap<BluetoothDevice, Integer>();
@@ -551,4 +586,6 @@
     private synchronized native boolean suspendSinkNative(String path);
     private synchronized native boolean resumeSinkNative(String path);
     private synchronized native Object []getSinkPropertiesNative(String path);
+    private synchronized native boolean avrcpVolumeUpNative(String path);
+    private synchronized native boolean avrcpVolumeDownNative(String path);
 }
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index dfb775f..aa20ac4 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -136,6 +136,14 @@
             }
             return false;
         }
+
+        @Override
+        public int hashCode() {
+            int hash = 1;
+            hash = hash * 31 + (address == null ? 0 : address.hashCode());
+            hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
+            return hash;
+        }
     }
 
     static {
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index afc6864..1023036 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -39,6 +39,8 @@
  */
 public abstract class Layout {
     private static final boolean DEBUG = false;
+    private static final ParagraphStyle[] NO_PARA_SPANS =
+        ArrayUtils.emptyArray(ParagraphStyle.class);
 
     /* package */ static final EmojiFactory EMOJI_FACTORY =
         EmojiFactory.newAvailableInstance();
@@ -57,7 +59,7 @@
     private RectF mEmojiRect;
 
     /**
-     * Return how wide a layout would be necessary to display the
+     * Return how wide a layout must be in order to display the
      * specified text with one line per paragraph.
      */
     public static float getDesiredWidth(CharSequence source,
@@ -66,7 +68,7 @@
     }
     
     /**
-     * Return how wide a layout would be necessary to display the
+     * Return how wide a layout must be in order to display the
      * specified text slice with one line per paragraph.
      */
     public static float getDesiredWidth(CharSequence source,
@@ -82,6 +84,7 @@
             if (next < 0)
                 next = end;
 
+            // note, omits trailing paragraph char
             float w = measureText(paint, workPaint,
                                   source, i, next, null, true, null);
 
@@ -97,10 +100,19 @@
     /**
      * Subclasses of Layout use this constructor to set the display text,
      * width, and other standard properties.
+     * @param text the text to render
+     * @param paint the default paint for the layout.  Styles can override
+     * various attributes of the paint.
+     * @param width the wrapping width for the text.
+     * @param align whether to left, right, or center the text.  Styles can
+     * override the alignment.
+     * @param spacingMult factor by which to scale the font size to get the
+     * default line spacing
+     * @param spacingAdd amount to add to the default line spacing
      */
     protected Layout(CharSequence text, TextPaint paint,
                      int width, Alignment align,
-                     float spacingmult, float spacingadd) {
+                     float spacingMult, float spacingAdd) {
         if (width < 0)
             throw new IllegalArgumentException("Layout: " + width + " < 0");
 
@@ -109,8 +121,8 @@
         mWorkPaint = new TextPaint();
         mWidth = width;
         mAlignment = align;
-        mSpacingMult = spacingmult;
-        mSpacingAdd = spacingadd;
+        mSpacingMult = spacingMult;
+        mSpacingAdd = spacingAdd;
         mSpannedText = text instanceof Spanned;
     }
 
@@ -141,10 +153,16 @@
     }
 
     /**
-     * Draw the specified rectangle from this Layout on the specified Canvas,
-     * with the specified path drawn between the background and the text.
+     * Draw this Layout on the specified canvas, with the highlight path drawn
+     * between the background and the text.
+     *
+     * @param c the canvas
+     * @param highlight the path of the highlight or cursor; can be null
+     * @param highlightPaint the paint for the highlight
+     * @param cursorOffsetVertical the amount to temporarily translate the
+     *        canvas while rendering the highlight
      */
-    public void draw(Canvas c, Path highlight, Paint highlightpaint,
+    public void draw(Canvas c, Path highlight, Paint highlightPaint,
                      int cursorOffsetVertical) {
         int dtop, dbottom;
 
@@ -157,13 +175,10 @@
             dbottom = sTempRect.bottom;
         }
 
-        TextPaint paint = mPaint;
 
         int top = 0;
-        // getLineBottom(getLineCount() -1) just calls getLineTop(getLineCount) 
         int bottom = getLineTop(getLineCount());
 
-
         if (dtop > top) {
             top = dtop;
         }
@@ -177,16 +192,19 @@
         int previousLineBottom = getLineTop(first);
         int previousLineEnd = getLineStart(first);
         
+        TextPaint paint = mPaint;
         CharSequence buf = mText;
-
-        ParagraphStyle[] nospans = ArrayUtils.emptyArray(ParagraphStyle.class);
-        ParagraphStyle[] spans = nospans;
-        int spanend = 0;
-        int textLength = 0;
+        int width = mWidth;
         boolean spannedText = mSpannedText;
 
+        ParagraphStyle[] spans = NO_PARA_SPANS;
+        int spanend = 0;
+        int textLength = 0;
+
+        // First, draw LineBackgroundSpans.
+        // LineBackgroundSpans know nothing about the alignment or direction of
+        // the layout or line.  XXX: Should they?
         if (spannedText) {
-            spanend = 0;
             textLength = buf.length();
             for (int i = first; i <= last; i++) {
                 int start = previousLineEnd;
@@ -209,7 +227,7 @@
                 for (int n = 0; n < spans.length; n++) {
                     LineBackgroundSpan back = (LineBackgroundSpan) spans[n];
 
-                    back.drawBackground(c, paint, 0, mWidth,
+                    back.drawBackground(c, paint, 0, width,
                                        ltop, lbaseline, lbottom,
                                        buf, start, end,
                                        i);
@@ -219,7 +237,7 @@
             spanend = 0;
             previousLineBottom = getLineTop(first);
             previousLineEnd = getLineStart(first);
-            spans = nospans;
+            spans = NO_PARA_SPANS;
         } 
 
         // There can be a highlight even without spans if we are drawing
@@ -229,7 +247,7 @@
                 c.translate(0, cursorOffsetVertical);
             }
 
-            c.drawPath(highlight, highlightpaint);
+            c.drawPath(highlight, highlightPaint);
 
             if (cursorOffsetVertical != 0) {
                 c.translate(0, -cursorOffsetVertical);
@@ -238,6 +256,9 @@
 
         Alignment align = mAlignment;
         
+        // Next draw the lines, one at a time.
+        // the baseline is the top of the following line minus the current
+        // line's descent.
         for (int i = first; i <= last; i++) {
             int start = previousLineEnd;
 
@@ -249,21 +270,20 @@
             previousLineBottom = lbottom;
             int lbaseline = lbottom - getLineDescent(i);
 
-            boolean par = false;
+            boolean isFirstParaLine = false;
             if (spannedText) { 
                 if (start == 0 || buf.charAt(start - 1) == '\n') {
-                    par = true;
+                    isFirstParaLine = true;
                 }
+                // New batch of paragraph styles, compute the alignment.
+                // Last alignment style wins.
                 if (start >= spanend) {
-
                     Spanned sp = (Spanned) buf;
-
                     spanend = sp.nextSpanTransition(start, textLength,
                                                     ParagraphStyle.class);
                     spans = sp.getSpans(start, spanend, ParagraphStyle.class);
                     
                     align = mAlignment;
-                    
                     for (int n = spans.length-1; n >= 0; n--) {
                         if (spans[n] instanceof AlignmentSpan) {
                             align = ((AlignmentSpan) spans[n]).getAlignment();
@@ -277,6 +297,8 @@
             int left = 0;
             int right = mWidth;
 
+            // Draw all leading margin spans.  Adjust left or right according
+            // to the paragraph direction of the line.
             if (spannedText) {
                 final int length = spans.length;
                 for (int n = 0; n < length; n++) {
@@ -286,15 +308,15 @@
                         if (dir == DIR_RIGHT_TO_LEFT) {
                             margin.drawLeadingMargin(c, paint, right, dir, ltop,
                                                      lbaseline, lbottom, buf,
-                                                     start, end, par, this);
+                                                     start, end, isFirstParaLine, this);
                                 
-                            right -= margin.getLeadingMargin(par);
+                            right -= margin.getLeadingMargin(isFirstParaLine);
                         } else {
                             margin.drawLeadingMargin(c, paint, left, dir, ltop,
                                                      lbaseline, lbottom, buf,
-                                                     start, end, par, this);
+                                                     start, end, isFirstParaLine, this);
 
-                            boolean useMargin = par;
+                            boolean useMargin = isFirstParaLine;
                             if (margin instanceof LeadingMarginSpan.LeadingMarginSpan2) {
                                 int count = ((LeadingMarginSpan.LeadingMarginSpan2)margin).getLeadingMarginLineCount();
                                 useMargin = count > i;
@@ -305,6 +327,8 @@
                 }
             }
 
+            // Adjust the point at which to start rendering depending on the
+            // alignment of the paragraph.
             int x;
             if (align == Alignment.ALIGN_NORMAL) {
                 if (dir == DIR_LEFT_TO_RIGHT) {
@@ -340,6 +364,7 @@
                     Assert.assertTrue(dir == DIR_LEFT_TO_RIGHT);
                     Assert.assertNotNull(c);
                 }
+                // XXX: assumes there's nothing additional to be done
                 c.drawText(buf, start, end, x, lbaseline, paint);
             } else {
                 drawText(c, buf, start, end, dir, directions,
@@ -382,7 +407,7 @@
 
     /**
      * Increase the width of this layout to the specified width.
-     * Be careful to use this only when you know it is appropriate --
+     * Be careful to use this only when you know it is appropriate&mdash;
      * it does not cause the text to reflow to use the full new width.
      */
     public final void increaseWidthTo(int wid) {
@@ -397,7 +422,7 @@
      * Return the total height of this layout.
      */
     public int getHeight() {
-        return getLineTop(getLineCount());  // same as getLineBottom(getLineCount() - 1);
+        return getLineTop(getLineCount());
     }
 
     /**
@@ -439,33 +464,35 @@
             bounds.left = 0;     // ???
             bounds.top = getLineTop(line);
             bounds.right = mWidth;   // ???
-            bounds.bottom = getLineBottom(line);
+            bounds.bottom = getLineTop(line + 1);
         }
         return getLineBaseline(line);
     }
 
     /**
-     * Return the vertical position of the top of the specified line.
-     * If the specified line is one beyond the last line, returns the
+     * Return the vertical position of the top of the specified line
+     * (0&hellip;getLineCount()).
+     * If the specified line is equal to the line count, returns the
      * bottom of the last line.
      */
     public abstract int getLineTop(int line);
 
     /**
-     * Return the descent of the specified line.
+     * Return the descent of the specified line(0&hellip;getLineCount() - 1).
      */
     public abstract int getLineDescent(int line);
 
     /**
-     * Return the text offset of the beginning of the specified line.
-     * If the specified line is one beyond the last line, returns the
-     * end of the last line.
+     * Return the text offset of the beginning of the specified line (
+     * 0&hellip;getLineCount()). If the specified line is equal to the line
+     * count, returns the length of the text.
      */
     public abstract int getLineStart(int line);
 
     /**
-     * Returns the primary directionality of the paragraph containing
-     * the specified line.
+     * Returns the primary directionality of the paragraph containing the
+     * specified line, either 1 for left-to-right lines, or -1 for right-to-left
+     * lines (see {@link #DIR_LEFT_TO_RIGHT}, {@link #DIR_RIGHT_TO_LEFT}).
      */
     public abstract int getParagraphDirection(int line);
 
@@ -477,9 +504,11 @@
     public abstract boolean getLineContainsTab(int line);
 
     /**
-     * Returns an array of directionalities for the specified line.
+     * Returns the directional run information for the specified line.
      * The array alternates counts of characters in left-to-right
      * and right-to-left segments of the line.
+     *
+     * <p>NOTE: this is inadequate to support bidirectional text, and will change.
      */
     public abstract Directions getLineDirections(int line);
 
@@ -1565,6 +1594,21 @@
         return h;
     }
 
+    /**
+     * Measure width of a run of text on a single line that is known to all be
+     * in the same direction as the paragraph base direction. Returns the width,
+     * and the line metrics in fm if fm is not null.
+     *
+     * @param paint the paint for the text; will not be modified
+     * @param workPaint paint available for modification
+     * @param text text
+     * @param start start of the line
+     * @param end limit of the line
+     * @param fm object to return integer metrics in, can be null
+     * @param hasTabs true if it is known that the line has tabs
+     * @param tabs tab position information
+     * @return the width of the text from start to end
+     */
     /* package */ static float measureText(TextPaint paint,
                                            TextPaint workPaint,
                                            CharSequence text,
@@ -1580,37 +1624,36 @@
 
         int len = end - start;
 
-        int here = 0;
-        float h = 0;
-        int ab = 0, be = 0;
-        int top = 0, bot = 0;
+        int lastPos = 0;
+        float width = 0;
+        int ascent = 0, descent = 0, top = 0, bottom = 0;
 
         if (fm != null) {
             fm.ascent = 0;
             fm.descent = 0;
         }
 
-        for (int i = hasTabs ? 0 : len; i <= len; i++) {
+        for (int pos = hasTabs ? 0 : len; pos <= len; pos++) {
             int codept = 0;
             Bitmap bm = null;
 
-            if (hasTabs && i < len) {
-                codept = buf[i];
+            if (hasTabs && pos < len) {
+                codept = buf[pos];
             }
 
-            if (codept >= 0xD800 && codept <= 0xDFFF && i < len) {
-                codept = Character.codePointAt(buf, i);
+            if (codept >= 0xD800 && codept <= 0xDFFF && pos < len) {
+                codept = Character.codePointAt(buf, pos);
 
                 if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
                     bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
                 }
             }
 
-            if (i == len || codept == '\t' || bm != null) {
+            if (pos == len || codept == '\t' || bm != null) {
                 workPaint.baselineShift = 0;
 
-                h += Styled.measureText(paint, workPaint, text,
-                                        start + here, start + i,
+                width += Styled.measureText(paint, workPaint, text,
+                                        start + lastPos, start + pos,
                                         fm);
 
                 if (fm != null) {
@@ -1623,60 +1666,80 @@
                     }
                 }
 
-                if (i != len) {
+                if (pos != len) {
                     if (bm == null) {
-                        h = nextTab(text, start, end, h, tabs);
+                        // no emoji, must have hit a tab
+                        width = nextTab(text, start, end, width, tabs);
                     } else {
+                        // This sets up workPaint with the font on the emoji
+                        // text, so that we can extract the ascent and scale.
+
+                        // We can't use the result of the previous call to
+                        // measureText because the emoji might have its own style.
+                        // We have to initialize workPaint here because if the
+                        // text is unstyled measureText might not use workPaint
+                        // at all.
                         workPaint.set(paint);
                         Styled.measureText(paint, workPaint, text,
-                                           start + i, start + i + 1, null);
+                                           start + pos, start + pos + 1, null);
 
-                        float wid = (float) bm.getWidth() *
+                        width += (float) bm.getWidth() *
                                     -workPaint.ascent() / bm.getHeight();
 
-                        h += wid;
-                        i++;
+                        // Since we had an emoji, we bump past the second half
+                        // of the surrogate pair.
+                        pos++;
                     }
                 }
 
                 if (fm != null) {
-                    if (fm.ascent < ab) {
-                        ab = fm.ascent;
+                    if (fm.ascent < ascent) {
+                        ascent = fm.ascent;
                     }
-                    if (fm.descent > be) {
-                        be = fm.descent;
+                    if (fm.descent > descent) {
+                        descent = fm.descent;
                     }
 
                     if (fm.top < top) {
                         top = fm.top;
                     }
-                    if (fm.bottom > bot) {
-                        bot = fm.bottom;
+                    if (fm.bottom > bottom) {
+                        bottom = fm.bottom;
                     }
 
-                    /*
-                     * No need to take bitmap height into account here,
-                     * since it is scaled to match the text height.
-                     */
+                    // No need to take bitmap height into account here,
+                    // since it is scaled to match the text height.
                 }
 
-                here = i + 1;
+                lastPos = pos + 1;
             }
         }
 
         if (fm != null) {
-            fm.ascent = ab;
-            fm.descent = be;
+            fm.ascent = ascent;
+            fm.descent = descent;
             fm.top = top;
-            fm.bottom = bot;
+            fm.bottom = bottom;
         }
 
         if (hasTabs)
             TextUtils.recycle(buf);
 
-        return h;
+        return width;
     }
 
+    /**
+     * Returns the position of the next tab stop after h on the line.
+     *
+     * @param text the text
+     * @param start start of the line
+     * @param end limit of the line
+     * @param h the current horizontal offset
+     * @param tabs the tabs, can be null.  If it is null, any tabs in effect
+     * on the line will be used.  If there are no tabs, a default offset
+     * will be used to compute the tab stop.
+     * @return the offset of the next tab stop.
+     */
     /* package */ static float nextTab(CharSequence text, int start, int end,
                                        float h, Object[] tabs) {
         float nh = Float.MAX_VALUE;
@@ -1747,6 +1810,16 @@
     public static class Directions {
         private short[] mDirections;
 
+        // The values in mDirections are the offsets from the first character
+        // in the line to the next flip in direction.  Runs at even indices
+        // are left-to-right, the others are right-to-left.  So, for example,
+        // a line that starts with a right-to-left run has 0 at mDirections[0],
+        // since the 'first' (ltr) run is zero length.
+        //
+        // The code currently assumes that each run is adjacent to the previous
+        // one, progressing in the base line direction.  This isn't sufficient
+        // to handle nested runs, for example numeric text in an rtl context
+        // in an ltr paragraph.
         /* package */ Directions(short[] dirs) {
             mDirections = dirs;
         }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index fbf1261..6c89f92 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -1012,6 +1012,10 @@
         int extra;
 
         if (needMultiply) {
+            // XXX: this looks like it is using the +0.5 and the cast to int
+            // to do rounding, but this I expect this isn't doing the intended
+            // thing when spacingmult < 1.  An intended extra of, say, -1.2
+            // will get 'rounded' to -.7 and then truncated to 0.
             extra = (int) ((below - above) * (spacingmult - 1)
                            + spacingadd + 0.5);
         } else {
diff --git a/core/java/android/text/Styled.java b/core/java/android/text/Styled.java
index 0aa2004..513b2cd 100644
--- a/core/java/android/text/Styled.java
+++ b/core/java/android/text/Styled.java
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.text;
 
 import android.graphics.Canvas;
@@ -23,27 +22,49 @@
 import android.text.style.ReplacementSpan;
 
 /**
- * This class provides static methods for drawing and measuring styled texts, like
- * {@link android.text.Spanned} object with {@link android.text.style.ReplacementSpan}.
+ * This class provides static methods for drawing and measuring styled text,
+ * like {@link android.text.Spanned} object with
+ * {@link android.text.style.ReplacementSpan}.
+ *
  * @hide
  */
 public class Styled
 {
-    private static float each(Canvas canvas,
+    /**
+     * Draws and/or measures a uniform run of text on a single line. No span of
+     * interest should start or end in the middle of this run (if not
+     * drawing, character spans that don't affect metrics can be ignored).
+     * Neither should the run direction change in the middle of the run.
+     *
+     * <p>The x position is the leading edge of the text. In a right-to-left
+     * paragraph, this will be to the right of the text to be drawn. Paint
+     * should not have an Align value other than LEFT or positioning will get
+     * confused.
+     *
+     * <p>On return, workPaint will reflect the original paint plus any
+     * modifications made by character styles on the run.
+     *
+     * <p>The returned width is signed and will be < 0 if the paragraph
+     * direction is right-to-left.
+     */
+    private static float drawUniformRun(Canvas canvas,
                               Spanned text, int start, int end,
-                              int dir, boolean reverse,
+                              int dir, boolean runIsRtl,
                               float x, int top, int y, int bottom,
                               Paint.FontMetricsInt fmi,
                               TextPaint paint,
                               TextPaint workPaint,
-                              boolean needwid) {
+                              boolean needWidth) {
 
-        boolean havewid = false;
+        boolean haveWidth = false;
         float ret = 0;
         CharacterStyle[] spans = text.getSpans(start, end, CharacterStyle.class);
 
         ReplacementSpan replacement = null;
 
+        // XXX: This shouldn't be modifying paint, only workPaint.
+        // However, the members belonging to TextPaint should have default
+        // values anyway.  Better to ensure this in the Layout constructor.
         paint.bgColor = 0;
         paint.baselineShift = 0;
         workPaint.set(paint);
@@ -65,9 +86,10 @@
             CharSequence tmp;
             int tmpstart, tmpend;
 
-            if (reverse) {
+            if (runIsRtl) {
                 tmp = TextUtils.getReverse(text, start, end);
                 tmpstart = 0;
+                // XXX: assumes getReverse doesn't change the length of the text
                 tmpend = end - start;
             } else {
                 tmp = text;
@@ -86,9 +108,9 @@
                     workPaint.setColor(workPaint.bgColor);
                     workPaint.setStyle(Paint.Style.FILL);
 
-                    if (!havewid) {
+                    if (!haveWidth) {
                         ret = workPaint.measureText(tmp, tmpstart, tmpend);
-                        havewid = true;
+                        haveWidth = true;
                     }
 
                     if (dir == Layout.DIR_RIGHT_TO_LEFT)
@@ -101,18 +123,18 @@
                 }
 
                 if (dir == Layout.DIR_RIGHT_TO_LEFT) {
-                    if (!havewid) {
+                    if (!haveWidth) {
                         ret = workPaint.measureText(tmp, tmpstart, tmpend);
-                        havewid = true;
+                        haveWidth = true;
                     }
 
                     canvas.drawText(tmp, tmpstart, tmpend,
                                     x - ret, y + workPaint.baselineShift, workPaint);
                 } else {
-                    if (needwid) {
-                        if (!havewid) {
+                    if (needWidth) {
+                        if (!haveWidth) {
                             ret = workPaint.measureText(tmp, tmpstart, tmpend);
-                            havewid = true;
+                            haveWidth = true;
                         }
                     }
 
@@ -120,9 +142,9 @@
                                     x, y + workPaint.baselineShift, workPaint);
                 }
             } else {
-                if (needwid && !havewid) {
+                if (needWidth && !haveWidth) {
                     ret = workPaint.measureText(tmp, tmpstart, tmpend);
-                    havewid = true;
+                    haveWidth = true;
                 }
             }
         } else {
@@ -145,25 +167,28 @@
     }
 
     /**
-     * Return the advance widths for the characters in the string.
-     * See also {@link android.graphics.Paint#getTextWidths(CharSequence, int, int, float[])}.
+     * Returns the advance widths for a uniform left-to-right run of text with
+     * no style changes in the middle of the run. If any style is replacement
+     * text, the first character will get the width of the replacement and the
+     * remaining characters will get a width of 0.
      * 
-     * @param paint The main {@link TextPaint} object.
-     * @param workPaint The {@link TextPaint} object used for temporal workspace.
-     * @param text The text to measure
-     * @param start The index of the first char to to measure
-     * @param end The end of the text slice to measure
-     * @param widths Array to receive the advance widths of the characters.
-     * Must be at least a large as (end - start).
-     * @param fmi FontMetrics information. Can be null.
-     * @return The actual number of widths returned. 
+     * @param paint the paint, will not be modified
+     * @param workPaint a paint to modify; on return will reflect the original
+     *        paint plus the effect of all spans on the run
+     * @param text the text
+     * @param start the start of the run
+     * @param end the limit of the run
+     * @param widths array to receive the advance widths of the characters. Must
+     *        be at least a large as (end - start).
+     * @param fmi FontMetrics information; can be null
+     * @return the actual number of widths returned
      */
     public static int getTextWidths(TextPaint paint,
                                     TextPaint workPaint,
                                     Spanned text, int start, int end,
                                     float[] widths, Paint.FontMetricsInt fmi) {
-        //  Keep workPaint as is so that developers reuse the workspace.
-        MetricAffectingSpan[] spans = text.getSpans(start, end, MetricAffectingSpan.class);
+        MetricAffectingSpan[] spans =
+            text.getSpans(start, end, MetricAffectingSpan.class);
 
 		ReplacementSpan replacement = null;
         workPaint.set(paint);
@@ -186,7 +211,6 @@
 
             if (end > start) {
                 widths[0] = wid;
-
                 for (int i = start + 1; i < end; i++)
                     widths[i - start] = 0;
             }
@@ -194,19 +218,42 @@
         return end - start;
     }
 
-    private static float foreach(Canvas canvas,
+    /**
+     * Renders and/or measures a directional run of text on a single line.
+     * Unlike {@link #drawUniformRun}, this can render runs that cross style
+     * boundaries.  Returns the signed advance width, if requested.
+     *
+     * <p>The x position is the leading edge of the text. In a right-to-left
+     * paragraph, this will be to the right of the text to be drawn. Paint
+     * should not have an Align value other than LEFT or positioning will get
+     * confused.
+     *
+     * <p>This optimizes for unstyled text and so workPaint might not be
+     * modified by this call.
+     *
+     * <p>The returned advance width will be < 0 if the paragraph
+     * direction is right-to-left.
+     */
+    private static float drawDirectionalRun(Canvas canvas,
                                  CharSequence text, int start, int end,
-                                 int dir, boolean reverse,
+                                 int dir, boolean runIsRtl,
                                  float x, int top, int y, int bottom,
                                  Paint.FontMetricsInt fmi,
                                  TextPaint paint,
                                  TextPaint workPaint,
                                  boolean needWidth) {
-        if (! (text instanceof Spanned)) {
+
+        // XXX: It looks like all calls to this API match dir and runIsRtl, so
+        // having both parameters is redundant and confusing.
+
+        // fast path for unstyled text
+        if (!(text instanceof Spanned)) {
             float ret = 0;
 
-            if (reverse) {
+            if (runIsRtl) {
                 CharSequence tmp = TextUtils.getReverse(text, start, end);
+                // XXX: this assumes getReverse doesn't tweak the length of
+                // the text
                 int tmpend = end - start;
 
                 if (canvas != null || needWidth)
@@ -227,15 +274,14 @@
                 paint.getFontMetricsInt(fmi);
             }
 
-            return ret * dir;   //Layout.DIR_RIGHT_TO_LEFT == -1
+            return ret * dir;   // Layout.DIR_RIGHT_TO_LEFT == -1
         }
         
         float ox = x;
-        int asc = 0, desc = 0;
-        int ftop = 0, fbot = 0;
+        int minAscent = 0, maxDescent = 0, minTop = 0, maxBottom = 0;
 
         Spanned sp = (Spanned) text;
-        Class division;
+        Class<?> division;
 
         if (canvas == null)
             division = MetricAffectingSpan.class;
@@ -246,20 +292,23 @@
         for (int i = start; i < end; i = next) {
             next = sp.nextSpanTransition(i, end, division);
 
-            x += each(canvas, sp, i, next, dir, reverse,
+            // XXX: if dir and runIsRtl were not the same, this would draw
+            // spans in the wrong order, but no one appears to call it this
+            // way.
+            x += drawUniformRun(canvas, sp, i, next, dir, runIsRtl,
                   x, top, y, bottom, fmi, paint, workPaint,
                   needWidth || next != end);
 
             if (fmi != null) {
-                if (fmi.ascent < asc)
-                    asc = fmi.ascent;
-                if (fmi.descent > desc)
-                    desc = fmi.descent;
+                if (fmi.ascent < minAscent)
+                    minAscent = fmi.ascent;
+                if (fmi.descent > maxDescent)
+                    maxDescent = fmi.descent;
 
-                if (fmi.top < ftop)
-                    ftop = fmi.top;
-                if (fmi.bottom > fbot)
-                    fbot = fmi.bottom;
+                if (fmi.top < minTop)
+                    minTop = fmi.top;
+                if (fmi.bottom > maxBottom)
+                    maxBottom = fmi.bottom;
             }
         }
 
@@ -267,71 +316,78 @@
             if (start == end) {
                 paint.getFontMetricsInt(fmi);
             } else {
-                fmi.ascent = asc;
-                fmi.descent = desc;
-                fmi.top = ftop;
-                fmi.bottom = fbot;
+                fmi.ascent = minAscent;
+                fmi.descent = maxDescent;
+                fmi.top = minTop;
+                fmi.bottom = maxBottom;
             }
         }
 
         return x - ox;
     }
 
-
+    /**
+     * Draws a unidirectional run of text on a single line, and optionally
+     * returns the signed advance.  Unlike drawDirectionalRun, the paragraph
+     * direction and run direction can be different.
+     */
     /* package */ static float drawText(Canvas canvas,
                                        CharSequence text, int start, int end,
-                                       int direction, boolean reverse,
+                                       int dir, boolean runIsRtl,
                                        float x, int top, int y, int bottom,
                                        TextPaint paint,
                                        TextPaint workPaint,
                                        boolean needWidth) {
-        if ((direction == Layout.DIR_RIGHT_TO_LEFT && !reverse) ||
-            (reverse && direction == Layout.DIR_LEFT_TO_RIGHT)) {
-            float ch = foreach(null, text, start, end, Layout.DIR_LEFT_TO_RIGHT,
-                         false, 0, 0, 0, 0, null, paint, workPaint,
-                         true);
+        // XXX this logic is (dir == DIR_LEFT_TO_RIGHT) == runIsRtl
+        if ((dir == Layout.DIR_RIGHT_TO_LEFT && !runIsRtl) ||
+            (runIsRtl && dir == Layout.DIR_LEFT_TO_RIGHT)) {
+            // TODO: this needs the real direction
+            float ch = drawDirectionalRun(null, text, start, end,
+                    Layout.DIR_LEFT_TO_RIGHT, false, 0, 0, 0, 0, null, paint,
+                    workPaint, true);
 
-            ch *= direction;  // DIR_RIGHT_TO_LEFT == -1
-            foreach(canvas, text, start, end, -direction,
-                    reverse, x + ch, top, y, bottom, null, paint,
+            ch *= dir;  // DIR_RIGHT_TO_LEFT == -1
+            drawDirectionalRun(canvas, text, start, end, -dir,
+                    runIsRtl, x + ch, top, y, bottom, null, paint,
                     workPaint, true);
 
             return ch;
         }
 
-        return foreach(canvas, text, start, end, direction, reverse,
+        return drawDirectionalRun(canvas, text, start, end, dir, runIsRtl,
                        x, top, y, bottom, null, paint, workPaint,
                        needWidth);
     }
     
     /**
-     * Draw the specified range of text, specified by start/end, with its origin at (x,y),
-     * in the specified Paint. The origin is interpreted based on the Align setting in the
-     * Paint.
-     *  
-     * This method considers style information in the text
-     * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method
-     * correctly draws the text).
-     * See also
-     * {@link android.graphics.Canvas#drawText(CharSequence, int, int, float, float, Paint)}
-     * and
-     * {@link android.graphics.Canvas#drawRect(float, float, float, float, Paint)}.
+     * Draws a run of text on a single line, with its
+     * origin at (x,y), in the specified Paint. The origin is interpreted based
+     * on the Align setting in the Paint.
+     *
+     * This method considers style information in the text (e.g. even when text
+     * is an instance of {@link android.text.Spanned}, this method correctly
+     * draws the text). See also
+     * {@link android.graphics.Canvas#drawText(CharSequence, int, int, float,
+     * float, Paint)} and
+     * {@link android.graphics.Canvas#drawRect(float, float, float, float,
+     * Paint)}.
      * 
-     * @param canvas The target canvas.
+     * @param canvas The target canvas
      * @param text The text to be drawn
      * @param start The index of the first character in text to draw
      * @param end (end - 1) is the index of the last character in text to draw
      * @param direction The direction of the text. This must be
-     * {@link android.text.Layout#DIR_LEFT_TO_RIGHT} or
-     * {@link android.text.Layout#DIR_RIGHT_TO_LEFT}.
+     *        {@link android.text.Layout#DIR_LEFT_TO_RIGHT} or
+     *        {@link android.text.Layout#DIR_RIGHT_TO_LEFT}.
      * @param x The x-coordinate of origin for where to draw the text
      * @param top The top side of the rectangle to be drawn
      * @param y The y-coordinate of origin for where to draw the text
      * @param bottom The bottom side of the rectangle to be drawn
      * @param paint The main {@link TextPaint} object.
-     * @param workPaint The {@link TextPaint} object used for temporal workspace.
-     * @param needWidth If true, this method returns the width of drawn text.
-     * @return Width of the drawn text if needWidth is true.
+     * @param workPaint The {@link TextPaint} object used for temporal
+     *        workspace.
+     * @param needWidth If true, this method returns the width of drawn text
+     * @return Width of the drawn text if needWidth is true
      */
     public static float drawText(Canvas canvas,
                                  CharSequence text, int start, int end,
@@ -341,34 +397,37 @@
                                  TextPaint workPaint,
                                  boolean needWidth) {
         // For safety.
-        direction = direction >= 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT;
-        /*
-         * Hided "reverse" parameter since it is meaningless for external developers.
-         * Kept workPaint as is so that developers reuse the workspace.
-         */
+        direction = direction >= 0 ? Layout.DIR_LEFT_TO_RIGHT
+                : Layout.DIR_RIGHT_TO_LEFT;
+
+        // Hide runIsRtl parameter since it is meaningless for external
+        // developers.
+        // XXX: the runIsRtl probably ought to be the same as direction, then
+        // this could draw rtl text.
         return drawText(canvas, text, start, end, direction, false,
                         x, top, y, bottom, paint, workPaint, needWidth);
     }
     
     /**
-     * Return the width of the text, considering style information in the text
-     * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method
-     * correctly mesures the width of the text).
+     * Returns the width of a run of left-to-right text on a single line,
+     * considering style information in the text (e.g. even when text is an
+     * instance of {@link android.text.Spanned}, this method correctly measures
+     * the width of the text).
      * 
-     * @param paint The main {@link TextPaint} object.
-     * @param workPaint The {@link TextPaint} object used for temporal workspace.
-     * @param text The text to measure
-     * @param start The index of the first character to start measuring
+     * @param paint the main {@link TextPaint} object; will not be modified
+     * @param workPaint the {@link TextPaint} object available for modification;
+     *        will not necessarily be used
+     * @param text the text to measure
+     * @param start the index of the first character to start measuring
      * @param end 1 beyond the index of the last character to measure
-     * @param fmi FontMetrics information. Can be null
-     * @return The width of the text 
+     * @param fmi FontMetrics information; can be null
+     * @return The width of the text
      */
     public static float measureText(TextPaint paint,
                                     TextPaint workPaint,
                                     CharSequence text, int start, int end,
                                     Paint.FontMetricsInt fmi) {
-        // Keep workPaint as is so that developers reuse the workspace.
-        return foreach(null, text, start, end,
+        return drawDirectionalRun(null, text, start, end,
                        Layout.DIR_LEFT_TO_RIGHT, false,
                        0, 0, 0, 0, fmi, paint, workPaint, true);
     }
diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java
index cb55329..6635ddb8 100644
--- a/core/java/android/text/style/LeadingMarginSpan.java
+++ b/core/java/android/text/style/LeadingMarginSpan.java
@@ -23,10 +23,44 @@
 import android.text.ParcelableSpan;
 import android.text.TextUtils;
 
+/**
+ * A paragraph style affecting the leading margin. There can be multiple leading
+ * margin spans on a single paragraph; they will be rendered in order, each
+ * adding its margin to the ones before it. The leading margin is on the right
+ * for lines in a right-to-left paragraph.
+ */
 public interface LeadingMarginSpan
 extends ParagraphStyle
 {
+    /**
+     * Returns the amount by which to adjust the leading margin. Positive values
+     * move away from the leading edge of the paragraph, negative values move
+     * towards it.
+     * 
+     * @param first true if the request is for the first line of a paragraph,
+     * false for subsequent lines
+     * @return the offset for the margin.
+     */
     public int getLeadingMargin(boolean first);
+
+    /**
+     * Renders the leading margin.  This is called before the margin has been
+     * adjusted by the value returned by {@link getLeadingMargin(boolean)}.
+     * 
+     * @param c the canvas
+     * @param p the paint. The this should be left unchanged on exit.
+     * @param x the current position of the margin
+     * @param dir the base direction of the paragraph; if negative, the margin
+     * is to the right of the text, otherwise it is to the left.
+     * @param top the top of the line
+     * @param baseline the baseline of the line
+     * @param bottom the bottom of the line
+     * @param text the text
+     * @param start the start of the line
+     * @param end the end of the line
+     * @param first true if this is the first line of its paragraph
+     * @param layout the layout containing this line
+     */
     public void drawLeadingMargin(Canvas c, Paint p,
                                   int x, int dir,
                                   int top, int baseline, int bottom,
@@ -38,14 +72,29 @@
         public int getLeadingMarginLineCount();
     };
 
+    /**
+     * The standard implementation of LeadingMarginSpan, which adjusts the
+     * margin but does not do any rendering.
+     */
     public static class Standard implements LeadingMarginSpan, ParcelableSpan {
         private final int mFirst, mRest;
         
+        /**
+         * Constructor taking separate indents for the first and subsequent
+         * lines.
+         * 
+         * @param first the indent for the first line of the paragraph
+         * @param rest the indent for the remaining lines of the paragraph
+         */
         public Standard(int first, int rest) {
             mFirst = first;
             mRest = rest;
         }
 
+        /**
+         * Constructor taking an indent for all lines.
+         * @param every the indent of each line
+         */
         public Standard(int every) {
             this(every, every);
         }
diff --git a/core/java/android/text/style/TabStopSpan.java b/core/java/android/text/style/TabStopSpan.java
index e5b7644..0566428 100644
--- a/core/java/android/text/style/TabStopSpan.java
+++ b/core/java/android/text/style/TabStopSpan.java
@@ -16,14 +16,31 @@
 
 package android.text.style;
 
+/**
+ * Represents a single tab stop on a line.
+ */
 public interface TabStopSpan
 extends ParagraphStyle
 {
+    /**
+     * Returns the offset of the tab stop from the leading margin of the
+     * line.
+     * @return the offset
+     */
     public int getTabStop();
 
+    /**
+     * The default implementation of TabStopSpan.
+     */
     public static class Standard
     implements TabStopSpan
     {
+        /**
+         * Constructor.
+         *
+         * @param where the offset of the tab stop from the leading margin of
+         *        the line
+         */
         public Standard(int where) {
             mTab = where;
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 57fdd8b..e5db120 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1504,6 +1504,31 @@
      * @hide
      */
     private static final int PREPRESSED             = 0x02000000;
+    
+    /**
+     * Always allow a user to overscroll this view, provided it is a
+     * view that can scroll.
+     */
+    private static final int OVERSCROLL_ALWAYS = 0;
+    
+    /**
+     * Allow a user to overscroll this view only if the content is large
+     * enough to meaningfully scroll, provided it is a view that can scroll.
+     */
+    private static final int OVERSCROLL_IF_CONTENT_SCROLLS = 1;
+    
+    /**
+     * Never allow a user to overscroll this view.
+     */
+    private static final int OVERSCROLL_NEVER = 2;
+    
+    /**
+     * Controls the overscroll mode for this view.
+     * See {@link #overscrollBy(int, int, int, int, int, int, int, int)},
+     * {@link #OVERSCROLL_ALWAYS}, {@link #OVERSCROLL_IF_CONTENT_SCROLLS},
+     * and {@link #OVERSCROLL_NEVER}.
+     */
+    private int mOverscrollMode = OVERSCROLL_ALWAYS;
 
     /**
      * The parent this view is attached to.
@@ -2053,6 +2078,9 @@
                         });
                     }
                     break;
+                case R.styleable.View_overscrollMode:
+                    mOverscrollMode = a.getInt(attr, OVERSCROLL_ALWAYS);
+                    break;
             }
         }
 
@@ -8573,43 +8601,59 @@
             int scrollX, int scrollY,
             int scrollRangeX, int scrollRangeY,
             int maxOverscrollX, int maxOverscrollY) {
-        // Scale the scroll amount if we're in the dropoff zone
-        final int dropoffX = maxOverscrollX / 2;
-        final int dropoffLeft = -dropoffX;
-        final int dropoffRight = dropoffX + scrollRangeX;
-        int newScrollX;
-        if ((scrollX < dropoffLeft && deltaX < 0) ||
-                (scrollX > dropoffRight && deltaX > 0)) {
-            newScrollX = scrollX + deltaX / 2;
-        } else {
-            newScrollX = scrollX + deltaX;
-            if (newScrollX > dropoffRight && deltaX > 0) {
-                int extra = newScrollX - dropoffRight;
-                newScrollX = dropoffRight + extra / 2;
-            } else if (newScrollX < dropoffLeft && deltaX < 0) {
-                int extra = newScrollX - dropoffLeft;
-                newScrollX = dropoffLeft + extra / 2;
-            }
-        }
+        final int overscrollMode = mOverscrollMode;
+        final boolean canScrollHorizontal = 
+                computeHorizontalScrollRange() > computeHorizontalScrollExtent();
+        final boolean canScrollVertical = 
+                computeVerticalScrollRange() > computeVerticalScrollExtent();
+        final boolean overscrollHorizontal = overscrollMode == OVERSCROLL_ALWAYS ||
+                (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
+        final boolean overscrollVertical = overscrollMode == OVERSCROLL_ALWAYS ||
+                (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
         
-        final int dropoffY = maxOverscrollY / 2;
-        final int dropoffTop = -dropoffY;
-        final int dropoffBottom = dropoffY + scrollRangeY;
-        int newScrollY;
-        if ((scrollY < dropoffTop && deltaY < 0) ||
-                (scrollY > dropoffBottom && deltaY > 0)) {
-            newScrollY = scrollY + deltaY / 2;
-        } else {
-            newScrollY = scrollY + deltaY;
-            if (newScrollY > dropoffBottom && deltaY > 0) {
-                int extra = newScrollY - dropoffBottom;
-                newScrollY = dropoffBottom + extra / 2;
-            } else if (newScrollY < dropoffTop && deltaY < 0) {
-                int extra = newScrollY - dropoffTop;
-                newScrollY = dropoffTop + extra / 2;
+        int newScrollX = scrollX + deltaX;
+        if (overscrollHorizontal) {
+            // Scale the scroll amount if we're in the dropoff zone
+            final int dropoffX = maxOverscrollX / 2;
+            final int dropoffLeft = -dropoffX;
+            final int dropoffRight = dropoffX + scrollRangeX;
+            if ((scrollX < dropoffLeft && deltaX < 0) ||
+                    (scrollX > dropoffRight && deltaX > 0)) {
+                newScrollX = scrollX + deltaX / 2;
+            } else {
+                if (newScrollX > dropoffRight && deltaX > 0) {
+                    int extra = newScrollX - dropoffRight;
+                    newScrollX = dropoffRight + extra / 2;
+                } else if (newScrollX < dropoffLeft && deltaX < 0) {
+                    int extra = newScrollX - dropoffLeft;
+                    newScrollX = dropoffLeft + extra / 2;
+                }
             }
+        } else {
+            maxOverscrollX = 0;
         }
 
+        int newScrollY = scrollY + deltaY;
+        if (overscrollVertical) {
+            final int dropoffY = maxOverscrollY / 2;
+            final int dropoffTop = -dropoffY;
+            final int dropoffBottom = dropoffY + scrollRangeY;
+            if ((scrollY < dropoffTop && deltaY < 0) ||
+                    (scrollY > dropoffBottom && deltaY > 0)) {
+                newScrollY = scrollY + deltaY / 2;
+            } else {
+                if (newScrollY > dropoffBottom && deltaY > 0) {
+                    int extra = newScrollY - dropoffBottom;
+                    newScrollY = dropoffBottom + extra / 2;
+                } else if (newScrollY < dropoffTop && deltaY < 0) {
+                    int extra = newScrollY - dropoffTop;
+                    newScrollY = dropoffTop + extra / 2;
+                }
+            }
+        } else {
+            maxOverscrollY = 0;
+        }
+        
         // Clamp values if at the limits and record
         final int left = -maxOverscrollX;
         final int right = maxOverscrollX + scrollRangeX;
@@ -8636,8 +8680,8 @@
         
         // Bump the device with some haptic feedback if we're at the edge
         // and didn't start there.
-        if ((clampedX && scrollX != left && scrollX != right) ||
-                (clampedY && scrollY != top && scrollY != bottom)) {
+        if ((overscrollHorizontal && clampedX && scrollX != left && scrollX != right) ||
+                (overscrollVertical && clampedY && scrollY != top && scrollY != bottom)) {
             performHapticFeedback(HapticFeedbackConstants.SCROLL_BARRIER);
         }
 
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 9e9cc7e..d1ad61f 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -116,7 +116,7 @@
      * @param   webView The WebView that created this.
      */
     /* package */ WebTextView(Context context, WebView webView) {
-        super(context);
+        super(context, null, com.android.internal.R.attr.webTextViewStyle);
         mWebView = webView;
         mMaxLength = -1;
     }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ae6c666..9672892 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1102,7 +1102,7 @@
      * methods may be called on a WebView after destroy.
      */
     public void destroy() {
-        clearTextEntry();
+        clearTextEntry(false);
         if (mWebViewCore != null) {
             // Set the handlers to null before destroying WebViewCore so no
             // more messages will be posted.
@@ -1388,7 +1388,7 @@
         arg.mUrl = url;
         arg.mExtraHeaders = extraHeaders;
         mWebViewCore.sendMessage(EventHub.LOAD_URL, arg);
-        clearTextEntry();
+        clearTextEntry(false);
     }
 
     /**
@@ -1417,7 +1417,7 @@
             arg.mUrl = url;
             arg.mPostData = postData;
             mWebViewCore.sendMessage(EventHub.POST_URL, arg);
-            clearTextEntry();
+            clearTextEntry(false);
         } else {
             loadUrl(url);
         }
@@ -1473,7 +1473,7 @@
         arg.mEncoding = encoding;
         arg.mFailUrl = failUrl;
         mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
-        clearTextEntry();
+        clearTextEntry(false);
     }
 
     /**
@@ -1490,7 +1490,7 @@
      * Reload the current url.
      */
     public void reload() {
-        clearTextEntry();
+        clearTextEntry(false);
         switchOutDrawHistory();
         mWebViewCore.sendMessage(EventHub.RELOAD);
     }
@@ -1577,7 +1577,7 @@
         // null, and that will be the case
         mCertificate = null;
         if (steps != 0) {
-            clearTextEntry();
+            clearTextEntry(false);
             mWebViewCore.sendMessage(EventHub.GO_BACK_FORWARD, steps,
                     ignoreSnapshot ? 1 : 0);
         }
@@ -1677,9 +1677,17 @@
                 && mWebTextView.hasFocus();
     }
 
-    private void clearTextEntry() {
+    /**
+     * Remove the WebTextView.
+     * @param disableFocusController If true, send a message to webkit
+     *     disabling the focus controller, so the caret stops blinking.
+     */
+    private void clearTextEntry(boolean disableFocusController) {
         if (inEditingMode()) {
             mWebTextView.remove();
+            if (disableFocusController) {
+                setFocusControllerInactive();
+            }
         }
     }
 
@@ -1713,7 +1721,7 @@
             Log.w(LOGTAG, "This WebView doesn't support zoom.");
             return;
         }
-        clearTextEntry();
+        clearTextEntry(false);
         if (getSettings().getBuiltInZoomControls()) {
             mZoomButtonsController.setVisible(true);
         } else {
@@ -3105,11 +3113,26 @@
         }
     }
 
+    private static class Metrics {
+        int mScrollX;
+        int mScrollY;
+        int mWidth;
+        int mHeight;
+        float mScale;
+    }
+
+    private Metrics getViewMetrics() {
+        Metrics metrics = new Metrics();
+        metrics.mScrollX = mScrollX;
+        metrics.mScrollY = computeVerticalScrollOffset();
+        metrics.mWidth = getWidth();
+        metrics.mHeight = getHeight() - getVisibleTitleHeight();
+        metrics.mScale = mActualScale;
+        return metrics;
+    }
+
     private void drawLayers(Canvas canvas) {
         if (mRootLayer != 0) {
-            int scrollY = computeVerticalScrollOffset();
-            int viewHeight = getHeight() - getVisibleTitleHeight();
-
             // Currently for each draw we compute the animation values;
             // We may in the future decide to do that independently.
             if (nativeEvaluateLayersAnimations(mRootLayer)) {
@@ -3119,9 +3142,7 @@
             }
 
             // We can now draw the layers.
-            nativeDrawLayers(mRootLayer, mScrollX, scrollY,
-                             getWidth(), viewHeight,
-                             mActualScale, canvas);
+            nativeDrawLayers(mRootLayer, canvas);
         }
     }
 
@@ -3209,7 +3230,15 @@
 
         mWebViewCore.drawContentPicture(canvas, color,
                 (animateZoom || mPreviewZoomOnly), animateScroll);
-
+        boolean cursorIsInLayer = nativeCursorIsInLayer();
+        if (drawCursorRing && !cursorIsInLayer) {
+            nativeDrawCursorRing(canvas);
+        }
+        // When the FindDialog is up, only draw the matches if we are not in
+        // the process of scrolling them into view.
+        if (mFindIsUp && !animateScroll) {
+            nativeDrawMatches(canvas);
+        }
         drawLayers(canvas);
 
         if (mNativeClass == 0) return;
@@ -3232,12 +3261,7 @@
                             LONG_PRESS_TIMEOUT);
                 }
             }
-            nativeDrawCursorRing(canvas);
-        }
-        // When the FindDialog is up, only draw the matches if we are not in
-        // the process of scrolling them into view.
-        if (mFindIsUp && !animateScroll) {
-            nativeDrawMatches(canvas);
+            if (cursorIsInLayer) nativeDrawCursorRing(canvas);
         }
         if (mFocusSizeChanged) {
             mFocusSizeChanged = false;
@@ -3743,6 +3767,7 @@
                 }
                 return true;
             }
+            clearTextEntry(true);
             nativeSetFollowedLink(true);
             if (!mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
                 mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
@@ -3823,7 +3848,7 @@
 
     @Override
     protected void onDetachedFromWindow() {
-        clearTextEntry();
+        clearTextEntry(false);
         super.onDetachedFromWindow();
         // Clean up the zoom controller
         mZoomButtonsController.setVisible(false);
@@ -5810,7 +5835,7 @@
                         // is necessary for page loads driven by webkit, and in
                         // particular when the user was on a password field, so
                         // the WebTextView was visible.
-                        clearTextEntry();
+                        clearTextEntry(false);
                         // update the zoom buttons as the scale can be changed
                         if (getSettings().getBuiltInZoomControls()) {
                             updateZoomButtonsEnabled();
@@ -5932,7 +5957,7 @@
                     }
                     break;
                 case CLEAR_TEXT_ENTRY:
-                    clearTextEntry();
+                    clearTextEntry(false);
                     break;
                 case INVAL_RECT_MSG_ID: {
                     Rect r = (Rect)msg.obj;
@@ -5952,6 +5977,7 @@
                 case SET_ROOT_LAYER_MSG_ID: {
                     int oldLayer = mRootLayer;
                     mRootLayer = msg.arg1;
+                    nativeSetRootLayer(mRootLayer);
                     if (oldLayer > 0) {
                         nativeDestroyLayer(oldLayer);
                     }
@@ -6538,8 +6564,7 @@
      */
     private void sendMoveMouseIfLatest(boolean removeFocus) {
         if (removeFocus) {
-            clearTextEntry();
-            setFocusControllerInactive();
+            clearTextEntry(true);
         }
         mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST,
                 cursorData());
@@ -6715,6 +6740,7 @@
     /* package */ native boolean nativeCursorMatchesFocus();
     private native boolean  nativeCursorIntersects(Rect visibleRect);
     private native boolean  nativeCursorIsAnchor();
+    private native boolean  nativeCursorIsInLayer();
     private native boolean  nativeCursorIsTextInput();
     private native Point    nativeCursorPosition();
     private native String   nativeCursorText();
@@ -6728,10 +6754,7 @@
     private native void     nativeDrawCursorRing(Canvas content);
     private native void     nativeDestroyLayer(int layer);
     private native boolean  nativeEvaluateLayersAnimations(int layer);
-    private native void     nativeDrawLayers(int layer,
-                                             int scrollX, int scrollY,
-                                             int width, int height,
-                                             float scale, Canvas canvas);
+    private native void     nativeDrawLayers(int layer, Canvas canvas);
     private native void     nativeDrawMatches(Canvas canvas);
     private native void     nativeDrawSelectionPointer(Canvas content,
             float scale, int x, int y, boolean extendSelection);
@@ -6781,6 +6804,7 @@
     private native void     nativeSetFindIsUp();
     private native void     nativeSetFollowedLink(boolean followed);
     private native void     nativeSetHeightCanMeasure(boolean measure);
+    private native void     nativeSetRootLayer(int layer);
     private native int      nativeTextGeneration();
     // Never call this version except by updateCachedTextfield(String) -
     // we always want to pass in our generation number.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4c77bdc..254efe7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2589,7 +2589,8 @@
                 if (trackMotionScroll(delta, delta)) {
                     if (motionView != null) {
                         // Tweak the scroll for how far we overshot
-                        mScrollY -= delta - (motionView.getTop() - oldTop);
+                        int overshoot = -(delta - (motionView.getTop() - oldTop));
+                        overscrollBy(0, overshoot, 0, mScrollY, 0, 0, 0, getOverscrollMax());
                     }
                     float vel = scroller.getCurrVelocity();
                     if (delta > 0) {
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 4eab4b3..cf53a06 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -200,6 +200,38 @@
     return JNI_FALSE;
 }
 
+static jboolean avrcpVolumeUpNative(JNIEnv *env, jobject object,
+                                     jstring path) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+                           c_path, "org.bluez.Control", "VolumeUp",
+                           DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(path, c_path);
+        return ret ? JNI_TRUE : JNI_FALSE;
+    }
+#endif
+    return JNI_FALSE;
+}
+
+static jboolean avrcpVolumeDownNative(JNIEnv *env, jobject object,
+                                     jstring path) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+                           c_path, "org.bluez.Control", "VolumeDown",
+                           DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(path, c_path);
+        return ret ? JNI_TRUE : JNI_FALSE;
+    }
+#endif
+    return JNI_FALSE;
+}
+
 #ifdef HAVE_BLUETOOTH
 DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
     DBusError err;
@@ -267,6 +299,7 @@
     free(user);
 }
 
+
 #endif
 
 
@@ -281,6 +314,8 @@
     {"resumeSinkNative", "(Ljava/lang/String;)Z", (void*)resumeSinkNative},
     {"getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
                                     (void *)getSinkPropertiesNative},
+    {"avrcpVolumeUpNative", "(Ljava/lang/String;)Z", (void*)avrcpVolumeUpNative},
+    {"avrcpVolumeDownNative", "(Ljava/lang/String;)Z", (void*)avrcpVolumeDownNative},
 };
 
 int register_android_server_BluetoothA2dpService(JNIEnv *env) {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ff8cdc9..ff93984 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -396,6 +396,8 @@
         <attr name="tabWidgetStyle" format="reference" />
         <!-- Default TextView style. -->
         <attr name="textViewStyle" format="reference" />
+        <!-- Default WebTextView style. -->
+        <attr name="webTextViewStyle" format="reference" />
         <!-- Default WebView style. -->
         <attr name="webViewStyle" format="reference" />
         <!-- Default style for drop down items. -->
@@ -1305,6 +1307,19 @@
              <code>public void sayHello(View v)</code> method of your context
              (typically, your Activity). -->
         <attr name="onClick" format="string" />
+
+        <!-- Defines overscrolling behavior. This property is used only if the
+             View is scrollable. Overscrolling is the ability for the user to
+             scroll a View beyond its content boundaries into empty space. -->
+        <attr name="overscrollMode">
+            <!-- Always allow the user to overscroll the content. -->
+            <enum name="always" value="0" />
+            <!-- Only allow the user to overscroll content if the content is large
+                 enough to meaningfully scroll. -->
+            <enum name="ifContentScrolls" value="1" />
+            <!-- Never overscroll. -->
+            <enum name="never" value="2" />
+        </attr>
     </declare-styleable>
 
     <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 70bc000..33b509b 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -83,7 +83,7 @@
          never be encrypted if an Encrypted File System solution
          is enabled. Specifically, this is an "opt-out" feature, meaning
          that, by default, user data will be encrypted if the EFS feature
-         is enabled.-->
+         is enabled. -->
     <attr name="neverEncrypt" format="boolean" />
 
     <!-- Option to indicate this application is only for testing purposes.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3c6338e..b334337 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1227,9 +1227,10 @@
      Resources proposed for Froyo.
      =============================================================== -->
   <eat-comment />
-  <public type="attr" name="neverEncrypt" id="0x010102b7" />
-  <public type="attr" name="installLocation" id="0x010102b8" />
-  <public type="attr" name="safeMode" id="0x010102b9" />
+  <public type="attr" name="installLocation" id="0x010102b7" />
+  <public type="attr" name="safeMode" id="0x010102b8" />
+  <public type="attr" name="webTextViewStyle" id="0x010102b9" />
+  <public type="attr" name="overscrollMode" id="0x010102ba" />
 
   <public type="anim" name="cycle_interpolator" id="0x010a000c" />
     
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 58e9f45..1287669 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -503,6 +503,17 @@
         <item name="android:scrollbars">horizontal|vertical</item>
     </style>
 
+    <style name="Widget.WebTextView">
+        <item name="android:focusable">true</item>
+        <item name="android:focusableInTouchMode">true</item>
+        <item name="android:clickable">true</item>
+        <item name="android:completionHintView">@android:layout/simple_dropdown_item_1line</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceLargeInverse</item>
+        <item name="android:completionThreshold">2</item>
+        <item name="android:dropDownSelector">@android:drawable/list_selector_background</item>
+        <item name="android:popupBackground">@android:drawable/spinner_dropdown_background</item>
+    </style>
+
     <style name="Widget.TabWidget">
         <item name="android:textAppearance">@style/TextAppearance.Widget.TabWidget</item>
         <item name="ellipsize">marquee</item>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index d7a3be3..9e19c57 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -170,6 +170,7 @@
         <item name="starStyle">@android:style/Widget.CompoundButton.Star</item>
         <item name="tabWidgetStyle">@android:style/Widget.TabWidget</item>
         <item name="textViewStyle">@android:style/Widget.TextView</item>
+        <item name="webTextViewStyle">@android:style/Widget.WebTextView</item>
         <item name="webViewStyle">@android:style/Widget.WebView</item>
         <item name="dropDownItemStyle">@android:style/Widget.DropDownItem</item>
         <item name="spinnerDropDownItemStyle">@android:style/Widget.DropDownItem.Spinner</item>
diff --git a/core/tests/coretests/src/android/app/SearchManagerTest.java b/core/tests/coretests/src/android/app/SearchManagerTest.java
index fc7e787..08b7f60 100644
--- a/core/tests/coretests/src/android/app/SearchManagerTest.java
+++ b/core/tests/coretests/src/android/app/SearchManagerTest.java
@@ -120,23 +120,6 @@
         assertSame(searchManager1, searchManager2 );
     }
 
-    @MediumTest
-    public void testSearchables() {
-        SearchManager searchManager = (SearchManager)
-                mContext.getSystemService(Context.SEARCH_SERVICE);
-        SearchableInfo si;
-
-        si = searchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, false);
-        assertNotNull(si);
-        assertFalse(searchManager.isDefaultSearchable(si));
-        si = searchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, true);
-        assertNotNull(si);
-        assertTrue(searchManager.isDefaultSearchable(si));
-        si = searchManager.getSearchableInfo(null, true);
-        assertNotNull(si);
-        assertTrue(searchManager.isDefaultSearchable(si));
-    }
-
     /**
      * Tests that startSearch() can be called multiple times without stopSearch()
      * in between.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 70c27c2..32c5c23 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -87,10 +87,11 @@
 
     /**
      * @hide Broadcast intent when the volume for a particular stream type changes.
-     * Includes the stream and the new volume
+     * Includes the stream, the new volume and previous volumes
      *
      * @see #EXTRA_VOLUME_STREAM_TYPE
      * @see #EXTRA_VOLUME_STREAM_VALUE
+     * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
@@ -126,6 +127,12 @@
     public static final String EXTRA_VOLUME_STREAM_VALUE =
         "android.media.EXTRA_VOLUME_STREAM_VALUE";
 
+    /**
+     * @hide The previous volume associated with the stream for the volume changed intent.
+     */
+    public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
+        "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
+
     /** The audio stream for phone calls */
     public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
     /** The audio stream for system sounds */
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index bde8a47..668917e 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -403,30 +403,34 @@
         // UI
         mVolumePanel.postVolumeChanged(streamType, flags);
         // Broadcast Intent
-        sendVolumeUpdate(streamType);
+        sendVolumeUpdate(streamType, oldIndex, streamState.mIndex);
     }
 
     /** @see AudioManager#setStreamVolume(int, int, int) */
     public void setStreamVolume(int streamType, int index, int flags) {
         ensureValidStreamType(streamType);
+
+        final int oldIndex = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
+
         index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]);
         setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true);
 
         // UI, etc.
         mVolumePanel.postVolumeChanged(streamType, flags);
         // Broadcast Intent
-        sendVolumeUpdate(streamType);
+        sendVolumeUpdate(streamType, oldIndex, index);
     }
 
-    private void sendVolumeUpdate(int streamType) {
+    private void sendVolumeUpdate(int streamType, int oldIndex, int index) {
+        oldIndex = (oldIndex + 5) / 10;
+        index = (index + 5) / 10;
+
         Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
         intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
-        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType));
+        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
+        intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
 
-        // Currently, sending the intent only when the stream is BLUETOOTH_SCO
-        if (streamType == AudioSystem.STREAM_BLUETOOTH_SCO) {
-            mContext.sendBroadcast(intent);
-        }
+        mContext.sendBroadcast(intent);
     }
 
     /**
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 2a65b0d..2012b3d 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -296,7 +296,7 @@
 
 void SoundPool::autoPause()
 {
-    LOGV("pauseAll()");
+    LOGV("autoPause()");
     Mutex::Autolock lock(&mLock);
     for (int i = 0; i < mMaxChannels; ++i) {
         SoundChannel* channel = &mChannelPool[i];
@@ -316,7 +316,7 @@
 
 void SoundPool::autoResume()
 {
-    LOGV("pauseAll()");
+    LOGV("autoResume()");
     Mutex::Autolock lock(&mLock);
     for (int i = 0; i < mMaxChannels; ++i) {
         SoundChannel* channel = &mChannelPool[i];
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index c92b9d7..dd0d064 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -7,8 +7,9 @@
                  android:process="system"
                  android:backupAgent="SettingsBackupAgent"
                  android:killAfterRestore="false"
-                 android:icon="@drawable/ic_launcher_settings"
-                 android:neverEncrypt="true">
+                 android:icon="@drawable/ic_launcher_settings">
+                 
+    <!-- todo add: android:neverEncrypt="true" -->
 
         <provider android:name="SettingsProvider" android:authorities="settings"
                   android:multiprocess="false"
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 0a6c72e..a267e0f 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -24,7 +24,7 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import android.app.Activity;
-import android.app.DeviceAdmin;
+import android.app.DeviceAdminReceiver;
 import android.app.DeviceAdminInfo;
 import android.app.DevicePolicyManager;
 import android.app.IDevicePolicyManager;
@@ -216,7 +216,7 @@
         ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
         if (admin != null) {
             sendAdminCommandLocked(admin,
-                    DeviceAdmin.ACTION_DEVICE_ADMIN_DISABLED);
+                    DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
             // XXX need to wait for it to complete.
             mAdminList.remove(admin);
             mAdminMap.remove(adminReceiver);
@@ -393,7 +393,7 @@
                 mAdminList.add(admin);
                 saveSettingsLocked();
                 sendAdminCommandLocked(admin,
-                        DeviceAdmin.ACTION_DEVICE_ADMIN_ENABLED);
+                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -709,7 +709,7 @@
                 }
                 return;
             }
-            Intent intent = new Intent(DeviceAdmin.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
+            Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
             intent.setComponent(admin.info.getComponent());
             mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
                 @Override
@@ -738,7 +738,7 @@
                         mFailedPasswordAttempts = 0;
                         saveSettingsLocked();
                     }
-                    sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_CHANGED,
+                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
                             DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -760,7 +760,7 @@
                 if (max > 0 && mFailedPasswordAttempts >= max) {
                     wipeDataLocked(0);
                 }
-                sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_FAILED,
+                sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
                         DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -778,7 +778,7 @@
                 try {
                     mFailedPasswordAttempts = 0;
                     saveSettingsLocked();
-                    sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_SUCCEEDED,
+                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
                             DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index d28047500..b566fb7e 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -18,10 +18,12 @@
 
 import android.app.Activity;
 import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
 import android.app.IActivityManager;
 import android.app.IUiModeManager;
 import android.app.KeyguardManager;
 import android.app.StatusBarManager;
+import android.app.PendingIntent;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.content.ActivityNotFoundException;
@@ -29,11 +31,18 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.Configuration;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
 import android.os.Binder;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
@@ -42,6 +51,8 @@
 import android.os.UEventObserver;
 import android.provider.Settings;
 import android.server.BluetoothService;
+import android.text.format.DateUtils;
+import android.text.format.Time;
 import android.util.Log;
 
 import com.android.internal.widget.LockPatternUtils;
@@ -59,10 +70,26 @@
     private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
     private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
 
+    private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL";
+
+    private static final int MSG_DOCK_STATE = 0;
+    private static final int MSG_UPDATE_TWILIGHT = 1;
+    private static final int MSG_ENABLE_LOCATION_UPDATES = 2;
+
     public static final int MODE_NIGHT_AUTO = Configuration.UI_MODE_NIGHT_MASK >> 4;
     public static final int MODE_NIGHT_NO = Configuration.UI_MODE_NIGHT_NO >> 4;
     public static final int MODE_NIGHT_YES = Configuration.UI_MODE_NIGHT_YES >> 4;
 
+    private static final long LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
+    private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20;
+    private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000;
+    private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 5 * DateUtils.MINUTE_IN_MILLIS;
+    // velocity for estimating a potential movement: 150km/h
+    private static final float MAX_VELOCITY_M_MS = 150 / 3600;
+    private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS;
+
+    private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE";
+
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
     private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
@@ -79,7 +106,11 @@
     private boolean mKeyguardDisabled;
     private LockPatternUtils mLockPatternUtils;
 
-    private StatusBarManager mStatusBarManager;    
+    private AlarmManager mAlarmManager;
+
+    private LocationManager mLocationManager;
+    private Location mLocation;
+    private StatusBarManager mStatusBarManager;
 
     // The broadcast receiver which receives the result of the ordered broadcast sent when
     // the dock state changes. The original ordered broadcast is sent with an initial result
@@ -115,6 +146,81 @@
         }
     };
 
+    private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) {
+                mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
+            }
+        }
+    };
+
+    private final LocationListener mLocationListener = new LocationListener() {
+
+        public void onLocationChanged(Location location) {
+            updateLocation(location);
+        }
+
+        public void onProviderDisabled(String provider) {
+        }
+
+        public void onProviderEnabled(String provider) {
+        }
+
+        public void onStatusChanged(String provider, int status, Bundle extras) {
+            // If the network location is no longer available check for a GPS fix
+            // and try to update the location.
+            if (provider == LocationManager.NETWORK_PROVIDER &&
+                    status != LocationProvider.AVAILABLE) {
+                updateLocation(mLocation);
+            }
+        }
+
+        private void updateLocation(Location location) {
+            location = DockObserver.chooseBestLocation(location,
+                    mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER));
+            if (hasMoved(location)) {
+                synchronized (this) {
+                    mLocation = location;
+                }
+                if (mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) {
+                    mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
+                }
+            }
+        }
+
+        /*
+         * The user has moved if the accuracy circles of the two locations
+         * don't overlap.
+         */
+        private boolean hasMoved(Location location) {
+            if (location == null) {
+                return false;
+            }
+            if (mLocation == null) {
+                return true;
+            }
+
+            /* if new location is older than the current one, the devices hasn't
+             * moved.
+             */
+            if (location.getTime() < mLocation.getTime()) {
+                return false;
+            }
+
+            /* Get the distance between the two points */
+            float distance = mLocation.distanceTo(location);
+
+            /* Get the total accuracy radius for both locations */
+            float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy();
+
+            /* If the distance is greater than the combined accuracy of the two
+             * points then they can't overlap and hence the user has moved.
+             */
+            return distance > totalAccuracy;
+        }
+    };
+
     public DockObserver(Context context, PowerManagerService pm) {
         mContext = context;
         mPowerManager = pm;
@@ -123,6 +229,13 @@
 
         ServiceManager.addService("uimode", mBinder);
 
+        mAlarmManager =
+            (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        mLocationManager =
+            (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
+        mContext.registerReceiver(mTwilightUpdateReceiver,
+                new IntentFilter(ACTION_UPDATE_NIGHT_MODE));
+
         startObserving(DOCK_UEVENT_MATCH);
     }
 
@@ -190,83 +303,161 @@
                 update();
             }
             mSystemReady = true;
+            mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
         }
     }
 
     private final void update() {
-        mHandler.sendEmptyMessage(0);
+        mHandler.sendEmptyMessage(MSG_DOCK_STATE);
     }
 
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            synchronized (this) {
-                Log.i(TAG, "Dock state changed: " + mDockState);
+            switch (msg.what) {
+                case MSG_DOCK_STATE:
+                    synchronized (this) {
+                        Log.i(TAG, "Dock state changed: " + mDockState);
 
-                final ContentResolver cr = mContext.getContentResolver();
+                        final ContentResolver cr = mContext.getContentResolver();
 
-                if (Settings.Secure.getInt(cr,
-                        Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
-                    Log.i(TAG, "Device not provisioned, skipping dock broadcast");
-                    return;
-                }
-                // Pack up the values and broadcast them to everyone
-                Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
-                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-                if (mCarModeEnabled && mDockState != Intent.EXTRA_DOCK_STATE_CAR) {
-                    // Pretend to be in DOCK_STATE_CAR.
-                    intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_CAR);
-                } else {
-                    intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
-                }
-                intent.putExtra(Intent.EXTRA_CAR_MODE_ENABLED, mCarModeEnabled);
-
-                // Check if this is Bluetooth Dock
-                String address = BluetoothService.readDockBluetoothAddress();
-                if (address != null)
-                    intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
-                            BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
-
-                // User feedback to confirm dock connection. Particularly
-                // useful for flaky contact pins...
-                if (Settings.System.getInt(cr,
-                        Settings.System.DOCK_SOUNDS_ENABLED, 1) == 1)
-                {
-                    String whichSound = null;
-                    if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
-                        if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) {
-                            whichSound = Settings.System.DESK_UNDOCK_SOUND;
-                        } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
-                            whichSound = Settings.System.CAR_UNDOCK_SOUND;
+                        if (Settings.Secure.getInt(cr,
+                                Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
+                            Log.i(TAG, "Device not provisioned, skipping dock broadcast");
+                            return;
                         }
-                    } else {
-                        if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
-                            whichSound = Settings.System.DESK_DOCK_SOUND;
-                        } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
-                            whichSound = Settings.System.CAR_DOCK_SOUND;
+                        // Pack up the values and broadcast them to everyone
+                        Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
+                        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+                        if (mCarModeEnabled && mDockState != Intent.EXTRA_DOCK_STATE_CAR) {
+                            // Pretend to be in DOCK_STATE_CAR.
+                            intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_CAR);
+                        } else {
+                            intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
                         }
+                        intent.putExtra(Intent.EXTRA_CAR_MODE_ENABLED, mCarModeEnabled);
+
+                        // Check if this is Bluetooth Dock
+                        String address = BluetoothService.readDockBluetoothAddress();
+                        if (address != null)
+                            intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
+                                    BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
+
+                        // User feedback to confirm dock connection. Particularly
+                        // useful for flaky contact pins...
+                        if (Settings.System.getInt(cr,
+                                Settings.System.DOCK_SOUNDS_ENABLED, 1) == 1)
+                        {
+                            String whichSound = null;
+                            if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                                if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+                                    whichSound = Settings.System.DESK_UNDOCK_SOUND;
+                                } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+                                    whichSound = Settings.System.CAR_UNDOCK_SOUND;
+                                }
+                            } else {
+                                if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+                                    whichSound = Settings.System.DESK_DOCK_SOUND;
+                                } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+                                    whichSound = Settings.System.CAR_DOCK_SOUND;
+                                }
+                            }
+
+                            if (whichSound != null) {
+                                final String soundPath = Settings.System.getString(cr, whichSound);
+                                if (soundPath != null) {
+                                    final Uri soundUri = Uri.parse("file://" + soundPath);
+                                    if (soundUri != null) {
+                                        final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+                                        if (sfx != null) sfx.play();
+                                    }
+                                }
+                            }
+                        }
+
+                        // Send the ordered broadcast; the result receiver will receive after all
+                        // broadcasts have been sent. If any broadcast receiver changes the result
+                        // code from the initial value of RESULT_OK, then the result receiver will
+                        // not launch the corresponding dock application. This gives apps a chance
+                        // to override the behavior and stay in their app even when the device is
+                        // placed into a dock.
+                        mContext.sendStickyOrderedBroadcast(
+                                intent, mResultReceiver, null, Activity.RESULT_OK, null, null);
+
                     }
-
-                    if (whichSound != null) {
-                        final String soundPath = Settings.System.getString(cr, whichSound);
-                        if (soundPath != null) {
-                            final Uri soundUri = Uri.parse("file://" + soundPath);
-                            if (soundUri != null) {
-                                final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
-                                if (sfx != null) sfx.play();
+                    break;
+                case MSG_UPDATE_TWILIGHT:
+                    synchronized (this) {
+                        if (mCarModeEnabled && mLocation != null && mNightMode == MODE_NIGHT_AUTO) {
+                            try {
+                                DockObserver.this.updateTwilight();
+                            } catch (RemoteException e) {
+                                Log.w(TAG, "Unable to change night mode.", e);
                             }
                         }
                     }
-                }
+                    break;
+                case MSG_ENABLE_LOCATION_UPDATES:
+                    if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
+                        mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
+                                LOCATION_UPDATE_MS, LOCATION_UPDATE_DISTANCE_METER, mLocationListener);
+                        retrieveLocation();
+                        if (mLocation != null) {
+                            try {
+                                DockObserver.this.updateTwilight();
+                            } catch (RemoteException e) {
+                                Log.w(TAG, "Unable to change night mode.", e);
+                            }
+                        }
+                    } else {
+                        long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL);
+                        interval *= 1.5;
+                        if (interval == 0) {
+                            interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN;
+                        } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) {
+                            interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX;
+                        }
+                        Bundle bundle = new Bundle();
+                        bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval);
+                        Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES);
+                        newMsg.setData(bundle);
+                        mHandler.sendMessageDelayed(newMsg, interval);
+                    }
+                    break;
+            }
+        }
 
-                // Send the ordered broadcast; the result receiver will receive after all
-                // broadcasts have been sent. If any broadcast receiver changes the result
-                // code from the initial value of RESULT_OK, then the result receiver will
-                // not launch the corresponding dock application. This gives apps a chance
-                // to override the behavior and stay in their app even when the device is
-                // placed into a dock.
-                mContext.sendStickyOrderedBroadcast(
-                        intent, mResultReceiver, null, Activity.RESULT_OK, null, null);
+        private void retrieveLocation() {
+            final Location gpsLocation =
+                mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+            Location location;
+            Criteria criteria = new Criteria();
+            criteria.setSpeedRequired(false);
+            criteria.setAltitudeRequired(false);
+            criteria.setBearingRequired(false);
+            final String bestProvider = mLocationManager.getBestProvider(criteria, true);
+            if (LocationManager.GPS_PROVIDER.equals(bestProvider)) {
+                location = gpsLocation;
+            } else {
+                location = DockObserver.chooseBestLocation(gpsLocation,
+                        mLocationManager.getLastKnownLocation(bestProvider));
+            }
+            // In the case there is no location available (e.g. GPS fix or network location
+            // is not available yet), the longitude of the location is estimated using the timezone,
+            // latitude and accuracy are set to get a good average.
+            if (location == null) {
+                Time currentTime = new Time();
+                currentTime.set(System.currentTimeMillis());
+                double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * currentTime.gmtoff
+                        - (currentTime.isDst > 0 ? 3600 : 0);
+                location = new Location("fake");
+                location.setLongitude(lngOffset);
+                location.setLatitude(59.95);
+                location.setAccuracy(417000.0f);
+                location.setTime(System.currentTimeMillis());
+            }
+            synchronized (this) {
+                mLocation = location;
             }
         }
     };
@@ -274,10 +465,15 @@
     private void setCarMode(boolean enabled) throws RemoteException {
         mCarModeEnabled = enabled;
         if (enabled) {
-            setMode(Configuration.UI_MODE_TYPE_CAR, mNightMode);
+            if (mNightMode == MODE_NIGHT_AUTO) {
+                updateTwilight();
+            } else {
+                setMode(Configuration.UI_MODE_TYPE_CAR, mNightMode << 4);
+            }
         } else {
             // Disabling the car mode clears the night mode.
-            setMode(Configuration.UI_MODE_TYPE_NORMAL, MODE_NIGHT_NO);
+            setMode(Configuration.UI_MODE_TYPE_NORMAL,
+                    Configuration.UI_MODE_NIGHT_UNDEFINED);
         }
 
         if (mStatusBarManager == null) {
@@ -290,38 +486,114 @@
         // the status bar should be totally disabled, the calls below will
         // have no effect until the device is unlocked.
         if (mStatusBarManager != null) {
+            long ident = Binder.clearCallingIdentity();
             mStatusBarManager.disable(enabled 
                 ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
                 : StatusBarManager.DISABLE_NONE);
-        }
-    }
-
-    private void setMode(int modeType, int modeNight) throws RemoteException {
-        final IActivityManager am = ActivityManagerNative.getDefault();
-        Configuration config = am.getConfiguration();
-
-        if (config.uiMode != (modeType | modeNight)) {
-            config.uiMode = modeType | modeNight;
-            long ident = Binder.clearCallingIdentity();
-            am.updateConfiguration(config);
             Binder.restoreCallingIdentity(ident);
         }
     }
 
+    private void setMode(int modeType, int modeNight) throws RemoteException {
+        long ident = Binder.clearCallingIdentity();
+        final IActivityManager am = ActivityManagerNative.getDefault();
+        Configuration config = am.getConfiguration();
+        if (config.uiMode != (modeType | modeNight)) {
+            config.uiMode = modeType | modeNight;
+            am.updateConfiguration(config);
+        }
+        Binder.restoreCallingIdentity(ident);
+    }
+
     private void setNightMode(int mode) throws RemoteException {
-        mNightMode = mode;
-        switch (mode) {
-            case MODE_NIGHT_NO:
-            case MODE_NIGHT_YES:
-                setMode(Configuration.UI_MODE_TYPE_CAR, mode << 4);
-                break;
-            case MODE_NIGHT_AUTO:
-                // FIXME: not yet supported, this functionality will be
-                // added in a separate change.
-                break;
-            default:
-                setMode(Configuration.UI_MODE_TYPE_CAR, MODE_NIGHT_NO << 4);
-                break;
+        if (mNightMode != mode) {
+            mNightMode = mode;
+            switch (mode) {
+                case MODE_NIGHT_NO:
+                case MODE_NIGHT_YES:
+                    setMode(Configuration.UI_MODE_TYPE_CAR, mode << 4);
+                    break;
+                case MODE_NIGHT_AUTO:
+                    long ident = Binder.clearCallingIdentity();
+                    updateTwilight();
+                    Binder.restoreCallingIdentity(ident);
+                    break;
+                default:
+                    setMode(Configuration.UI_MODE_TYPE_CAR, MODE_NIGHT_NO << 4);
+                    break;
+            }
+        }
+    }
+
+    private void updateTwilight() throws RemoteException {
+        synchronized (this) {
+            if (mLocation == null) {
+                return;
+            }
+            final long currentTime = System.currentTimeMillis();
+            int nightMode;
+            // calculate current twilight
+            TwilightCalculator tw = new TwilightCalculator();
+            tw.calculateTwilight(currentTime,
+                    mLocation.getLatitude(), mLocation.getLongitude());
+            if (tw.mState == TwilightCalculator.DAY) {
+                nightMode = MODE_NIGHT_NO;
+            } else {
+                nightMode =  MODE_NIGHT_YES;
+            }
+
+            // schedule next update
+            final int mLastTwilightState = tw.mState;
+            // add some extra time to be on the save side.
+            long nextUpdate = DateUtils.MINUTE_IN_MILLIS;
+            if (currentTime > tw.mSunset) {
+                // next update should be on the following day
+                tw.calculateTwilight(currentTime
+                        + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(),
+                        mLocation.getLongitude());
+            }
+
+            if (mLastTwilightState == TwilightCalculator.NIGHT) {
+                nextUpdate += tw.mSunrise;
+            } else {
+                nextUpdate += tw.mSunset;
+            }
+
+            Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE);
+            PendingIntent pendingIntent =
+                    PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
+            mAlarmManager.cancel(pendingIntent);
+            mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent);
+
+            // set current mode
+            setMode(Configuration.UI_MODE_TYPE_CAR, nightMode << 4);
+        }
+    }
+
+    /**
+     * Check which of two locations is better by comparing the distance a device
+     * could have cover since the last timestamp of the location.
+     *
+     * @param location first location
+     * @param otherLocation second location
+     * @return one of the two locations
+     */
+    protected static Location chooseBestLocation(Location location, Location otherLocation) {
+        if (location == null) {
+            return otherLocation;
+        }
+        if (otherLocation == null) {
+            return location;
+        }
+        final long currentTime = System.currentTimeMillis();
+        float gpsPotentialMove = MAX_VELOCITY_M_MS * (currentTime - location.getTime())
+                + location.getAccuracy();
+        float otherPotentialMove = MAX_VELOCITY_M_MS * (currentTime - otherLocation.getTime())
+                + otherLocation.getAccuracy();
+        if (gpsPotentialMove < otherPotentialMove) {
+            return location;
+        } else {
+            return otherLocation;
         }
     }
 
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index cf083c04..ceae973 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -259,8 +259,12 @@
                     rdata[idx++] = line.substring(tok[0].length() + 1);
                 } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
                     if (LOCAL_LOGD) Log.d(TAG, String.format("List terminated with {%s}", line));
-                    if (i != rsp.size()) {
-                        Log.w(TAG, String.format("Recv'd %d lines after list term", (rsp.size()-i)));
+                    int last = rsp.size() -1;
+                    if (i != last) {
+                        Log.w(TAG, String.format("Recv'd %d lines after end of list {%s}", (last-i), cmd));
+                        for (int j = i; j <= last ; j++) {
+                            Log.w(TAG, String.format("ExtraData <%s>", rsp.get(i)));
+                        }
                     }
                     return rdata;
                 } else {
diff --git a/services/java/com/android/server/TwilightCalculator.java b/services/java/com/android/server/TwilightCalculator.java
new file mode 100644
index 0000000..a8f67d8
--- /dev/null
+++ b/services/java/com/android/server/TwilightCalculator.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010 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.server;
+
+import android.text.format.DateUtils;
+import android.util.FloatMath;
+
+/** @hide */
+public class TwilightCalculator {
+
+    /** Value of {@link #mState} if it is currently day */
+    public static final int DAY = 0;
+
+    /** Value of {@link #mState} if it is currently night */
+    public static final int NIGHT = 1;
+
+    private static final float DEGREES_TO_RADIANS = (float) (Math.PI / 180.0f);
+
+    // element for calculating solar transit.
+    private static final float J0 = 0.0009f;
+
+    // correction for civil twilight
+    private static final float ALTIDUTE_CORRECTION_CIVIL_TWILIGHT = -0.104719755f;
+
+    // coefficients for calculating Equation of Center.
+    private static final float C1 = 0.0334196f;
+    private static final float C2 = 0.000349066f;
+    private static final float C3 = 0.000005236f;
+
+    private static final float OBLIQUITY = 0.40927971f;
+
+    // Java time on Jan 1, 2000 12:00 UTC.
+    private static final long UTC_2000 = 946728000000L;
+
+    /** Time of sunset (civil twilight) in milliseconds. */
+    public long mSunset;
+
+    /** Time of sunrise (civil twilight) in milliseconds. */
+    public long mSunrise;
+
+    /** Current state */
+    public int mState;
+
+    /**
+     * calculates the civil twilight bases on time and geo-coordinates.
+     *
+     * @param time time in milliseconds.
+     * @param latiude latitude in degrees.
+     * @param longitude latitude in degrees.
+     */
+    public void calculateTwilight(long time, double latiude, double longitude) {
+        final float daysSince2000 = (float) (time - UTC_2000) / DateUtils.DAY_IN_MILLIS;
+
+        // mean anomaly
+        final float meanAnomaly = 6.240059968f + daysSince2000 * 0.01720197f;
+
+        // true anomaly
+        final float trueAnomaly = meanAnomaly + C1 * FloatMath.sin(meanAnomaly) + C2
+                * FloatMath.sin(2 * meanAnomaly) + C3 * FloatMath.sin(3 * meanAnomaly);
+
+        // ecliptic longitude
+        final float solarLng = trueAnomaly + 1.796593063f + (float) Math.PI;
+
+        // solar transit in days since 2000
+        final double arcLongitude = -longitude / 360;
+        float n = Math.round(daysSince2000 - J0 - arcLongitude);
+        double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053f * FloatMath.sin(meanAnomaly)
+                + -0.0069f * FloatMath.sin(2 * solarLng);
+
+        // declination of sun
+        double solarDec = Math.asin(FloatMath.sin(solarLng) * FloatMath.sin(OBLIQUITY));
+
+        final double latRad = latiude * DEGREES_TO_RADIANS;
+        float hourAngle = (float) (Math
+                .acos((FloatMath.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
+                        * Math.sin(solarDec))
+                        / (Math.cos(latRad) * Math.cos(solarDec))) / (2 * Math.PI));
+
+        mSunset = Math.round((solarTransitJ2000 + hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
+        mSunrise = Math.round((solarTransitJ2000 - hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
+
+        if (mSunrise < time && mSunset > time) {
+            mState = DAY;
+        } else {
+            mState = NIGHT;
+        }
+    }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java
index 3e7094e..71936f1 100644
--- a/telephony/java/com/android/internal/telephony/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/IccUtils.java
@@ -397,7 +397,7 @@
         int bits = data[valueIndex++] & 0xFF;
         int colorNumber = data[valueIndex++] & 0xFF;
         int clutOffset = ((data[valueIndex++] & 0xFF) << 8)
-                | data[valueIndex++];
+                | (data[valueIndex++] & 0xFF);
         length = length - 6;
 
         int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber);
diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
index 9caae3d..41e527c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
@@ -409,7 +409,7 @@
                     case USIM_EFIAP_TAG:
                     case USIM_EFSNE_TAG:
                         data = tlv.getData();
-                        int efid = data[0] << 8 | data[1];
+                        int efid = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
                         val.put(tag, efid);
                         break;
                 }
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index 2b6b81e..28f1e73 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -29,6 +29,11 @@
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
     <uses-permission android:name="android.permission.DELETE_PACKAGES" />
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
+    <uses-permission android:name="android.permission.ASEC_ACCESS" />
+    <uses-permission android:name="android.permission.ASEC_CREATE" />
+    <uses-permission android:name="android.permission.ASEC_DESTROY" />
+    <uses-permission android:name="android.permission.ASEC_MOUNT_UNMOUNT" />
+    <uses-permission android:name="android.permission.ASEC_RENAME" />
     <uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" />
     <uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
     <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
new file mode 100755
index 0000000..7569d7a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2006 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.unit_tests;
+
+import android.os.storage.IMountService.Stub;
+
+import android.net.Uri;
+import android.os.FileUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.storage.IMountService;
+import android.os.storage.StorageResultCode;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.StatFs;
+import android.provider.Settings;
+import junit.framework.Assert;
+
+public class AsecTests extends AndroidTestCase {
+    private static final boolean localLOGV = true;
+    public static final String TAG="AsecTests";
+
+    void failStr(String errMsg) {
+        Log.w(TAG, "errMsg="+errMsg);
+    }
+    void failStr(Exception e) {
+        Log.w(TAG, "e.getMessage="+e.getMessage());
+        Log.w(TAG, "e="+e);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
+        cleanupContainers();
+    }
+
+    private void cleanupContainers() throws RemoteException {
+        IMountService ms = getMs();
+        String[] containers = ms.getSecureContainerList();
+
+        for (int i = 0; i < containers.length; i++) {
+            if (containers[i].startsWith("com.android.unittests.AsecTests.")) {
+                ms.destroySecureContainer(containers[i]);
+            }
+        }
+    }
+
+    private IMountService getMs() {
+        IBinder service = ServiceManager.getService("mount");
+        if (service != null) {
+            return IMountService.Stub.asInterface(service);
+        } else {
+            Log.e(TAG, "Can't get mount service");
+        }
+        return null;
+    }
+
+    private boolean isMediaMounted() {
+        try {
+        String mPath = Environment.getExternalStorageDirectory().toString();
+        String state = getMs().getVolumeState(mPath);
+        return Environment.MEDIA_MOUNTED.equals(state);
+        } catch (RemoteException e) {
+            failStr(e);
+            return false;
+        }
+    }
+
+    public void testCreateContainer() {
+        Assert.assertTrue(isMediaMounted());
+        IMountService ms = getMs();
+        try {
+            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testCreateContainer", 4, "fat", "none", 1000);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testDestroyContainer() {
+        Assert.assertTrue(isMediaMounted());
+        IMountService ms = getMs();
+        try {
+            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testDestroyContainer", 4, "fat", "none", 1000);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+            rc = ms.destroySecureContainer("com.android.unittests.AsecTests.testDestroyContainer");
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testMountContainer() {
+        Assert.assertTrue(isMediaMounted());
+        IMountService ms = getMs();
+        try {
+            int rc = ms.createSecureContainer(
+                    "com.android.unittests.AsecTests.testMountContainer", 4, "fat", "none", 1000);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+
+            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountContainer");
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+
+            rc = ms.mountSecureContainer("com.android.unittests.AsecTests.testMountContainer", "none", 1000);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testMountBadKey() {
+        Assert.assertTrue(isMediaMounted());
+        IMountService ms = getMs();
+        try {
+            int rc = ms.createSecureContainer(
+                    "com.android.unittests.AsecTests.testMountBadKey", 4, "fat",
+                            "00000000000000000000000000000000", 1000);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+
+            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountBadKey");
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+
+            rc = ms.mountSecureContainer(
+                    "com.android.unittests.AsecTests.testMountBadKey",
+                            "00000000000000000000000000000001", 1001);
+            Assert.assertEquals(StorageResultCode.OperationFailedInternalError, rc);
+
+            rc = ms.mountSecureContainer(
+                    "com.android.unittests.AsecTests.testMountBadKey", "none", 1001);
+            Assert.assertEquals(StorageResultCode.OperationFailedInternalError, rc);
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 452368e..4d51356 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -81,172 +81,112 @@
         "platform",  // platform specific
         "http/wml",
     };
-        
+
     static final String [] ignoreTestList = {
-        // RegExp is exponatal
-        "fast/regex/test1.html",
-        "fast/regex/slow.html",
-        // RegExp is too large, causing OOM
-        "fast/js/regexp-charclass-crash.html",
-        // The Android browser has no notion of private browsing.
-        "storage/private-browsing-readonly.html",
-        "storage/domstorage/localstorage/private-browsing-affects-storage.html",
-        "storage/domstorage/sessionstorage/private-browsing-affects-storage.html",
-        // Android layout tests are stored in "layout_tests". The following two
-        // tests expect "LayoutTests" in their output.
-        "storage/domstorage/localstorage/iframe-events.html",
-        "storage/domstorage/sessionstorage/iframe-events.html",
-        // We do not support multi touch events.
-        "fast/events/touch/basic-multi-touch-events.html",
-        // below tests (failed or crashes) are filtered out temporarily due to prioritizing
         "editing/selection/move-left-right.html",
+        "fast/events/touch/basic-multi-touch-events.html", // We do not support multi touch events.
+        "fast/js/regexp-charclass-crash.html", // RegExp is too large, causing OOM
+        "fast/regex/test1.html", // RegExp is exponential
+        "fast/regex/slow.html", // RegExp is exponential
+        "storage/domstorage/localstorage/iframe-events.html", // Expects test to be in LayoutTests
+        "storage/domstorage/localstorage/private-browsing-affects-storage.html", // No notion of private browsing.
+        "storage/domstorage/sessionstorage/iframe-events.html", // Expects test to be in LayoutTests
+        "storage/domstorage/sessionstorage/private-browsing-affects-storage.html", // No notion of private browsing.
+        "storage/private-browsing-readonly.html", // No notion of private browsing.
     };
-    
+
     static void fillIgnoreResultSet() {
-        // need test plugin
-        ignoreResultList.add("fast/dom/Window/Plug-ins.html");
-        // pixel depth
-        ignoreResultList.add("fast/dom/Window/window-screen-properties.html");
-        // missing space in textrun, ok as text is wrapped. ignore. #714933
-        ignoreResultList.add("fast/events/onload-webkit-before-webcore.html");
-        // missing support for textInputController.makeAttributedString()
-        ignoreResultList.add("fast/forms/attributed-strings.html");
-        // charset convert. #516936 ignore, won't fix
-        ignoreResultList.add("fast/forms/form-data-encoding-2.html");
-        // charset convert. #516936 ignore, won't fix
-        ignoreResultList.add("fast/forms/form-data-encoding.html");
-        // execCommand "insertText" not supported
-        ignoreResultList.add("fast/forms/input-appearance-maxlength.html");
-        // Copy&Paste commands not supported
-        ignoreResultList.add("fast/forms/input-truncate-newline.html");
-        ignoreResultList.add("fast/forms/textarea-paste-newline.html");
-        // requires eventSender.mouseMoveTo, mouseDown & mouseUp and 
-        // abs. position of mouse to select a word. ignore, won't fix #716583
-        ignoreResultList.add("fast/forms/onselect-textarea.html");
-        // requires eventSender.mouseMoveTo, mouseDown & mouseUp and 
-        // abs. position of mouse to select a word. ignore, won't fix #716583
-        ignoreResultList.add("fast/forms/onselect-textfield.html");
-        // not implemented queryCommandEnabled:BackColor, Undo & Redo
-        ignoreResultList.add("fast/forms/plaintext-mode-1.html");
-        // Our text areas are a little thinner than Apples. Also RTL test failes
-        ignoreResultList.add("fast/forms/textarea-appearance-wrap.html");
-        // Our text areas are a little thinner than Apples
-        ignoreResultList.add("fast/forms/textarea-hard-linewrap.html");
-        // screen width&height are different
-        ignoreResultList.add("fast/frames/frameElement-widthheight.html");
-        ignoreResultList.add("fast/frames/frame-js-url-clientWidth.html");
-        //  requires JS test API, textInputController
-        ignoreResultList.add("fast/text/attributed-substring-from-range.html"); 
-        ignoreResultList.add("fast/text/attributed-substring-from-range-001.html");
-        // will not fix #619707
-        ignoreResultList.add("fast/css/case-transform.html");
-        // different platform defaults for font and different screen size
-        ignoreResultList.add("fast/css/computed-style.html");
-        // different screen size result in extra spaces in Apple compared to us
-        ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html");
-        // xslt and xpath elements missing from property list
-        ignoreResultList.add("fast/dom/Window/window-properties.html");
-        // requires textInputController.characterIndexForPoint
-        ignoreResultList.add("fast/dom/character-index-for-point.html");
-        // requires xpath support
-        ignoreResultList.add("fast/dom/gc-9.html");
-        // requires xslt and xpath support
-        ignoreResultList.add("fast/dom/global-constructors.html");
-        // dynamic plugins not supported
-        ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html");
-        ignoreResultList.add("fast/js/navigator-mimeTypes-length.html");
-        // there is extra spacing in the file due to multiple input boxes
-        // fitting on one line on Apple, ours are wrapped. Space at line ends
-        // are stripped.
-        ignoreResultList.add("fast/dom/tabindex-clamp.html");
-        
-        // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/dom/Window/window-xy-properties.html");
-        ignoreResultList.add("fast/events/window-events-bubble.html");
-        ignoreResultList.add("fast/events/window-events-bubble2.html");
-        ignoreResultList.add("fast/events/window-events-capture.html");
-        ignoreResultList.add("fast/forms/select-empty-list.html");
-        ignoreResultList.add("fast/replaced/image-map.html");
-        ignoreResultList.add("fast/events/capture-on-target.html");
-        ignoreResultList.add("fast/events/dblclick-addEventListener.html");
-        ignoreResultList.add("fast/events/drag-in-frames.html");
-        ignoreResultList.add("fast/events/drag-outside-window.html");
-        ignoreResultList.add("fast/events/event-sender-mouse-click.html");
-        ignoreResultList.add("fast/events/event-view-toString.html");
-        ignoreResultList.add("fast/events/frame-click-focus.html");
-        ignoreResultList.add("fast/events/input-image-scrolled-x-y.html");
-        ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html");
-        ignoreResultList.add("fast/events/mouseclick-target-and-positioning.html");
-        ignoreResultList.add("fast/events/mouseover-mouseout.html");
-        ignoreResultList.add("fast/events/mouseover-mouseout2.html");
-        ignoreResultList.add("fast/events/mouseup-outside-button.html");
-        ignoreResultList.add("fast/events/mouseup-outside-document.html");
-        ignoreResultList.add("fast/events/onclick-list-marker.html");
-        ignoreResultList.add("fast/events/ondragenter.html");
-        ignoreResultList.add("fast/forms/drag-into-textarea.html");
-        ignoreResultList.add("fast/forms/input-select-on-click.html");
-        ignoreResultList.add("fast/forms/listbox-onchange.html");
-        ignoreResultList.add("fast/forms/search-cancel-button-mouseup.html");
-        ignoreResultList.add("fast/forms/textarea-scrolled-endline-caret.html");
-        
-        // there is extra spacing in the file due to multiple frame boxes
-        // fitting on one line on Apple, ours are wrapped. Space at line ends
-        // are stripped.
-        ignoreResultList.add("fast/events/iframe-object-onload.html");
-        // eventSender.mouseDown(), mouseUp() and objc API missing
-        ignoreResultList.add("fast/events/mouseup-outside-document.html");
-        ignoreResultList.add("fast/events/objc-keyboard-event-creation.html");
-        ignoreResultList.add("fast/events/objc-event-api.html");
-        // not capturing the console messages
-        ignoreResultList.add("fast/forms/selected-index-assert.html");
-        ignoreResultList.add("fast/parser/script-tag-with-trailing-slash.html");
-        // there is extra spacing as the text areas and input boxes fit next
-        // to each other on Apple, but are wrapped on our screen.
-        ignoreResultList.add("fast/forms/selection-functions.html");
-        // Text selection done differently on our platform. When a inputbox
-        // gets focus, the entire block is selected.
-        ignoreResultList.add("fast/forms/textarea-initial-caret-position.html");
-        ignoreResultList.add("fast/forms/textarea-no-scroll-on-blur.html");
-        // Requires LayoutTests to exist at /tmp/LayoutTests
-        ignoreResultList.add("fast/loader/local-JavaScript-from-local.html");
-        ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html");
-        // extra spacing because iFrames rendered next to each other on Apple
-        ignoreResultList.add("fast/loader/opaque-base-url.html");
-        ignoreResultList.add("fast/text/plain-text-line-breaks.html");
+        ignoreResultList.add("fast/css/case-transform.html"); // will not fix #619707
+        ignoreResultList.add("fast/css/computed-style.html"); // different platform defaults for font and different screen size
+        ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); // different screen size result in extra spaces in Apple compared to us
+        ignoreResultList.add("fast/dom/Window/Plug-ins.html"); // need test plugin
+        ignoreResultList.add("fast/dom/Window/window-properties.html"); // xslt and xpath elements missing from property list
+        ignoreResultList.add("fast/dom/Window/window-screen-properties.html"); // pixel depth
+        ignoreResultList.add("fast/dom/Window/window-xy-properties.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/dom/character-index-for-point.html"); // requires textInputController.characterIndexForPoint
+        ignoreResultList.add("fast/dom/gc-9.html"); // requires xpath support
+        ignoreResultList.add("fast/dom/global-constructors.html"); // requires xslt and xpath support
+        ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html"); // dynamic plugins not supported
+        ignoreResultList.add("fast/dom/tabindex-clamp.html"); // there is extra spacing in the file due to multiple input boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped.
+        ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/capture-on-target.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/dblclick-addEventListener.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/drag-in-frames.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/drag-outside-window.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/event-sender-mouse-click.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/event-view-toString.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/frame-click-focus.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/iframe-object-onload.html"); // there is extra spacing in the file due to multiple frame boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped.
+        ignoreResultList.add("fast/events/input-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/mouseclick-target-and-positioning.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/mouseover-mouseout.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/mouseover-mouseout2.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/mouseup-outside-button.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/mouseup-outside-document.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/objc-event-api.html"); // eventSender.mouseDown(), mouseUp() and objc API missing
+        ignoreResultList.add("fast/events/objc-keyboard-event-creation.html"); // eventSender.mouseDown(), mouseUp() and objc API missing
+        ignoreResultList.add("fast/events/onclick-list-marker.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/ondragenter.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/onload-webkit-before-webcore.html"); // missing space in textrun, ok as text is wrapped. ignore. #714933
+        ignoreResultList.add("fast/events/window-events-bubble.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/window-events-bubble2.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/window-events-capture.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/attributed-strings.html"); // missing support for textInputController.makeAttributedString()
+        ignoreResultList.add("fast/forms/drag-into-textarea.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/form-data-encoding-2.html"); // charset convert. #516936 ignore, won't fix
+        ignoreResultList.add("fast/forms/form-data-encoding.html"); // charset convert. #516936 ignore, won't fix
+        ignoreResultList.add("fast/forms/input-appearance-maxlength.html"); // execCommand "insertText" not supported
+        ignoreResultList.add("fast/forms/input-select-on-click.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/input-truncate-newline.html"); // Copy&Paste commands not supported
+        ignoreResultList.add("fast/forms/listbox-onchange.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/onselect-textarea.html"); // requires eventSender.mouseMoveTo, mouseDown & mouseUp and abs. position of mouse to select a word. ignore, won't fix #716583
+        ignoreResultList.add("fast/forms/onselect-textfield.html"); // requires eventSender.mouseMoveTo, mouseDown & mouseUp and abs. position of mouse to select a word. ignore, won't fix #716583
+        ignoreResultList.add("fast/forms/plaintext-mode-1.html"); // not implemented queryCommandEnabled:BackColor, Undo & Redo
+        ignoreResultList.add("fast/forms/search-cancel-button-mouseup.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/select-empty-list.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/selected-index-assert.html"); // not capturing the console messages
+        ignoreResultList.add("fast/forms/selection-functions.html"); // there is extra spacing as the text areas and input boxes fit next to each other on Apple, but are wrapped on our screen.
+        ignoreResultList.add("fast/forms/textarea-appearance-wrap.html"); // Our text areas are a little thinner than Apples. Also RTL test failes
+        ignoreResultList.add("fast/forms/textarea-hard-linewrap.html"); // Our text areas are a little thinner than Apples
+        ignoreResultList.add("fast/forms/textarea-initial-caret-position.html"); // Text selection done differently on our platform. When a inputbox gets focus, the entire block is selected.
+        ignoreResultList.add("fast/forms/textarea-no-scroll-on-blur.html"); // Text selection done differently on our platform. When a inputbox gets focus, the entire block is selected.
+        ignoreResultList.add("fast/forms/textarea-paste-newline.html"); // Copy&Paste commands not supported
+        ignoreResultList.add("fast/forms/textarea-scrolled-endline-caret.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/frames/frameElement-widthheight.html"); // screen width&height are different
+        ignoreResultList.add("fast/frames/frame-js-url-clientWidth.html"); // screen width&height are different
+        ignoreResultList.add("fast/js/navigator-mimeTypes-length.html"); // dynamic plugins not supported
+        ignoreResultList.add("fast/loader/local-JavaScript-from-local.html"); // Requires LayoutTests to exist at /tmp/LayoutTests
+        ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html"); // Requires LayoutTests to exist at /tmp/LayoutTests
+        ignoreResultList.add("fast/loader/opaque-base-url.html"); // extra spacing because iFrames rendered next to each other on Apple
+        ignoreResultList.add("fast/parser/script-tag-with-trailing-slash.html"); // not capturing the console messages
+        ignoreResultList.add("fast/replaced/image-map.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/text/attributed-substring-from-range.html"); //  requires JS test API, textInputController
+        ignoreResultList.add("fast/text/attributed-substring-from-range-001.html"); //  requires JS test API, textInputController
+        ignoreResultList.add("fast/text/plain-text-line-breaks.html"); // extra spacing because iFrames rendered next to each other on Apple
     }
-    
+
     static void fillBugTable() {
-        bugList.put("fast/forms/check-box-enter-key.html", "716715");
         bugList.put("fast/forms/focus-control-to-page.html", "716638");
         bugList.put("fast/html/tab-order.html", "719289");
         bugList.put("fast/dom/attribute-namespaces-get-set.html", "733229");
-        bugList.put("fast/dom/location-hash.html", "733822");
         bugList.put("fast/dom/set-innerHTML.html", "733823");
         bugList.put("fast/dom/xmlhttprequest-get.html", "733846");
         bugList.put("fast/encoding/css-charset-default.html", "733856");
         bugList.put("fast/encoding/default-xhtml-encoding.html", "733882");
         bugList.put("fast/encoding/meta-in-xhtml.html", "733882");
         bugList.put("fast/events/frame-tab-focus.html", "734308");
-        bugList.put("fast/events/keydown-keypress-focus-change.html", "653224");
-        bugList.put("fast/events/keypress-focus-change.html", "653224");
         bugList.put("fast/events/option-tab.html", "734308");
         bugList.put("fast/forms/focus2.html", "735111");
         bugList.put("fast/forms/listbox-selection.html", "735116");
         bugList.put("fast/forms/search-event-delay.html", "735120");
         bugList.put("fast/frames/iframe-window-focus.html", "735140");
         bugList.put("fast/innerHTML/004.html", "733882");
-        bugList.put("fast/js/date-DST-time-cusps.html", "735144");
         bugList.put("fast/js/string-capitalization.html", "516936");
         bugList.put("fast/js/string-concatenate-outofmemory.html","735152");
         bugList.put("fast/parser/external-entities.html", "735176");
-        bugList.put("fast/events/div-focus.html", "735185");
         bugList.put("fast/overflow/scroll-vertical-not-horizontal.html", "735196");
         bugList.put("fast/events/arrow-navigation.html", "735233");
         bugList.put("fast/forms/select-type-ahead-non-latin.html", "735244");
-        bugList.put("fast/events/js-keyboard-event-creation.html", "735255");
-        
     }
-    
-    
-    
+
 }